diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-01-13 12:35:07 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-01-13 12:35:07 +0100 |
commit | c96e976d0faed03bb29f459cd2879ff96ac7f316 (patch) | |
tree | cb530e79f29cec410b4f7caf15a170afbdcf8d70 | |
parent | 92e8b887662cdbc251722438c8195b8e40f4fc2f (diff) | |
parent | e9906e642a674598785523128503cc8a1a45ff96 (diff) |
Merge branch 'justus/openpgp-next-cv448' into justus/openpgp-nextjustus/openpgp-next
-rw-r--r-- | openpgp/src/cert/builder.rs | 19 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng.rs | 2 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng/ecdh.rs | 7 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle.rs | 4 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/asymmetric.rs | 75 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/ecdh.rs | 48 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust.rs | 2 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust/ecdh.rs | 4 | ||||
-rw-r--r-- | openpgp/src/crypto/ecdh.rs | 4 | ||||
-rw-r--r-- | openpgp/src/crypto/mpi.rs | 63 | ||||
-rw-r--r-- | openpgp/src/packet/signature.rs | 1 | ||||
-rw-r--r-- | openpgp/src/policy.rs | 8 | ||||
-rw-r--r-- | openpgp/src/types/mod.rs | 27 | ||||
-rw-r--r-- | sq/sq-usage.md | 2 | ||||
-rw-r--r-- | sq/src/commands/key.rs | 3 | ||||
-rw-r--r-- | sq/src/sq_cli/key.rs | 3 |
16 files changed, 255 insertions, 17 deletions
diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs index 3060627c..47c70b4e 100644 --- a/openpgp/src/cert/builder.rs +++ b/openpgp/src/cert/builder.rs @@ -64,6 +64,8 @@ pub use key::{ pub enum CipherSuite { /// EdDSA and ECDH over Curve25519 with SHA512 and AES256 Cv25519, + /// EdDSA and ECDH over Curve448 with SHA512 and AES256 + Cv448, /// 3072 bit RSA with SHA512 and AES256 RSA3k, /// EdDSA and ECDH over NIST P-256 with SHA256 and AES256 @@ -118,6 +120,12 @@ impl CipherSuite { check_pk!(PublicKeyAlgorithm::ECDH); check_curve!(Curve::Cv25519); }, + Cv448 => { + check_pk!(PublicKeyAlgorithm::EdDSA); + check_curve!(Curve::Ed448); + check_pk!(PublicKeyAlgorithm::ECDH); + check_curve!(Curve::Cv448); + }, RSA2k | RSA3k | RSA4k => { check_pk!(PublicKeyAlgorithm::RSAEncryptSign); }, @@ -154,8 +162,11 @@ impl CipherSuite { Key4::generate_rsa(3072), CipherSuite::RSA4k => Key4::generate_rsa(4096), - CipherSuite::Cv25519 | CipherSuite::P256 | - CipherSuite::P384 | CipherSuite::P521 => { + CipherSuite::Cv25519 + | CipherSuite::Cv448 + | CipherSuite::P256 + | CipherSuite::P384 + | CipherSuite::P521 => { let flags = flags.as_ref(); let sign = flags.for_certification() || flags.for_signing() || flags.for_authentication(); @@ -164,6 +175,8 @@ impl CipherSuite { let curve = match self { CipherSuite::Cv25519 if sign => Curve::Ed25519, CipherSuite::Cv25519 if encrypt => Curve::Cv25519, + CipherSuite::Cv448 if sign => Curve::Ed448, + CipherSuite::Cv448 if encrypt => Curve::Cv448, CipherSuite::Cv25519 => { return Err(Error::InvalidOperation( "No key flags set".into()) @@ -1699,7 +1712,7 @@ mod tests { fn all_ciphersuites() { use self::CipherSuite::*; - for cs in vec![Cv25519, RSA3k, P256, P384, P521, RSA2k, RSA4k] + for cs in vec![Cv25519, Cv448, RSA3k, P256, P384, P521, RSA2k, RSA4k] .into_iter().filter(|cs| cs.is_supported().is_ok()) { assert!(CertBuilder::new() diff --git a/openpgp/src/crypto/backend/cng.rs b/openpgp/src/crypto/backend/cng.rs index b2e830d8..767259e5 100644 --- a/openpgp/src/crypto/backend/cng.rs +++ b/openpgp/src/crypto/backend/cng.rs @@ -42,6 +42,8 @@ impl Curve { match &self { NistP256 | NistP384 | NistP521 | Ed25519 | Cv25519 => true, + Ed448 | Cv448 + => false, BrainpoolP256 | BrainpoolP512 | Unknown(_) => false, } diff --git a/openpgp/src/crypto/backend/cng/ecdh.rs b/openpgp/src/crypto/backend/cng/ecdh.rs index ab687e24..95bbcb44 100644 --- a/openpgp/src/crypto/backend/cng/ecdh.rs +++ b/openpgp/src/crypto/backend/cng/ecdh.rs @@ -60,6 +60,8 @@ where encrypt_wrap(recipient, session_key, VB, &S) } + Curve::Cv448 => + return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => { let (Rx, Ry) = q.decode_point(curve)?; @@ -142,7 +144,7 @@ where Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), // N/A - Curve::Unknown(_) | Curve::Ed25519 => + Curve::Unknown(_) | Curve::Ed25519 | Curve::Ed448 => Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), } } @@ -204,6 +206,9 @@ where secret.into() } + Curve::Cv448 => + return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), + Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => { // Get the public part V of the ephemeral key and // compute the shared point S = rV = rvG, where (r, R) diff --git a/openpgp/src/crypto/backend/nettle.rs b/openpgp/src/crypto/backend/nettle.rs index ef68cc35..c64bb41a 100644 --- a/openpgp/src/crypto/backend/nettle.rs +++ b/openpgp/src/crypto/backend/nettle.rs @@ -70,6 +70,10 @@ impl Curve { match &self { NistP256 | NistP384 | NistP521 | Ed25519 | Cv25519 => true, + Ed448 + => nettle::ed448::IS_SUPPORTED, + Cv448 + => nettle::curve448::IS_SUPPORTED, BrainpoolP256 | BrainpoolP512 | Unknown(_) => false, } diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs index 9efad861..fc362401 100644 --- a/openpgp/src/crypto/backend/nettle/asymmetric.rs +++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs @@ -4,13 +4,24 @@ //! [`Decryptor`]: super::super::asymmetric::Decryptor //! [`KeyPair`]: super::super::asymmetric::KeyPair -use nettle::{curve25519, ecc, ecdh, ecdsa, ed25519, dsa, rsa, random::Yarrow}; +use nettle::{ + curve25519, + curve448, + dsa, + ecc, + ecdh, + ecdsa, + ed25519, + ed448, + random::Yarrow, + rsa, +}; use crate::{Error, Result}; use crate::packet::{key, Key}; use crate::crypto::asymmetric::{KeyPair, Decryptor, Signer}; -use crate::crypto::mpi::{self, MPI, PublicKey}; +use crate::crypto::mpi::{self, MPI, ProtectedMPI, PublicKey}; use crate::crypto::SessionKey; use crate::types::{Curve, HashAlgorithm}; @@ -94,6 +105,17 @@ impl Signer for KeyPair { s: MPI::new(&sig[ed25519::ED25519_KEY_SIZE..]), }) }, + + Curve::Ed448 => { + let public = q.decode_octet_string(curve.field_size()?)?; + let secret = scalar.decode_octet_string(curve.field_size()?)?; + let mut sig = vec![0; ed448::ED448_SIGNATURE_SIZE]; + ed448::sign(public, secret, digest, &mut sig)?; + Ok(mpi::Signature::EdDSA { + r: MPI::new_octet_string(sig), + s: MPI::zero(), + }) + }, _ => Err( Error::UnsupportedEllipticCurve(curve.clone()).into()), }, @@ -286,6 +308,19 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { ed25519::verify(&q.value()[1..], digest, &signature)? }, + Curve::Ed448 => { + let public = q.decode_octet_string(curve.field_size()?)?; + let signature = + r.decode_octet_string(curve.field_size()? * 2)?; + assert_eq!(signature.len(), ed448::ED448_SIGNATURE_SIZE); + if ! s.is_zero() { + return Err(Error::BadSignature( + "Ed448 signature's S parameter is not zero".into()) + .into()); + } + + ed448::verify(public, digest, signature)? + }, _ => return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), }, @@ -492,6 +527,42 @@ impl<R> Key4<SecretParts, R> (public_mpis, sec, ECDH) } + (Curve::Ed448, true) => { + let private: Protected = + ed448::private_key(&mut rng).into(); + let mut public = [0; ed448::ED448_KEY_SIZE]; + ed448::public_key(&mut public, &private)?; + + let public = PublicKey::EdDSA { + curve: Curve::Ed448, + q: MPI::new_octet_string(public), + }; + let private = mpi::SecretKeyMaterial::EdDSA { + scalar: ProtectedMPI::new_octet_string(private), + }; + + (public, private.into(), EdDSA) + }, + + (Curve::Cv448, false) => { + let private: Protected = + curve448::private_key(&mut rng).into(); + let mut public = [0; curve448::CURVE448_SIZE]; + curve448::mul_g(&mut public, &private)?; + + let public = PublicKey::ECDH { + curve: Curve::Cv448, + q: MPI::new_octet_string(public), + hash: HashAlgorithm::SHA512, + sym: SymmetricAlgorithm::AES256, + }; + let private = mpi::SecretKeyMaterial::ECDH { + scalar: ProtectedMPI::new_octet_string(private), + }; + + (public, private.into(), ECDH) + }, + (Curve::NistP256, true) | (Curve::NistP384, true) | (Curve::NistP521, true) => { let (public, private, field_sz) = match curve { diff --git a/openpgp/src/crypto/backend/nettle/ecdh.rs b/openpgp/src/crypto/backend/nettle/ecdh.rs index eea5661d..7aec6d73 100644 --- a/openpgp/src/crypto/backend/nettle/ecdh.rs +++ b/openpgp/src/crypto/backend/nettle/ecdh.rs @@ -1,6 +1,12 @@ //! Elliptic Curve Diffie-Hellman. -use nettle::{curve25519, ecc, ecdh, random::Yarrow}; +use nettle::{ + curve25519, + curve448, + ecc, + ecdh, + random::Yarrow, +}; use crate::{Error, Result}; use crate::crypto::SessionKey; @@ -45,6 +51,28 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>, encrypt_wrap(recipient, session_key, VB, &S) } + Curve::Cv448 => { + // Obtain the authenticated recipient public key R + let R = q.decode_octet_string(curve.field_size()?)?; + + // Generate an ephemeral key pair {v, V=vG} + let v: Protected = + curve448::private_key(&mut rng).into(); + + // Compute the public key. + let mut VB = [0; curve448::CURVE448_SIZE]; + curve448::mul_g(&mut VB, &v) + .expect("buffers are of the wrong size"); + let VB = MPI::new_octet_string(&VB); + + // Compute the shared point S = vR; + let mut S: Protected = + vec![0; curve448::CURVE448_SIZE].into(); + curve448::mul(&mut S, &v, R) + .expect("buffers are of the wrong size"); + + encrypt_wrap(recipient, session_key, VB, &S) + }, Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => { // Obtain the authenticated recipient public key R and // generate an ephemeral private key v. @@ -107,7 +135,7 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>, Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), // N/A - Curve::Unknown(_) | Curve::Ed25519 => + Curve::Unknown(_) | Curve::Ed25519 | Curve::Ed448 => Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), } } else { @@ -154,6 +182,20 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>, S } + Curve::Cv448 => { + // Get the public part V of the ephemeral key. + let V = e.decode_octet_string(curve.field_size()?)?; + let r = scalar.decode_octet_string(curve.field_size()?)?; + + // Compute the shared point S = rV = rvG, where (r, R) + // is the recipient's key pair. + let mut S: Protected = + vec![0; curve448::CURVE448_SIZE].into(); + curve448::mul(&mut S, r, V) + .expect("buffers are of the wrong size"); + S + }, + Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => { // Get the public part V of the ephemeral key and // compute the shared point S = rV = rvG, where (r, R) @@ -208,7 +250,7 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>, Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), // N/A - Curve::Unknown(_) | Curve::Ed25519 => + Curve::Unknown(_) | Curve::Ed25519 | Curve::Ed448 => return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), }; diff --git a/openpgp/src/crypto/backend/rust.rs b/openpgp/src/crypto/backend/rust.rs index 26284d33..75274934 100644 --- a/openpgp/src/crypto/backend/rust.rs +++ b/openpgp/src/crypto/backend/rust.rs @@ -48,6 +48,8 @@ impl Curve { => false, Ed25519 | Cv25519 => true, + Ed448 | Cv448 + => false, BrainpoolP256 | BrainpoolP512 | Unknown(_) => false, } diff --git a/openpgp/src/crypto/backend/rust/ecdh.rs b/openpgp/src/crypto/backend/rust/ecdh.rs index 8531013d..b05ee7ba 100644 --- a/openpgp/src/crypto/backend/rust/ecdh.rs +++ b/openpgp/src/crypto/backend/rust/ecdh.rs @@ -52,6 +52,8 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>, (VB, shared) }, + Curve::Cv448 => + return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), Curve::NistP256 => { use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; @@ -111,6 +113,8 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>, let secret = r.diffie_hellman(&V); Vec::from(secret.to_bytes()).into() }, + Curve::Cv448 => + return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), Curve::NistP256 => { use p256::{ SecretKey, diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs index 2092ad07..33016dec 100644 --- a/openpgp/src/crypto/ecdh.rs +++ b/openpgp/src/crypto/ecdh.rs @@ -26,6 +26,7 @@ pub(crate) use crate::crypto::backend::ecdh::{encrypt, decrypt}; pub(crate) fn default_ecdh_kdf_hash(curve: &Curve) -> HashAlgorithm { match curve { Curve::Cv25519 => HashAlgorithm::SHA256, + Curve::Cv448 => HashAlgorithm::SHA512, // From RFC6637: Curve::NistP256 => HashAlgorithm::SHA256, Curve::NistP384 => HashAlgorithm::SHA384, @@ -35,6 +36,7 @@ pub(crate) fn default_ecdh_kdf_hash(curve: &Curve) -> HashAlgorithm { Curve::BrainpoolP512 => HashAlgorithm::SHA512, // Conservative default. Curve::Ed25519 // Odd: Not an encryption algo. + | Curve::Ed448 // Odd: Not an encryption algo. | Curve::Unknown(_) => HashAlgorithm::SHA512, } } @@ -43,6 +45,7 @@ pub(crate) fn default_ecdh_kdf_hash(curve: &Curve) -> HashAlgorithm { pub(crate) fn default_ecdh_kek_cipher(curve: &Curve) -> SymmetricAlgorithm { match curve { Curve::Cv25519 => SymmetricAlgorithm::AES128, + Curve::Cv448 => SymmetricAlgorithm::AES256, // From RFC6637: Curve::NistP256 => SymmetricAlgorithm::AES128, Curve::NistP384 => SymmetricAlgorithm::AES192, @@ -52,6 +55,7 @@ pub(crate) fn default_ecdh_kek_cipher(curve: &Curve) -> SymmetricAlgorithm { Curve::BrainpoolP512 => SymmetricAlgorithm::AES256, // Conservative default. Curve::Ed25519 // Odd: Not an encryption algo. + | Curve::Ed448 // Odd: Not an encryption algo. | Curve::Unknown(_) => SymmetricAlgorithm::AES256, } } diff --git a/openpgp/src/crypto/mpi.rs b/openpgp/src/crypto/mpi.rs index e21ba98a..26625474 100644 --- a/openpgp/src/crypto/mpi.rs +++ b/openpgp/src/crypto/mpi.rs @@ -71,6 +71,11 @@ impl MPI { } } + /// Creates new MPI encoding a native octet string. + pub fn new_octet_string<B: AsRef<[u8]>>(bytes: B) -> Self { + Self::new_octet_string_common(bytes.as_ref()).into() + } + /// Creates new MPI encoding an uncompressed EC point. /// /// Encodes the given point on a elliptic curve (see [Section 6 of @@ -106,11 +111,11 @@ impl MPI { /// /// [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2 pub fn new_compressed_point(x: &[u8]) -> Self { - Self::new_compressed_point_common(x).into() + Self::new_octet_string_common(x).into() } /// Common implementation shared between MPI and ProtectedMPI. - fn new_compressed_point_common(x: &[u8]) -> Vec<u8> { + fn new_octet_string_common(x: &[u8]) -> Vec<u8> { let mut val = vec![0; 1 + x.len()]; val[0] = 0x40; val[1..].copy_from_slice(x); @@ -153,6 +158,36 @@ impl MPI { crate::crypto::pad(self.value(), to) } + /// Decodes a native octet string encoded as MPI. + /// + /// Decodes the MPI into a native octet string for use with ECC + /// algorithms. + /// + /// # Errors + /// + /// `Error::MalformedMPI` if the point is formatted incorrectly or + /// the length doesn't match the expected length. + pub fn decode_octet_string(&self, expected_size: usize) -> Result<&[u8]> { + Self::decode_octet_string_common(self.value(), expected_size) + } + + /// Common implementation shared between MPI and ProtectedMPI. + fn decode_octet_string_common(value: &[u8], expected_size: usize) + -> Result<&[u8]> { + if value.len() != 1 + expected_size { + return Err(Error::MalformedMPI( + format!("Bad size of octet string: {} expected: {}", + value.len(), 1 + expected_size)).into()); + } + + if value.get(0).map(|&b| b != 0x40).unwrap_or(true) { + return Err(Error::MalformedMPI( + "Bad encoding of octet string".into()).into()); + } + + Ok(&value[1..]) + } + /// Decodes an EC point encoded as MPI. /// /// Decodes the MPI into a point on an elliptic curve (see @@ -201,6 +236,10 @@ impl MPI { Ok((&value[1..], &[])) }, + Ed448 | Cv448 => + Err(Error::InvalidOperation( + "Native octet string is not a point".into()).into()), + NistP256 | NistP384 | NistP521 @@ -372,6 +411,11 @@ impl std::hash::Hash for ProtectedMPI { } impl ProtectedMPI { + /// Creates new MPI encoding a native octet string. + pub fn new_octet_string<B: AsRef<[u8]>>(bytes: B) -> Self { + MPI::new_octet_string_common(bytes.as_ref()).into() + } + /// Creates new MPI encoding an uncompressed EC point. /// /// Encodes the given point on a elliptic curve (see [Section 6 of @@ -394,7 +438,7 @@ impl ProtectedMPI { /// /// [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2 pub fn new_compressed_point(x: &[u8]) -> Self { - MPI::new_compressed_point_common(x).into() + MPI::new_octet_string_common(x).into() } /// Returns the length of the MPI in bits. @@ -428,6 +472,19 @@ impl ProtectedMPI { v } + /// Decodes a native octet string encoded as MPI. + /// + /// Decodes the MPI into a native octet string for use with ECC + /// algorithms. + /// + /// # Errors + /// + /// `Error::MalformedMPI` if the point is formatted incorrectly or + /// the length doesn't match the expected length. + pub fn decode_octet_string(&self, expected_size: usize) -> Result<&[u8]> { + MPI::decode_octet_string_common(self.value(), expected_size) + } + /// Decodes an EC point encoded as MPI. /// /// Decodes the MPI into a point on an elliptic curve (see diff --git a/openpgp/src/packet/signature.rs b/openpgp/src/packet/signature.rs index a392adc5..bfd121d8 100644 --- a/openpgp/src/packet/signature.rs +++ b/openpgp/src/packet/signature.rs @@ -3709,6 +3709,7 @@ mod test { for curve in vec![ Ed25519, + Ed448, NistP256, NistP384, NistP521, diff --git a/openpgp/src/policy.rs b/openpgp/src/policy.rs index 0e2305fc..50eca0a1 100644 --- a/openpgp/src/policy.rs +++ b/openpgp/src/policy.rs @@ -700,7 +700,7 @@ a_cutoff_list!(SubpacketTagCutoffList, SubpacketTag, 38, ACCEPT, // 37. AttestedCertifications. ]); -a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 18, +a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 19, [ Some(Timestamp::Y2014M2), // 0. RSA1024. ACCEPT, // 1. RSA2048. @@ -720,6 +720,7 @@ a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 18, ACCEPT, // 15. BrainpoolP256. ACCEPT, // 16. BrainpoolP512. ACCEPT, // 17. Cv25519. + ACCEPT, // 18. Cv448. ]); a_cutoff_list!(SymmetricAlgorithmCutoffList, SymmetricAlgorithm, 14, @@ -1564,6 +1565,8 @@ impl<'a> Policy for StandardPolicy<'a> { Curve::BrainpoolP512 => BrainpoolP512, Curve::Ed25519 => Cv25519, Curve::Cv25519 => Cv25519, + Curve::Ed448 => Cv448, + Curve::Cv448 => Cv448, Curve::Unknown(_) => Unknown, } }, @@ -1693,6 +1696,8 @@ pub enum AsymmetricAlgorithm { BrainpoolP512, /// D.J. Bernstein's Curve25519. Cv25519, + /// Mike Hamburg's Edwards curve Ed448-Goldilocks. + Cv448, /// Unknown algorithm. Unknown, } @@ -1757,6 +1762,7 @@ impl From<AsymmetricAlgorithm> for u8 { BrainpoolP256 => 15, BrainpoolP512 => 16, Cv25519 => 17, + Cv448 => 18, Unknown => 255, } } diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs index 3d1a6acf..24001dda 100644 --- a/openpgp/src/types/mod.rs +++ b/openpgp/src/types/mod.rs @@ -363,6 +363,10 @@ pub enum Curve { Ed25519, /// Elliptic curve Diffie-Hellman using D.J. Bernstein's Curve25519. Cv25519, + /// Mike Hamburg's Edwards curve Ed448-Goldilocks. + Ed448, + /// Elliptic curve Diffie-Hellman using Mike Hamburg's Ed448-Goldilocks. + Cv448, /// Unknown curve. Unknown(Box<[u8]>), } @@ -402,6 +406,8 @@ impl Curve { BrainpoolP512 => Some(512), Ed25519 => Some(256), Cv25519 => Some(256), + Ed448 => Some(57 * 8), + Cv448 => Some(56 * 8), Unknown(_) => None, } } @@ -461,6 +467,11 @@ impl fmt::Display for Curve { => f.write_str("D.J. Bernstein's \"Twisted\" Edwards curve Ed25519"), Cv25519 => f.write_str("Elliptic curve Diffie-Hellman using D.J. Bernstein's Curve25519"), + Ed448 + => f.write_str("Mike Hamburg's Edwards curve Ed448-Goldilocks"), + Cv448 + => f.write_str("Elliptic curve Diffie-Hellman using \ + Mike Hamburg's Ed448-Goldilocks"), Unknown(ref oid) => write!(f, "Unknown curve (OID: {:?})", oid), } @@ -475,6 +486,8 @@ impl fmt::Display for Curve { => f.write_str("Ed25519"), Cv25519 => f.write_str("Curve25519"), + Ed448 => f.write_str("Ed448"), + Cv448 => f.write_str("Curve448"), Unknown(ref oid) => write!(f, "Unknown curve {:?}", oid), } @@ -493,6 +506,8 @@ const ED25519_OID: &[u8] = &[0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01]; const CV25519_OID: &[u8] = &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01]; +const ED448_OID: &[u8] = &[0x2b, 0x65, 0x71]; +const CV448_OID: &[u8] = &[0x2b, 0x65, 0x6f]; #[allow(clippy::len_without_is_empty)] impl Curve { @@ -517,6 +532,8 @@ impl Curve { BRAINPOOL_P512_OID => Curve::BrainpoolP512, ED25519_OID => Curve::Ed25519, CV25519_OID => Curve::Cv25519, + ED448_OID => Curve::Ed448, + CV448_OID => Curve::Cv448, oid => Curve::Unknown(Vec::from(oid).into_boxed_slice()), } |