summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-01-13 12:35:07 +0100
committerJustus Winter <justus@sequoia-pgp.org>2023-01-13 12:35:07 +0100
commitc96e976d0faed03bb29f459cd2879ff96ac7f316 (patch)
treecb530e79f29cec410b4f7caf15a170afbdcf8d70
parent92e8b887662cdbc251722438c8195b8e40f4fc2f (diff)
parente9906e642a674598785523128503cc8a1a45ff96 (diff)
Merge branch 'justus/openpgp-next-cv448' into justus/openpgp-nextjustus/openpgp-next
-rw-r--r--openpgp/src/cert/builder.rs19
-rw-r--r--openpgp/src/crypto/backend/cng.rs2
-rw-r--r--openpgp/src/crypto/backend/cng/ecdh.rs7
-rw-r--r--openpgp/src/crypto/backend/nettle.rs4
-rw-r--r--openpgp/src/crypto/backend/nettle/asymmetric.rs75
-rw-r--r--openpgp/src/crypto/backend/nettle/ecdh.rs48
-rw-r--r--openpgp/src/crypto/backend/rust.rs2
-rw-r--r--openpgp/src/crypto/backend/rust/ecdh.rs4
-rw-r--r--openpgp/src/crypto/ecdh.rs4
-rw-r--r--openpgp/src/crypto/mpi.rs63
-rw-r--r--openpgp/src/packet/signature.rs1
-rw-r--r--openpgp/src/policy.rs8
-rw-r--r--openpgp/src/types/mod.rs27
-rw-r--r--sq/sq-usage.md2
-rw-r--r--sq/src/commands/key.rs3
-rw-r--r--sq/src/sq_cli/key.rs3
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()),
}