diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-02-27 12:32:03 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2024-03-13 10:59:50 +0100 |
commit | dda8bc17260ba0b1d067ba41277f18ab3353dd0f (patch) | |
tree | 39562290289a12ca979c779318355cecc95e5684 | |
parent | 710996262e5dc3e39649e210eb58c5a93e5ab2d9 (diff) |
openpgp: Implement the new CFRG public key algorithms.
- X25519 and Ed25519 are the new MTI algorithms, X448 and Ed448 are
optional.
-rw-r--r-- | openpgp/src/cert/builder.rs | 13 | ||||
-rw-r--r-- | openpgp/src/crypto/asymmetric.rs | 68 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/botan/asymmetric.rs | 5 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng/asymmetric.rs | 5 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/interface.rs | 42 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/asymmetric.rs | 12 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/openssl/asymmetric.rs | 5 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust/asymmetric.rs | 5 | ||||
-rw-r--r-- | openpgp/src/crypto/mpi.rs | 209 | ||||
-rw-r--r-- | openpgp/src/packet/key.rs | 136 | ||||
-rw-r--r-- | openpgp/src/packet/pkesk.rs | 11 | ||||
-rw-r--r-- | openpgp/src/packet/signature.rs | 30 | ||||
-rw-r--r-- | openpgp/src/parse.rs | 7 | ||||
-rw-r--r-- | openpgp/src/parse/mpis.rs | 93 | ||||
-rw-r--r-- | openpgp/src/policy.rs | 37 | ||||
-rw-r--r-- | openpgp/src/serialize.rs | 44 | ||||
-rw-r--r-- | openpgp/src/types/mod.rs | 39 |
17 files changed, 733 insertions, 28 deletions
diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs index 51b3ea4b..9eef69b8 100644 --- a/openpgp/src/cert/builder.rs +++ b/openpgp/src/cert/builder.rs @@ -217,13 +217,24 @@ impl CipherSuite { || flags.for_storage_encryption(); match self { + CipherSuite::Cv25519 => match (sign, encrypt) { + (true, false) => Key4::generate_ed25519(), + (false, true) => Key4::generate_x25519(), + (true, true) => + Err(Error::InvalidOperation( + "Can't use key for encryption and signing".into()) + .into()), + (false, false) => + Err(Error::InvalidOperation( + "No key flags set".into()) + .into()), + }, CipherSuite::RSA2k => Key4::generate_rsa(2048), CipherSuite::RSA3k => Key4::generate_rsa(3072), CipherSuite::RSA4k => Key4::generate_rsa(4096), - CipherSuite::Cv25519 | CipherSuite::P256 | CipherSuite::P384 | CipherSuite::P521 => { let curve = match self { CipherSuite::Cv25519 if sign => Curve::Ed25519, diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs index 6420048d..5412581d 100644 --- a/openpgp/src/crypto/asymmetric.rs +++ b/openpgp/src/crypto/asymmetric.rs @@ -3,7 +3,12 @@ use crate::packet::{self, key, Key}; use crate::crypto::SessionKey; use crate::crypto::mpi; -use crate::types::{Curve, HashAlgorithm, PublicKeyAlgorithm}; +use crate::types::{ + Curve, + HashAlgorithm, + PublicKeyAlgorithm, + SymmetricAlgorithm, +}; use crate::{Error, Result}; @@ -222,6 +227,22 @@ impl Signer for KeyPair { self.secret().map(|secret| { match (self.public().pk_algo(), self.public().mpis(), secret) { + (PublicKeyAlgorithm::Ed25519, + mpi::PublicKey::Ed25519 { a }, + mpi::SecretKeyMaterial::Ed25519 { x }) => { + Ok(mpi::Signature::Ed25519 { + s: Box::new(Backend::ed25519_sign(x, a, digest)?), + }) + }, + + (PublicKeyAlgorithm::Ed448, + mpi::PublicKey::Ed448 { a }, + mpi::SecretKeyMaterial::Ed448 { x }) => { + Ok(mpi::Signature::Ed448 { + s: Box::new(Backend::ed448_sign(x, a, digest)?), + }) + }, + (PublicKeyAlgorithm::EdDSA, mpi::PublicKey::EdDSA { curve, q }, mpi::SecretKeyMaterial::EdDSA { scalar }) => match curve { @@ -257,9 +278,54 @@ impl Decryptor for KeyPair { plaintext_len: Option<usize>) -> Result<SessionKey> { + use crate::crypto::ecdh::aes_key_unwrap; + use crate::crypto::backend::{Backend, interface::{Asymmetric, Kdf}}; + + #[allow(non_snake_case)] self.secret().map(|secret| { + #[allow(clippy::erasing_op, clippy::identity_op)] #[allow(clippy::match_single_binding)] match (self.public().mpis(), secret, ciphertext) { + (mpi::PublicKey::X25519 { u: U }, + mpi::SecretKeyMaterial::X25519 { x }, + mpi::Ciphertext::X25519 { e: E, key }) => { + // Compute the shared point S = xE; + let S = Backend::x25519_shared_point(x, E)?; + + // Compute the wrap key. + let wrap_algo = SymmetricAlgorithm::AES128; + let mut ikm: SessionKey = vec![0; 32 + 32 + 32].into(); + ikm[0 * 32..1 * 32].copy_from_slice(&E[..]); + ikm[1 * 32..2 * 32].copy_from_slice(&U[..]); + ikm[2 * 32..3 * 32].copy_from_slice(&S[..]); + let mut kek = vec![0; wrap_algo.key_size()?].into(); + Backend::hkdf_sha256(&ikm, None, b"OpenPGP X25519", + &mut kek)?; + + Ok(aes_key_unwrap(wrap_algo, kek.as_protected(), + key)?.into()) + }, + + (mpi::PublicKey::X448 { u: U }, + mpi::SecretKeyMaterial::X448 { x }, + mpi::Ciphertext::X448 { e: E, key }) => { + // Compute the shared point S = xE; + let S = Backend::x448_shared_point(x, E)?; + + // Compute the wrap key. + let wrap_algo = SymmetricAlgorithm::AES256; + let mut ikm: SessionKey = vec![0; 56 + 56 + 56].into(); + ikm[0 * 56..1 * 56].copy_from_slice(&E[..]); + ikm[1 * 56..2 * 56].copy_from_slice(&U[..]); + ikm[2 * 56..3 * 56].copy_from_slice(&S[..]); + let mut kek = vec![0; wrap_algo.key_size()?].into(); + Backend::hkdf_sha256(&ikm, None, b"OpenPGP X448", + &mut kek)?; + + Ok(aes_key_unwrap(wrap_algo, kek.as_protected(), + key)?.into()) + }, + (_public, secret, _ciphertext) => self.decrypt_backend(secret, ciphertext, plaintext_len), } diff --git a/openpgp/src/crypto/backend/botan/asymmetric.rs b/openpgp/src/crypto/backend/botan/asymmetric.rs index 8a1f35ac..75d78b67 100644 --- a/openpgp/src/crypto/backend/botan/asymmetric.rs +++ b/openpgp/src/crypto/backend/botan/asymmetric.rs @@ -38,9 +38,11 @@ impl Asymmetric for super::Backend { use PublicKeyAlgorithm::*; #[allow(deprecated)] match algo { + X25519 | Ed25519 | RSAEncryptSign | RSAEncrypt | RSASign | DSA | ECDH | ECDSA | EdDSA | ElGamalEncrypt | ElGamalEncryptSign => true, + X448 | Ed448 | Private(_) | Unknown(_) => false, } @@ -373,11 +375,12 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data), - RSASign | DSA | ECDSA | EdDSA => + RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 => Err(Error::InvalidOperation( format!("{} is not an encryption algorithm", self.pk_algo()) ).into()), + X25519 | X448 | Private(_) | Unknown(_) => Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()), } diff --git a/openpgp/src/crypto/backend/cng/asymmetric.rs b/openpgp/src/crypto/backend/cng/asymmetric.rs index 809ab7f7..8330c901 100644 --- a/openpgp/src/crypto/backend/cng/asymmetric.rs +++ b/openpgp/src/crypto/backend/cng/asymmetric.rs @@ -41,8 +41,10 @@ impl Asymmetric for super::Backend { use PublicKeyAlgorithm::*; #[allow(deprecated)] match algo { + X25519 | Ed25519 | RSAEncryptSign | RSAEncrypt | RSASign | DSA | ECDH | ECDSA | EdDSA => true, + X448 | Ed448 | ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => false, } @@ -508,12 +510,13 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data), - RSASign | DSA | ECDSA | EdDSA => + RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 => Err(Error::InvalidOperation( format!("{} is not an encryption algorithm", self.pk_algo()) ).into()), ElGamalEncrypt | ElGamalEncryptSign | + X25519 | X448 | Private(_) | Unknown(_) => Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()), } diff --git a/openpgp/src/crypto/backend/interface.rs b/openpgp/src/crypto/backend/interface.rs index 05e56a8c..8e0d3957 100644 --- a/openpgp/src/crypto/backend/interface.rs +++ b/openpgp/src/crypto/backend/interface.rs @@ -75,6 +75,24 @@ pub trait Asymmetric { fn x25519_shared_point(secret: &Protected, public: &[u8; 32]) -> Result<Protected>; + /// Generates an X448 key pair. + /// + /// Returns a tuple containing the secret and public key. + fn x448_generate_key() -> Result<(Protected, [u8; 56])> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::X448).into()) + } + + /// Computes the public key for a given secret key. + fn x448_derive_public(_secret: &Protected) -> Result<[u8; 56]> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::X448).into()) + } + + /// Computes the shared point. + fn x448_shared_point(_secret: &Protected, _public: &[u8; 56]) + -> Result<Protected> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::X448).into()) + } + /// Generates an Ed25519 key pair. /// /// Returns a tuple containing the secret and public key. @@ -91,6 +109,30 @@ pub trait Asymmetric { fn ed25519_verify(public: &[u8; 32], digest: &[u8], signature: &[u8; 64]) -> Result<bool>; + /// Generates an Ed448 key pair. + /// + /// Returns a tuple containing the secret and public key. + fn ed448_generate_key() -> Result<(Protected, [u8; 57])> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::Ed448).into()) + } + + /// Computes the public key for a given secret key. + fn ed448_derive_public(_secret: &Protected) -> Result<[u8; 57]> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::Ed448).into()) + } + + /// Creates an Ed448 signature. + fn ed448_sign(_secret: &Protected, _public: &[u8; 57], _digest: &[u8]) + -> Result<[u8; 114]> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::Ed448).into()) + } + + /// Verifies an Ed448 signature. + fn ed448_verify(_public: &[u8; 57], _digest: &[u8], _signature: &[u8; 114]) + -> Result<bool> { + Err(Error::UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm::Ed448).into()) + } + /// Generates a DSA key pair. /// /// `p_bits` denotes the desired size of the parameter `p`. diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs index 3202a67b..8108c4f9 100644 --- a/openpgp/src/crypto/backend/nettle/asymmetric.rs +++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs @@ -12,7 +12,10 @@ use crate::packet::{key, Key}; use crate::crypto::asymmetric::KeyPair; use crate::crypto::backend::interface::Asymmetric; use crate::crypto::mpi::{self, MPI, ProtectedMPI, PublicKey}; -use crate::crypto::SessionKey; +use crate::crypto::{ + SessionKey, + mem::Protected, +}; use crate::types::{Curve, HashAlgorithm}; impl Asymmetric for super::Backend { @@ -20,8 +23,10 @@ impl Asymmetric for super::Backend { use PublicKeyAlgorithm::*; #[allow(deprecated)] match algo { + X25519 | Ed25519 | RSAEncryptSign | RSAEncrypt | RSASign | DSA | ECDH | ECDSA | EdDSA => true, + X448 | Ed448 | ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => false, } @@ -287,11 +292,13 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data), - RSASign | DSA | ECDSA | EdDSA => + RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 => Err(Error::InvalidOperation( format!("{} is not an encryption algorithm", self.pk_algo()) ).into()), + X25519 | // Handled in common code. + X448 | // Handled in common code. ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()), @@ -352,7 +359,6 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { } use std::time::SystemTime; -use crate::crypto::mem::Protected; use crate::packet::key::{Key4, SecretParts}; use crate::types::PublicKeyAlgorithm; diff --git a/openpgp/src/crypto/backend/openssl/asymmetric.rs b/openpgp/src/crypto/backend/openssl/asymmetric.rs index 0ae2ca15..60768306 100644 --- a/openpgp/src/crypto/backend/openssl/asymmetric.rs +++ b/openpgp/src/crypto/backend/openssl/asymmetric.rs @@ -28,9 +28,11 @@ impl Asymmetric for super::Backend { use PublicKeyAlgorithm::*; #[allow(deprecated)] match algo { + X25519 | Ed25519 | RSAEncryptSign | RSAEncrypt | RSASign => true, DSA => true, ECDH | ECDSA | EdDSA => true, + X448 | Ed448 | ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => false, @@ -358,12 +360,13 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data), - RSASign | DSA | ECDSA | EdDSA => + RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 => Err(Error::InvalidOperation( format!("{} is not an encryption algorithm", self.pk_algo()) ).into()), ElGamalEncrypt | ElGamalEncryptSign | + X25519 | X448 | Private(_) | Unknown(_) => Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()), } diff --git a/openpgp/src/crypto/backend/rust/asymmetric.rs b/openpgp/src/crypto/backend/rust/asymmetric.rs index 7df6ecf6..e7c770a7 100644 --- a/openpgp/src/crypto/backend/rust/asymmetric.rs +++ b/openpgp/src/crypto/backend/rust/asymmetric.rs @@ -45,10 +45,12 @@ impl Asymmetric for super::Backend { use PublicKeyAlgorithm::*; #[allow(deprecated)] match algo { + X25519 | Ed25519 | RSAEncryptSign | RSAEncrypt | RSASign | ECDH | EdDSA | ECDSA => true, DSA => true, + X448 | Ed448 | ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => false, } @@ -376,12 +378,13 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data), - RSASign | DSA | ECDSA | EdDSA => + RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 => Err(Error::InvalidOperation( format!("{} is not an encryption algorithm", self.pk_algo()) ).into()), ElGamalEncrypt | ElGamalEncryptSign | + X25519 | X448 | Private(_) | Unknown(_) => Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()), } diff --git a/openpgp/src/crypto/mpi.rs b/openpgp/src/crypto/mpi.rs index 2179fd89..e771e9ab 100644 --- a/openpgp/src/crypto/mpi.rs +++ b/openpgp/src/crypto/mpi.rs @@ -584,6 +584,30 @@ pub enum PublicKey { sym: SymmetricAlgorithm, }, + /// X25519 public key. + X25519 { + /// The public key, an opaque string. + u: [u8; 32], + }, + + /// X448 public key. + X448 { + /// The public key, an opaque string. + u: Box<[u8; 56]>, + }, + + /// Ed25519 public key. + Ed25519 { + /// The public key, an opaque string. + a: [u8; 32], + }, + + /// Ed448 public key. + Ed448 { + /// The public key, an opaque string. + a: Box<[u8; 57]>, + }, + /// Unknown number of MPIs for an unknown algorithm. Unknown { /// The successfully parsed MPIs. @@ -614,6 +638,10 @@ impl PublicKey { EdDSA { ref curve,.. } => curve.bits(), ECDSA { ref curve,.. } => curve.bits(), ECDH { ref curve,.. } => curve.bits(), + X25519 { .. } => Some(256), + X448 { .. } => Some(448), + Ed25519 { .. } => Some(256), + Ed448 { .. } => Some(456), Unknown { .. } => None, } } @@ -629,6 +657,10 @@ impl PublicKey { EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA), ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA), ECDH { .. } => Some(PublicKeyAlgorithm::ECDH), + X25519 { .. } => Some(PublicKeyAlgorithm::X25519), + X448 { .. } => Some(PublicKeyAlgorithm::X448), + Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519), + Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448), Unknown { .. } => None, } } @@ -647,7 +679,7 @@ impl Arbitrary for PublicKey { use self::PublicKey::*; use crate::arbitrary_helper::gen_arbitrary_from_range; - match gen_arbitrary_from_range(0..6, g) { + match gen_arbitrary_from_range(0..10, g) { 0 => RSA { e: MPI::arbitrary(g), n: MPI::arbitrary(g), @@ -683,11 +715,30 @@ impl Arbitrary for PublicKey { sym: SymmetricAlgorithm::arbitrary(g), }, + 6 => X25519 { u: arbitrary(g) }, + 7 => X448 { u: Box::new(arbitrarize(g, [0; 56])) }, + 8 => Ed25519 { a: arbitrary(g) }, + 9 => Ed448 { a: Box::new(arbitrarize(g, [0; 57])) }, + _ => unreachable!(), } } } +#[cfg(test)] +pub(crate) fn arbitrarize<T: AsMut<[u8]>>(g: &mut Gen, mut a: T) -> T +{ + a.as_mut().iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g)); + a +} + +#[cfg(test)] +pub(crate) fn arbitrary<T: Default + AsMut<[u8]>>(g: &mut Gen) -> T +{ + arbitrarize(g, Default::default()) +} + + /// A secret key. /// /// Provides a typed and structured way of storing multiple MPIs in @@ -746,6 +797,30 @@ pub enum SecretKeyMaterial { scalar: ProtectedMPI, }, + /// X25519 secret key. + X25519 { + /// The secret key, an opaque string. + x: Protected, + }, + + /// X448 secret key. + X448 { + /// The secret key, an opaque string. + x: Protected, + }, + + /// Ed25519 secret key. + Ed25519 { + /// The secret key, an opaque string. + x: Protected, + }, + + /// Ed448 secret key. + Ed448 { + /// The secret key, an opaque string. + x: Protected, + }, + /// Unknown number of MPIs for an unknown algorithm. Unknown { /// The successfully parsed MPIs. @@ -772,6 +847,14 @@ impl fmt::Debug for SecretKeyMaterial { write!(f, "ECDSA {{ scalar: {:?} }}", scalar), SecretKeyMaterial::ECDH{ ref scalar } => write!(f, "ECDH {{ scalar: {:?} }}", scalar), + SecretKeyMaterial::X25519 { x } => + write!(f, "X25519 {{ x: {:?} }}", x), + SecretKeyMaterial::X448 { x } => + write!(f, "X448 {{ x: {:?} }}", x), + SecretKeyMaterial::Ed25519 { x } => + write!(f, "Ed25519 {{ x: {:?} }}", x), + SecretKeyMaterial::Ed448 { x } => + write!(f, "Ed448 {{ x: {:?} }}", x), SecretKeyMaterial::Unknown{ ref mpis, ref rest } => write!(f, "Unknown {{ mips: {:?}, rest: {:?} }}", mpis, rest), } @@ -789,6 +872,14 @@ impl fmt::Debug for SecretKeyMaterial { f.write_str("ECDSA { <Redacted> }"), SecretKeyMaterial::ECDH{ .. } => f.write_str("ECDH { <Redacted> }"), + SecretKeyMaterial::X25519 { .. } => + f.write_str("X25519 { <Redacted> }"), + SecretKeyMaterial::X448 { .. } => + f.write_str("X448 { <Redacted> }"), + SecretKeyMaterial::Ed25519 { .. } => + f.write_str("Ed25519 { <Redacted> }"), + SecretKeyMaterial::Ed448 { .. } => + f.write_str("Ed448 { <Redacted> }"), SecretKeyMaterial::Unknown{ .. } => f.write_str("Unknown { <Redacted> }"), } @@ -808,7 +899,11 @@ impl PartialOrd for SecretKeyMaterial { SecretKeyMaterial::EdDSA{ .. } => 3, SecretKeyMaterial::ECDSA{ .. } => 4, SecretKeyMaterial::ECDH{ .. } => 5, - SecretKeyMaterial::Unknown{ .. } => 6, + SecretKeyMaterial::X25519 { .. } => 6, + SecretKeyMaterial::X448 { .. } => 7, + SecretKeyMaterial::Ed25519 { .. } => 8, + SecretKeyMaterial::Ed448 { .. } => 9, + SecretKeyMaterial::Unknown { .. } => 10, } } @@ -845,6 +940,15 @@ impl PartialOrd for SecretKeyMaterial { ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => { scalar1.cmp(scalar2) } + (SecretKeyMaterial::X25519 { x: x0 }, + SecretKeyMaterial::X25519 { x: x1 }) => x0.cmp(x1), + (SecretKeyMaterial::X448 { x: x0 }, + SecretKeyMaterial::X448 { x: x1 }) => x0.cmp(x1), + (SecretKeyMaterial::Ed25519 { x: x0 }, + SecretKeyMaterial::Ed25519 { x: x1 }) => x0.cmp(x1), + (SecretKeyMaterial::Ed448 { x: x0 }, + SecretKeyMaterial::Ed448 { x: x1 }) => x0.cmp(x1), + (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 } ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => { let o1 = secure_cmp(rest1, rest2); @@ -893,6 +997,10 @@ impl SecretKeyMaterial { EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA), ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA), ECDH { .. } => Some(PublicKeyAlgorithm::ECDH), + X25519 { .. } => Some(PublicKeyAlgorithm::X25519), + X448 { .. } => Some(PublicKeyAlgorithm::X448), + Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519), + Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448), Unknown { .. } => None, } } @@ -938,6 +1046,19 @@ impl SecretKeyMaterial { scalar: MPI::arbitrary(g).into(), }), + X25519 => Ok(SecretKeyMaterial::X25519 { + x: arbitrarize(g, vec![0; 32]).into(), + }), + X448 => Ok(SecretKeyMaterial::X448 { + x: arbitrarize(g, vec![0; 56]).into(), + }), + Ed25519 => Ok(SecretKeyMaterial::Ed25519 { + x: arbitrarize(g, vec![0; 32]).into(), + }), + Ed448 => Ok(SecretKeyMaterial::Ed448 { + x: arbitrarize(g, vec![0; 57]).into(), + }), + Private(_) | Unknown(_) => Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()), } @@ -1018,6 +1139,22 @@ pub enum Ciphertext { key: Box<[u8]>, }, + /// X25519 ciphertext. + X25519 { + /// Ephermeral key. + e: Box<[u8; 32]>, + /// Symmetrically encrypted session key. + key: Box<[u8]>, + }, + + /// X448 ciphertext. + X448 { + /// Ephermeral key. + e: Box<[u8; 56]>, + /// Symmetrically encrypted session key. + key: Box<[u8]>, + }, + /// Unknown number of MPIs for an unknown algorithm. Unknown { /// The successfully parsed MPIs. @@ -1041,6 +1178,8 @@ impl Ciphertext { RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign), ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt), ECDH { .. } => Some(PublicKeyAlgorithm::ECDH), + X25519 { .. } => Some(PublicKeyAlgorithm::X25519), + X448 { .. } => Some(PublicKeyAlgorithm::X448), Unknown { .. } => None, } } @@ -1058,7 +1197,7 @@ impl Arbitrary for Ciphertext { fn arbitrary(g: &mut Gen) -> Self { use crate::arbitrary_helper::gen_arbitrary_from_range; |