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>2023-06-26 13:24:44 +0200
commitffcc75e9c10491f61688f3fc29b884170732ce4e (patch)
tree977f9e593be89203842875f1e1b2fbff87c64c2f
parent130cabbfedde5d022f24c4e026d9ad5da9a7f0a0 (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.rs43
-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.rs7
-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, 735 insertions, 29 deletions
diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs
index 6e181ce5..25025825 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 c817aafd..86a9dac8 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,
}
@@ -353,11 +355,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 38eb1905..6ca15bb1 100644
--- a/openpgp/src/crypto/backend/cng/asymmetric.rs
+++ b/openpgp/src/crypto/backend/cng/asymmetric.rs
@@ -27,8 +27,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,
}
@@ -498,12 +500,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 76bd703d..eed7777e 100644
--- a/openpgp/src/crypto/backend/interface.rs
+++ b/openpgp/src/crypto/backend/interface.rs
@@ -1,6 +1,7 @@
//! The crypto-backend abstraction.
use crate::{
+ Error,
Result,
crypto::{
SessionKey,
@@ -57,6 +58,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.
@@ -72,6 +91,30 @@ pub trait Asymmetric {
/// Verifies an Ed25519 signature.
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())
+ }
}
/// Key-Derivation-Functions.
diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs
index 2e631edd..dc1a54f2 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, 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,
}
@@ -273,11 +278,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()),
@@ -338,7 +345,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 61a0b735..daf6208f 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,
@@ -347,12 +349,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 44163e2d..2bb04c24 100644
--- a/openpgp/src/crypto/backend/rust/asymmetric.rs
+++ b/openpgp/src/crypto/backend/rust/asymmetric.rs
@@ -32,10 +32,12 @@ impl Asymmetric for super::Backend {
use PublicKeyAlgorithm::*;
#[allow(deprecated)]
match algo {
+ X25519 | Ed25519 |
RSAEncryptSign | RSAEncrypt | RSASign | ECDH | EdDSA | ECDSA
=> true,
DSA
=> false,
+ X448 | Ed448 |
ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_)
=> false,
}
@@ -94,7 +96,7 @@ impl Asymmetric for super::Backend {
// depends on 0.7.
use rand07::rngs::OsRng as OsRng;
let pair = ed25519_dalek::Keypair::generate(&mut OsRng);
- Ok((pair.secret.as_bytes().as_slice().into(), pair.secret.to_bytes()))
+ Ok((pair.secret.as_bytes().as_slice().into(), pair.public.to_bytes()))
}
fn ed25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
@@ -322,12 +324,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 fa27beb7..52058e96 100644
--- a/openpgp/src/crypto/mpi.rs
+++ b/openpgp/src/crypto/mpi.rs
@@ -572,6 +572,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.
@@ -602,6 +626,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,
}
}
@@ -617,6 +645,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,
}
}
@@ -635,7 +667,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),
@@ -671,11 +703,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
@@ -734,6 +785,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.
@@ -760,6 +835,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),
}
@@ -777,6 +860,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> }"),
}
@@ -796,7 +887,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,
}
}
@@ -833,6 +928,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);
@@ -881,6 +985,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,
}
}
@@ -926,6 +1034,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()),
}
@@ -996,6 +1117,22 @@ pub enum Ciphertext {
key: Box<[u8]>,
},
+ /// X25519 ciphertext.
+ X25519 {
+ /// Ephermeral key.
+ e: Box<[u8; 32]>,
+ /// Symmetrically encrypted session key.
+ key: Bo