diff options
author | Wiktor Kwapisiewicz <wiktor@metacode.biz> | 2023-03-23 09:59:46 +0100 |
---|---|---|
committer | Wiktor Kwapisiewicz <wiktor@metacode.biz> | 2023-03-23 14:22:59 +0100 |
commit | eab194fceb8acbe436ad6ab60f89a957f2e61bd2 (patch) | |
tree | 9430f02db8e9d9be07a8a9ba5ac9d0a9eae5837a | |
parent | b1d8527d1fb56e2d97c8a285d2ff1dc1e931d4c6 (diff) |
openpgp: Move `Key4::import_secret_cv25519` into common code.
- Most of the logic in this function is the same across backends.
- Introduce `Key4::derive_cv25519_public_key` that does
backend-specific derivation.
- Fixes https://gitlab.com/sequoia-pgp/sequoia/-/issues/958
-rw-r--r-- | openpgp/src/crypto/backend/botan/asymmetric.rs | 34 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng/asymmetric.rs | 47 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/asymmetric.rs | 39 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/openssl/asymmetric.rs | 44 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust/asymmetric.rs | 38 | ||||
-rw-r--r-- | openpgp/src/packet/key.rs | 37 |
6 files changed, 53 insertions, 186 deletions
diff --git a/openpgp/src/crypto/backend/botan/asymmetric.rs b/openpgp/src/crypto/backend/botan/asymmetric.rs index bf9b53c6..51ed2edc 100644 --- a/openpgp/src/crypto/backend/botan/asymmetric.rs +++ b/openpgp/src/crypto/backend/botan/asymmetric.rs @@ -29,7 +29,6 @@ use crate::{ Curve, HashAlgorithm, PublicKeyAlgorithm, - SymmetricAlgorithm, }, }; @@ -392,40 +391,11 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { impl<R> Key4<SecretParts, R> where R: key::KeyRole, { - /// Creates a new OpenPGP secret key packet for an existing X25519 key. - /// - /// The ECDH key will use hash algorithm `hash` and symmetric - /// algorithm `sym`. If one or both are `None` secure defaults - /// will be used. The key will have it's creation date set to - /// `ctime` or the current time if `None` is given. - pub fn import_secret_cv25519<H, S, T>(private_key: &[u8], - hash: H, sym: S, ctime: T) - -> Result<Self> where H: Into<Option<HashAlgorithm>>, - S: Into<Option<SymmetricAlgorithm>>, - T: Into<Option<SystemTime>> + pub(crate) fn derive_cv25519_public_key(private_key: &Protected) -> Result<[u8; 32]> { let secret = Privkey::load_x25519(private_key)?; - let public = secret.pubkey()?.get_x25519_key()?; - let mut secret = secret.get_x25519_key()?; - - // OpenPGP stores the secret in reverse order. - secret.reverse(); - use crate::crypto::ecdh; - Self::with_secret( - ctime.into().unwrap_or_else(crate::now), - PublicKeyAlgorithm::ECDH, - mpi::PublicKey::ECDH { - curve: Curve::Cv25519, - hash: hash.into().unwrap_or_else( - || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)), - sym: sym.into().unwrap_or_else( - || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)), - q: MPI::new_compressed_point(&public), - }, - mpi::SecretKeyMaterial::ECDH { - scalar: secret.into(), - }.into()) + Ok(<[u8; 32]>::try_from(&secret.pubkey()?.get_x25519_key()?[..])?) } /// Creates a new OpenPGP secret key packet for an existing Ed25519 key. diff --git a/openpgp/src/crypto/backend/cng/asymmetric.rs b/openpgp/src/crypto/backend/cng/asymmetric.rs index d0a5fd9b..1eb110af 100644 --- a/openpgp/src/crypto/backend/cng/asymmetric.rs +++ b/openpgp/src/crypto/backend/cng/asymmetric.rs @@ -13,7 +13,7 @@ use crate::crypto::SessionKey; use crate::crypto::{pad, pad_at_least, pad_truncating}; use crate::packet::key::{Key4, SecretParts}; use crate::packet::{key, Key}; -use crate::types::{PublicKeyAlgorithm, SymmetricAlgorithm}; +use crate::types::PublicKeyAlgorithm; use crate::types::{Curve, HashAlgorithm}; use num_bigint_dig::{traits::ModInverse, BigInt, BigUint}; @@ -684,22 +684,7 @@ impl<R> Key4<SecretParts, R> where R: key::KeyRole, { - /// Creates a new OpenPGP secret key packet for an existing X25519 key. - /// - /// The ECDH key will use hash algorithm `hash` and symmetric - /// algorithm `sym`. If one or both are `None` secure defaults - /// will be used. The key will have its creation date set to - /// `ctime` or the current time if `None` is given. - pub fn import_secret_cv25519<H, S, T>( - private_key: &[u8], - hash: H, - sym: S, - ctime: T, - ) -> Result<Self> - where - H: Into<Option<HashAlgorithm>>, - S: Into<Option<SymmetricAlgorithm>>, - T: Into<Option<SystemTime>>, + pub(crate) fn derive_cv25519_public_key(private_key: &Protected) -> Result<[u8; 32]> { use cng::asymmetric::{AsymmetricAlgorithm, AsymmetricAlgorithmId, Ecdh, Private}; use cng::asymmetric::{AsymmetricKey, Export}; @@ -712,33 +697,7 @@ where &provider, private_key )?; - let blob = key.export()?; - - // Mark MPI as compressed point with 0x40 prefix. See - // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07#section-13.2. - let mut public = [0u8; 1 + CURVE25519_SIZE]; - public[0] = 0x40; - public[1..].copy_from_slice(blob.x()); - - // Reverse the scalar. See - // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html. - let mut private = blob.d().to_vec(); - private.reverse(); - - use crate::crypto::ecdh; - Self::with_secret( - ctime.into().unwrap_or_else(crate::now), - PublicKeyAlgorithm::ECDH, - mpi::PublicKey::ECDH { - curve: Curve::Cv25519, - hash: hash.into().unwrap_or_else( - || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)), - sym: sym.into().unwrap_or_else( - || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)), - q: mpi::MPI::new(&public), - }, - mpi::SecretKeyMaterial::ECDH { scalar: private.into() }.into() - ) + Ok(<[u8; 32]>::try_from(&key.export()?.x()[..])?) } /// Creates a new OpenPGP secret key packet for an existing Ed25519 key. diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs index 0d908c55..54fa31d2 100644 --- a/openpgp/src/crypto/backend/nettle/asymmetric.rs +++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs @@ -319,45 +319,16 @@ 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, SymmetricAlgorithm}; +use crate::types::PublicKeyAlgorithm; impl<R> Key4<SecretParts, R> where R: key::KeyRole, { - - /// Creates a new OpenPGP secret key packet for an existing X25519 key. - /// - /// The ECDH key will use hash algorithm `hash` and symmetric - /// algorithm `sym`. If one or both are `None` secure defaults - /// will be used. The key will have it's creation date set to - /// `ctime` or the current time if `None` is given. - pub fn import_secret_cv25519<H, S, T>(private_key: &[u8], - hash: H, sym: S, ctime: T) - -> Result<Self> where H: Into<Option<HashAlgorithm>>, - S: Into<Option<SymmetricAlgorithm>>, - T: Into<Option<SystemTime>> + pub(crate) fn derive_cv25519_public_key(private_key: &Protected) -> Result<[u8; 32]> { - let mut public_key = [0; curve25519::CURVE25519_SIZE]; - curve25519::mul_g(&mut public_key, private_key).unwrap(); - - let mut private_key = Vec::from(private_key); - private_key.reverse(); - - use crate::crypto::ecdh; - Self::with_secret( - ctime.into().unwrap_or_else(crate::now), - PublicKeyAlgorithm::ECDH, - mpi::PublicKey::ECDH { - curve: Curve::Cv25519, - hash: hash.into().unwrap_or_else( - || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)), - sym: sym.into().unwrap_or_else( - || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)), - q: MPI::new_compressed_point(&public_key), - }, - mpi::SecretKeyMaterial::ECDH { - scalar: private_key.into(), - }.into()) + let mut public_key = [0; ed25519::ED25519_KEY_SIZE]; + curve25519::mul_g(&mut public_key, private_key)?; + Ok(public_key) } /// Creates a new OpenPGP secret key packet for an existing Ed25519 key. diff --git a/openpgp/src/crypto/backend/openssl/asymmetric.rs b/openpgp/src/crypto/backend/openssl/asymmetric.rs index 07d0c7f4..1d586585 100644 --- a/openpgp/src/crypto/backend/openssl/asymmetric.rs +++ b/openpgp/src/crypto/backend/openssl/asymmetric.rs @@ -7,7 +7,6 @@ use crate::crypto::mem::Protected; use crate::crypto::SessionKey; use crate::packet::key::{Key4, SecretParts}; use crate::packet::{key, Key}; -use crate::types::SymmetricAlgorithm; use crate::types::{Curve, HashAlgorithm, PublicKeyAlgorithm}; use std::convert::{TryFrom, TryInto}; use std::time::SystemTime; @@ -391,48 +390,11 @@ impl<R> Key4<SecretParts, R> where R: key::KeyRole, { - /// Creates a new OpenPGP secret key packet for an existing X25519 key. - /// - /// The ECDH key will use hash algorithm `hash` and symmetric - /// algorithm `sym`. If one or both are `None` secure defaults - /// will be used. The key will have it's creation date set to - /// `ctime` or the current time if `None` is given. - pub fn import_secret_cv25519<H, S, T>( - private_key: &[u8], - hash: H, - sym: S, - ctime: T, - ) -> Result<Self> - where - H: Into<Option<HashAlgorithm>>, - S: Into<Option<SymmetricAlgorithm>>, - T: Into<Option<SystemTime>>, + pub(crate) fn derive_cv25519_public_key(private_key: &Protected) -> Result<[u8; 32]> { let key = PKey::private_key_from_raw_bytes(private_key, openssl::pkey::Id::X25519)?; - let public_key = key.raw_public_key()?; - - let mut private_key: Protected = key.raw_private_key().map(|key| key.into())?; - private_key.reverse(); - - use crate::crypto::ecdh; - Self::with_secret( - ctime.into().unwrap_or_else(crate::now), - PublicKeyAlgorithm::ECDH, - mpi::PublicKey::ECDH { - curve: Curve::Cv25519, - hash: hash - .into() - .unwrap_or_else(|| ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)), - sym: sym - .into() - .unwrap_or_else(|| ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)), - q: MPI::new_compressed_point(&public_key), - }, - mpi::SecretKeyMaterial::ECDH { - scalar: private_key.into(), - } - .into(), - ) + let public = key.raw_public_key()?; + Ok(<[u8; 32]>::try_from(&public[..])?) } /// Creates a new OpenPGP secret key packet for an existing Ed25519 key. diff --git a/openpgp/src/crypto/backend/rust/asymmetric.rs b/openpgp/src/crypto/backend/rust/asymmetric.rs index 1ee32fc2..4090fdbb 100644 --- a/openpgp/src/crypto/backend/rust/asymmetric.rs +++ b/openpgp/src/crypto/backend/rust/asymmetric.rs @@ -19,7 +19,7 @@ use crate::crypto::SessionKey; use crate::crypto::pad_truncating; use crate::packet::{key, Key}; use crate::packet::key::{Key4, SecretParts}; -use crate::types::{Curve, HashAlgorithm, PublicKeyAlgorithm, SymmetricAlgorithm}; +use crate::types::{Curve, HashAlgorithm, PublicKeyAlgorithm}; const CURVE25519_SIZE: usize = 32; @@ -345,42 +345,12 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { impl<R> Key4<SecretParts, R> where R: key::KeyRole, { - - /// Creates a new OpenPGP secret key packet for an existing X25519 key. - /// - /// The ECDH key will use hash algorithm `hash` and symmetric - /// algorithm `sym`. If one or both are `None` secure defaults - /// will be used. The key will have it's creation date set to - /// `ctime` or the current time if `None` is given. - pub fn import_secret_cv25519<H, S, T>(private_key: &[u8], - hash: H, sym: S, ctime: T) - -> Result<Self> where H: Into<Option<HashAlgorithm>>, - S: Into<Option<SymmetricAlgorithm>>, - T: Into<Option<SystemTime>> + pub(crate) fn derive_cv25519_public_key(private_key: &Protected) -> Result<[u8; 32]> { use x25519_dalek::{PublicKey, StaticSecret}; - let secret = StaticSecret::from(<[u8; 32]>::try_from(private_key)?); - let public_key = PublicKey::from(&secret); - - let mut private_key = Vec::from(private_key); - private_key.reverse(); - - use crate::crypto::ecdh; - Self::with_secret( - ctime.into().unwrap_or_else(crate::now), - PublicKeyAlgorithm::ECDH, - mpi::PublicKey::ECDH { - curve: Curve::Cv25519, - hash: hash.into().unwrap_or_else( - || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)), - sym: sym.into().unwrap_or_else( - || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)), - q: MPI::new_compressed_point(&*public_key.as_bytes()), - }, - mpi::SecretKeyMaterial::ECDH { - scalar: private_key.into(), - }.into()) + let secret = StaticSecret::from(<[u8; 32]>::try_from(&private_key[..])?); + Ok(*PublicKey::from(&secret).as_bytes()) } /// Creates a new OpenPGP secret key packet for an existing Ed25519 key. diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs index 148061d8..a6079f40 100644 --- a/openpgp/src/packet/key.rs +++ b/openpgp/src/packet/key.rs @@ -91,7 +91,7 @@ use quickcheck::{Arbitrary, Gen}; use crate::Error; use crate::cert::prelude::*; -use crate::crypto::{self, mem, mpi, hash::{Hash, Digest}}; +use crate::crypto::{self, mem::{self, Protected}, mpi, hash::{Hash, Digest}}; use crate::packet; use crate::packet::prelude::*; use crate::PublicKeyAlgorithm; @@ -1053,6 +1053,41 @@ impl<R> Key4<SecretParts, R> r: std::marker::PhantomData, }) } + + /// Creates a new OpenPGP secret key packet for an existing X25519 key. + /// + /// The ECDH key will use hash algorithm `hash` and symmetric + /// algorithm `sym`. If one or both are `None` secure defaults + /// will be used. The key will have it's creation date set to + /// `ctime` or the current time if `None` is given. + pub fn import_secret_cv25519<H, S, T>(private_key: &[u8], + hash: H, sym: S, ctime: T) + -> Result<Self> where H: Into<Option<HashAlgorithm>>, + S: Into<Option<SymmetricAlgorithm>>, + T: Into<Option<std::time::SystemTime>> + { + let mut private_key = Protected::from(private_key); + + let public_key = Self::derive_cv25519_public_key(&private_key)?; + + private_key.reverse(); + + use crate::crypto::ecdh; + Self::with_secret( + ctime.into().unwrap_or_else(crate::now), + PublicKeyAlgorithm::ECDH, + mpi::PublicKey::ECDH { + curve: Curve::Cv25519, + hash: hash.into().unwrap_or_else( + || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)), + sym: sym.into().unwrap_or_else( + || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)), + q: mpi::MPI::new_compressed_point(&public_key), + }, + mpi::SecretKeyMaterial::ECDH { + scalar: private_key.into(), + }.into()) + } } impl<P, R> Key4<P, R> |