Skip to content

Commit 1e4947f

Browse files
committed
XXX: openpgp: Implement ML-KEM-768 and ML-KEM-1024 using OpenSSL.
- Requires support in rust-openssl that is not yet merged. See sfackler/rust-openssl#2405 - Fixes #1171.
1 parent c075896 commit 1e4947f

File tree

1 file changed

+125
-1
lines changed

1 file changed

+125
-1
lines changed

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

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ impl Asymmetric for super::Backend {
3939
// XXX: Would be better to have a runtime test.
4040
SLHDSA128s | SLHDSA128f | SLHDSA256s =>
4141
openssl::version::number() >= 0x3_05_00_00_0,
42+
// XXX: Would be better to have a runtime test.
4243
MLKEM768_X25519 | MLKEM1024_X448 =>
43-
false,
44+
openssl::version::number() >= 0x3_05_00_00_0,
4445
ElGamalEncrypt | ElGamalEncryptSign |
4546
Private(_) | Unknown(_)
4647
=> false,
@@ -438,6 +439,129 @@ impl Asymmetric for super::Backend {
438439
Ok(ctx.verify(digest, &signature[..])?)
439440
}
440441

442+
fn mlkem768_generate_key() -> Result<(Protected, Box<[u8; 1184]>)> {
443+
use openssl::pkey_ml_kem::{PKeyMlKemBuilder, PKeyMlKemParams, Variant};
444+
445+
let key = PKeyMlKemBuilder::<Private>::new_generate(Variant::MlKem768)?
446+
.generate()?;
447+
let key_params = PKeyMlKemParams::<Private>::from_pkey(&key)?;
448+
449+
let mut secret = Protected::from(vec![0; 64]);
450+
let mut public = Box::new([0; 1184]);
451+
debug_assert_eq!(secret.len(), key_params.private_key_seed()?.len());
452+
debug_assert_eq!(public.len(), key_params.public_key()?.len());
453+
secret[..].copy_from_slice(key_params.private_key_seed()?);
454+
public[..].copy_from_slice(key_params.public_key()?);
455+
456+
Ok((secret, public))
457+
}
458+
459+
fn mlkem768_encapsulate(public: &[u8; 1184])
460+
-> Result<(Box<[u8; 1088]>, Protected)>
461+
{
462+
use openssl::pkey_ml_kem::{PKeyMlKemBuilder, Variant};
463+
464+
let key = PKeyMlKemBuilder::<Public>::new(
465+
Variant::MlKem768, public, None)?
466+
.build()?;
467+
468+
let mut ciphertext = Box::new([0; 1088]);
469+
let mut keyshare = Protected::from(vec![0; 32]);
470+
471+
let mut ctx = PkeyCtx::new(&key)?;
472+
ctx.encapsulate_init()?;
473+
let (l0, l1) = ctx.encapsulate(Some(&mut ciphertext[..]),
474+
Some(&mut keyshare))?;
475+
476+
debug_assert_eq!(l0, ciphertext.len());
477+
debug_assert_eq!(l1, keyshare.len());
478+
Ok((ciphertext, keyshare))
479+
}
480+
481+
fn mlkem768_decapsulate(secret: &Protected,
482+
ciphertext: &[u8; 1088])
483+
-> Result<Protected>
484+
{
485+
use openssl::pkey_ml_kem::{PKeyMlKemBuilder, Variant};
486+
487+
let key = PKeyMlKemBuilder::<Private>::from_seed(
488+
Variant::MlKem768, secret.as_ref())?
489+
.build()?;
490+
491+
let mut ctx = PkeyCtx::new(&key)?;
492+
ctx.decapsulate_init()?;
493+
let len = ctx.decapsulate(&ciphertext[..], None)?;
494+
let mut keyshare = Protected::from(vec![0; len]);
495+
let len = ctx.decapsulate(&ciphertext[..], Some(&mut keyshare[..]))?;
496+
497+
// Shouldn't happen, but better safe than sorry.
498+
if len != keyshare.len() {
499+
let mut k = Protected::from(vec![0; len]);
500+
k[..].copy_from_slice(&keyshare[..len]);
501+
keyshare = k;
502+
}
503+
504+
Ok(keyshare)
505+
}
506+
507+
fn mlkem1024_generate_key() -> Result<(Protected, Box<[u8; 1568]>)> {
508+
use openssl::pkey_ml_kem::{PKeyMlKemBuilder, PKeyMlKemParams, Variant};
509+
510+
let key = PKeyMlKemBuilder::<Private>::new_generate(Variant::MlKem1024)?
511+
.generate()?;
512+
let key_params = PKeyMlKemParams::<Private>::from_pkey(&key)?;
513+
514+
let mut secret = Protected::from(vec![0; 64]);
515+
let mut public = Box::new([0; 1568]);
516+
debug_assert_eq!(secret.len(), key_params.private_key_seed()?.len());
517+
debug_assert_eq!(public.len(), key_params.public_key()?.len());
518+
secret[..].copy_from_slice(key_params.private_key_seed()?);
519+
public[..].copy_from_slice(key_params.public_key()?);
520+
521+
Ok((secret, public))
522+
}
523+
524+
fn mlkem1024_encapsulate(public: &[u8; 1568])
525+
-> Result<(Box<[u8; 1568]>, Protected)>
526+
{
527+
use openssl::pkey_ml_kem::{PKeyMlKemBuilder, Variant};
528+
529+
let key = PKeyMlKemBuilder::<Public>::new(
530+
Variant::MlKem1024, public, None)?
531+
.build()?;
532+
533+
let mut ciphertext = Box::new([0; 1568]);
534+
let mut keyshare = Protected::from(vec![0; 32]);
535+
536+
let mut ctx = PkeyCtx::new(&key)?;
537+
ctx.encapsulate_init()?;
538+
let (l0, l1) = ctx.encapsulate(Some(&mut ciphertext[..]),
539+
Some(&mut keyshare))?;
540+
541+
debug_assert_eq!(l0, ciphertext.len());
542+
debug_assert_eq!(l1, keyshare.len());
543+
Ok((ciphertext, keyshare))
544+
}
545+
546+
fn mlkem1024_decapsulate(secret: &Protected,
547+
ciphertext: &[u8; 1568])
548+
-> Result<Protected>
549+
{
550+
use openssl::pkey_ml_kem::{PKeyMlKemBuilder, Variant};
551+
552+
let key = PKeyMlKemBuilder::<Private>::from_seed(
553+
Variant::MlKem1024, secret.as_ref())?
554+
.build()?;
555+
556+
let mut ctx = PkeyCtx::new(&key)?;
557+
ctx.decapsulate_init()?;
558+
let mut keyshare = Protected::from(vec![0; 32]);
559+
let len = ctx.decapsulate(&ciphertext[..], Some(&mut keyshare[..]))?;
560+
debug_assert_eq!(len, keyshare.len());
561+
562+
Ok(keyshare)
563+
}
564+
441565
fn dsa_generate_key(p_bits: usize)
442566
-> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)>
443567
{

0 commit comments

Comments
 (0)