summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-02-27 12:32:03 +0100
committerJustus Winter <justus@sequoia-pgp.org>2024-03-13 10:59:50 +0100
commitdda8bc17260ba0b1d067ba41277f18ab3353dd0f (patch)
tree39562290289a12ca979c779318355cecc95e5684
parent710996262e5dc3e39649e210eb58c5a93e5ab2d9 (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.rs13
-rw-r--r--openpgp/src/crypto/asymmetric.rs68
-rw-r--r--openpgp/src/crypto/backend/botan/asymmetric.rs5
-rw-r--r--openpgp/src/crypto/backend/cng/asymmetric.rs5
-rw-r--r--openpgp/src/crypto/backend/interface.rs42
-rw-r--r--openpgp/src/crypto/backend/nettle/asymmetric.rs12
-rw-r--r--openpgp/src/crypto/backend/openssl/asymmetric.rs5
-rw-r--r--openpgp/src/crypto/backend/rust/asymmetric.rs5
-rw-r--r--openpgp/src/crypto/mpi.rs209
-rw-r--r--openpgp/src/packet/key.rs136
-rw-r--r--openpgp/src/packet/pkesk.rs11
-rw-r--r--openpgp/src/packet/signature.rs30
-rw-r--r--openpgp/src/parse.rs7
-rw-r--r--openpgp/src/parse/mpis.rs93
-rw-r--r--openpgp/src/policy.rs37
-rw-r--r--openpgp/src/serialize.rs44
-rw-r--r--openpgp/src/types/mod.rs39
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;