Skip to content

Commit 749170f

Browse files
committed
XXX: openpgp: Implement ML-DSA-65 and ML-DSA-87 using OpenSSL.
- Note: this requires support in rust-openssl that has not been merged. See sfackler/rust-openssl#2405 - Fixes #1173.
1 parent f18f8b1 commit 749170f

File tree

1 file changed

+112
-2
lines changed

1 file changed

+112
-2
lines changed

openpgp/src/crypto/backend/openssl/asymmetric.rs

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use openssl::derive::Deriver;
1717
use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
1818
use openssl::ecdsa::EcdsaSig;
1919
use openssl::nid::Nid;
20-
use openssl::pkey::PKey;
20+
use openssl::pkey::{PKey, Private, Public};
2121
use openssl::pkey_ctx::PkeyCtx;
2222
use openssl::rsa::{Padding, Rsa, RsaPrivateKeyBuilder};
2323
use openssl::sign::Signer as OpenSslSigner;
@@ -33,7 +33,9 @@ impl Asymmetric for super::Backend {
3333
RSAEncryptSign | RSAEncrypt | RSASign => true,
3434
DSA => true,
3535
ECDH | ECDSA | EdDSA => true,
36-
MLDSA65_Ed25519 | MLDSA87_Ed448 => false,
36+
// XXX: Would be better to have a runtime test.
37+
MLDSA65_Ed25519 | MLDSA87_Ed448 =>
38+
openssl::version::number() >= 0x3_05_00_00_0,
3739
SLHDSA128s | SLHDSA128f | SLHDSA256s =>
3840
false,
3941
MLKEM768_X25519 | MLKEM1024_X448 =>
@@ -165,6 +167,114 @@ impl Asymmetric for super::Backend {
165167
Ok(verifier.verify_oneshot(signature, digest)?)
166168
}
167169

170+
fn mldsa65_generate_key() -> Result<(Protected, Box<[u8; 1952]>)> {
171+
use openssl::pkey_ml_dsa::{PKeyMlDsaBuilder, PKeyMlDsaParams, Variant};
172+
173+
let key = PKeyMlDsaBuilder::<Private>::new_generate(Variant::MlDsa65)?
174+
.generate()?;
175+
let public_params = PKeyMlDsaParams::<Public>::from_pkey(&key)?;
176+
let secret_params = PKeyMlDsaParams::<Private>::from_pkey(&key)?;
177+
178+
let mut secret = Protected::from(vec![0; 32]);
179+
let mut public = Box::new([0; 1952]);
180+
debug_assert_eq!(secret.len(), secret_params.private_key_seed()?.len());
181+
debug_assert_eq!(public.len(), public_params.public_key()?.len());
182+
secret[..].copy_from_slice(secret_params.private_key_seed()?);
183+
public[..].copy_from_slice(public_params.public_key()?);
184+
185+
Ok((secret, public))
186+
}
187+
188+
fn mldsa65_sign(secret: &Protected, digest: &[u8])
189+
-> Result<Box<[u8; 3309]>>
190+
{
191+
use openssl::pkey_ml_dsa::{PKeyMlDsaBuilder, Variant};
192+
use openssl::signature::Signature;
193+
194+
let key = PKeyMlDsaBuilder::<Private>::from_seed(
195+
Variant::MlDsa65, secret.as_ref())?
196+
.build()?;
197+
let mut algo = Signature::for_ml_dsa(Variant::MlDsa65)?;
198+
199+
let mut ctx = PkeyCtx::new(&key)?;
200+
ctx.sign_message_init(&mut algo)?;
201+
let mut signature = Box::new([0; 3309]);
202+
let len = ctx.sign(digest, Some(&mut signature[..]))?;
203+
debug_assert_eq!(len, signature.len());
204+
205+
Ok(signature)
206+
}
207+
208+
fn mldsa65_verify(public: &[u8; 1952], digest: &[u8], signature: &[u8; 3309])
209+
-> Result<bool>
210+
{
211+
use openssl::pkey_ml_dsa::{PKeyMlDsaBuilder, Variant};
212+
use openssl::signature::Signature;
213+
214+
let key = PKeyMlDsaBuilder::<Public>::new(
215+
Variant::MlDsa65, public, None)?
216+
.build()?;
217+
let mut algo = Signature::for_ml_dsa(Variant::MlDsa65)?;
218+
219+
let mut ctx = PkeyCtx::new(&key)?;
220+
ctx.verify_message_init(&mut algo)?;
221+
Ok(ctx.verify(digest, &signature[..])?)
222+
}
223+
224+
fn mldsa87_generate_key() -> Result<(Protected, Box<[u8; 2592]>)> {
225+
use openssl::pkey_ml_dsa::{PKeyMlDsaBuilder, PKeyMlDsaParams, Variant};
226+
227+
let key = PKeyMlDsaBuilder::<Private>::new_generate(Variant::MlDsa87)?
228+
.generate()?;
229+
let public_params = PKeyMlDsaParams::<Public>::from_pkey(&key)?;
230+
let secret_params = PKeyMlDsaParams::<Private>::from_pkey(&key)?;
231+
232+
let mut secret = Protected::from(vec![0; 32]);
233+
let mut public = Box::new([0; 2592]);
234+
debug_assert_eq!(secret.len(), secret_params.private_key_seed()?.len());
235+
debug_assert_eq!(public.len(), public_params.public_key()?.len());
236+
secret[..].copy_from_slice(secret_params.private_key_seed()?);
237+
public[..].copy_from_slice(public_params.public_key()?);
238+
239+
Ok((secret, public))
240+
}
241+
242+
fn mldsa87_sign(secret: &Protected, digest: &[u8])
243+
-> Result<Box<[u8; 4627]>>
244+
{
245+
use openssl::pkey_ml_dsa::{PKeyMlDsaBuilder, Variant};
246+
use openssl::signature::Signature;
247+
248+
let key = PKeyMlDsaBuilder::<Private>::from_seed(
249+
Variant::MlDsa87, secret.as_ref())?
250+
.build()?;
251+
let mut algo = Signature::for_ml_dsa(Variant::MlDsa87)?;
252+
253+
let mut ctx = PkeyCtx::new(&key)?;
254+
ctx.sign_message_init(&mut algo)?;
255+
let mut signature = Box::new([0; 4627]);
256+
let len = ctx.sign(digest, Some(&mut signature[..]))?;
257+
debug_assert_eq!(len, signature.len());
258+
259+
Ok(signature)
260+
}
261+
262+
fn mldsa87_verify(public: &[u8; 2592], digest: &[u8], signature: &[u8; 4627])
263+
-> Result<bool>
264+
{
265+
use openssl::pkey_ml_dsa::{PKeyMlDsaBuilder, Variant};
266+
use openssl::signature::Signature;
267+
268+
let key = PKeyMlDsaBuilder::<Public>::new(
269+
Variant::MlDsa87, public, None)?
270+
.build()?;
271+
let mut algo = Signature::for_ml_dsa(Variant::MlDsa87)?;
272+
273+
let mut ctx = PkeyCtx::new(&key)?;
274+
ctx.verify_message_init(&mut algo)?;
275+
Ok(ctx.verify(digest, &signature[..])?)
276+
}
277+
168278
fn dsa_generate_key(p_bits: usize)
169279
-> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)>
170280
{

0 commit comments

Comments
 (0)