diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-01-02 15:07:06 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-01-02 15:07:06 +0100 |
commit | de44f79686b9b4caadb6eda4637e5ed7ea9298a7 (patch) | |
tree | ac4f2379d6010d12fe8fa547a0d1de69705fed15 | |
parent | 3d0ad24698b0d3ec9e43114aa3110d6b28f720df (diff) |
openpgp: Move KeyPair to crypto.
-rw-r--r-- | openpgp/src/crypto/asymmetric.rs | 153 | ||||
-rw-r--r-- | openpgp/src/crypto/mod.rs | 5 | ||||
-rw-r--r-- | openpgp/src/message/mod.rs | 2 | ||||
-rw-r--r-- | openpgp/src/packet/signature/mod.rs | 151 | ||||
-rw-r--r-- | openpgp/src/packet/signature/subpacket.rs | 2 | ||||
-rw-r--r-- | openpgp/src/serialize/stream.rs | 3 | ||||
-rw-r--r-- | openpgp/src/tpk/builder.rs | 3 | ||||
-rw-r--r-- | openpgp/src/tpk/mod.rs | 3 | ||||
-rw-r--r-- | openpgp/src/tsk.rs | 3 |
9 files changed, 169 insertions, 156 deletions
diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs index 9c8a1ae6..51d95934 100644 --- a/openpgp/src/crypto/asymmetric.rs +++ b/openpgp/src/crypto/asymmetric.rs @@ -1,9 +1,12 @@ -//! Asymmetric crypto operations. +//! Asymmetric crypt operations. + +use nettle::{dsa, ecdsa, ed25519, rsa, Yarrow}; use packet::Key; -use crypto::mpis; -use constants::HashAlgorithm; +use crypto::mpis::{self, MPI}; +use constants::{Curve, HashAlgorithm}; +use Error; use Result; /// Creates a signature. @@ -20,3 +23,147 @@ pub trait Signer { fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<mpis::Signature>; } + +/// A cryptographic key pair. +pub struct KeyPair { + public: Key, + secret: mpis::SecretKey, +} + +impl KeyPair { + /// Creates a new key pair. + pub fn new(public: Key, secret: mpis::SecretKey) -> Result<Self> { + Ok(Self { + public: public, + secret: secret, + }) + } +} + +impl Signer for KeyPair { + fn public(&self) -> &Key { + &self.public + } + + fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) + -> Result<mpis::Signature> + { + use PublicKeyAlgorithm::*; + use crypto::mpis::PublicKey; + use memsec; + + let mut rng = Yarrow::default(); + + #[allow(deprecated)] + match (self.public.pk_algo(), self.public.mpis(), &self.secret) + { + (RSASign, + &PublicKey::RSA { ref e, ref n }, + &mpis::SecretKey::RSA { ref p, ref q, ref d, .. }) | + (RSAEncryptSign, + &PublicKey::RSA { ref e, ref n }, + &mpis::SecretKey::RSA { ref p, ref q, ref d, .. }) => { + let public = rsa::PublicKey::new(&n.value, &e.value)?; + let secret = rsa::PrivateKey::new(&d.value, &p.value, + &q.value, Option::None)?; + + // The signature has the length of the modulus. + let mut sig = vec![0u8; n.value.len()]; + + // As described in [Section 5.2.2 and 5.2.3 of RFC 4880], + // to verify the signature, we need to encode the + // signature data in a PKCS1-v1.5 packet. + // + // [Section 5.2.2 and 5.2.3 of RFC 4880]: + // https://tools.ietf.org/html/rfc4880#section-5.2.2 + rsa::sign_digest_pkcs1(&public, &secret, digest, + hash_algo.oid()?, + &mut rng, &mut sig)?; + + Ok(mpis::Signature::RSA { + s: MPI::new(&sig), + }) + }, + + (DSA, + &PublicKey::DSA { ref p, ref q, ref g, .. }, + &mpis::SecretKey::DSA { ref x }) => { + let params = dsa::Params::new(&p.value, &q.value, &g.value); + let secret = dsa::PrivateKey::new(&x.value); + + let sig = dsa::sign(¶ms, &secret, digest, &mut rng)?; + + Ok(mpis::Signature::DSA { + r: MPI::new(&sig.r()), + s: MPI::new(&sig.s()), + }) + }, + + (EdDSA, + &PublicKey::EdDSA { ref curve, ref q }, + &mpis::SecretKey::EdDSA { ref scalar }) => match curve { + Curve::Ed25519 => { + let public = q.decode_point(&Curve::Ed25519)?.0; + + let mut sig = vec![0; ed25519::ED25519_SIGNATURE_SIZE]; + + // Nettle expects the private key to be exactly + // ED25519_KEY_SIZE bytes long but OpenPGP allows leading + // zeros to be stripped. + // Padding has to be unconditionaly, otherwise we have a + // secret-dependant branch. + let missing = ed25519::ED25519_KEY_SIZE + .saturating_sub(scalar.value.len()); + let mut sec = [0u8; ed25519::ED25519_KEY_SIZE]; + sec[missing..].copy_from_slice(&scalar.value[..]); + + let res = ed25519::sign(public, &sec[..], digest, &mut sig); + unsafe { + memsec::memzero(sec.as_mut_ptr(), + ed25519::ED25519_KEY_SIZE); + } + res?; + + Ok(mpis::Signature::EdDSA { + r: MPI::new(&sig[..32]), + s: MPI::new(&sig[32..]), + }) + }, + _ => Err( + Error::UnsupportedEllipticCurve(curve.clone()).into()), + }, + + (ECDSA, + &PublicKey::ECDSA { ref curve, .. }, + &mpis::SecretKey::ECDSA { ref scalar }) => { + let secret = match curve { + Curve::NistP256 => + ecdsa::PrivateKey::new::<ecdsa::Secp256r1>( + &scalar.value)?, + Curve::NistP384 => + ecdsa::PrivateKey::new::<ecdsa::Secp384r1>( + &scalar.value)?, + Curve::NistP521 => + ecdsa::PrivateKey::new::<ecdsa::Secp521r1>( + &scalar.value)?, + _ => + return Err( + Error::UnsupportedEllipticCurve(curve.clone()) + .into()), + }; + + let sig = ecdsa::sign(&secret, digest, &mut rng); + + Ok(mpis::Signature::ECDSA { + r: MPI::new(&sig.r()), + s: MPI::new(&sig.s()), + }) + }, + + (pk_algo, _, _) => Err(Error::InvalidArgument(format!( + "unsupported combination of algorithm {:?}, key {:?}, \ + and secret key {:?}", + pk_algo, self.public, self.secret)).into()), + } + } +} diff --git a/openpgp/src/crypto/mod.rs b/openpgp/src/crypto/mod.rs index 300a5aeb..33f27078 100644 --- a/openpgp/src/crypto/mod.rs +++ b/openpgp/src/crypto/mod.rs @@ -20,7 +20,10 @@ pub mod mpis; pub mod s2k; pub(crate) mod symmetric; -pub use self::asymmetric::Signer; +pub use self::asymmetric::{ + Signer, + KeyPair, +}; /// Holds a session key. /// diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs index c7be55ea..9c64f7d9 100644 --- a/openpgp/src/message/mod.rs +++ b/openpgp/src/message/mod.rs @@ -402,6 +402,7 @@ mod tests { use SymmetricAlgorithm; use PublicKeyAlgorithm; use SignatureType; + use crypto::KeyPair; use crypto::s2k::S2K; use crypto::mpis::{Ciphertext, MPI}; use packet::Tag; @@ -413,7 +414,6 @@ mod tests { use packet::SEIP; use packet::MDC; use packet::key::SecretKey; - use packet::signature::KeyPair; use KeyID; use Container; diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs index 22240259..ef040841 100644 --- a/openpgp/src/packet/signature/mod.rs +++ b/openpgp/src/packet/signature/mod.rs @@ -7,7 +7,7 @@ use constants::Curve; use Error; use Result; use crypto::{ - mpis::{self, MPI}, + mpis, Signer, }; use HashAlgorithm; @@ -22,7 +22,7 @@ use packet; use packet::signature::subpacket::SubpacketArea; use serialize::Serialize; -use nettle::{dsa, ecdsa, ed25519, Hash, rsa, Yarrow}; +use nettle::{dsa, ecdsa, ed25519, Hash, rsa}; use nettle::rsa::verify_digest_pkcs1; #[cfg(test)] @@ -214,150 +214,6 @@ impl Builder { } } -/// A cryptographic key pair. -pub struct KeyPair { - public: Key, - secret: mpis::SecretKey, -} - -impl KeyPair { - /// Creates a new key pair. - pub fn new(public: Key, secret: mpis::SecretKey) -> Result<Self> { - Ok(Self { - public: public, - secret: secret, - }) - } -} - -impl Signer for KeyPair { - fn public(&self) -> &Key { - &self.public - } - - fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) - -> Result<mpis::Signature> - { - use PublicKeyAlgorithm::*; - use crypto::mpis::PublicKey; - use memsec; - - let mut rng = Yarrow::default(); - - #[allow(deprecated)] - match (self.public.pk_algo(), self.public.mpis(), &self.secret) - { - (RSASign, - &PublicKey::RSA { ref e, ref n }, - &mpis::SecretKey::RSA { ref p, ref q, ref d, .. }) | - (RSAEncryptSign, - &PublicKey::RSA { ref e, ref n }, - &mpis::SecretKey::RSA { ref p, ref q, ref d, .. }) => { - let public = rsa::PublicKey::new(&n.value, &e.value)?; - let secret = rsa::PrivateKey::new(&d.value, &p.value, - &q.value, Option::None)?; - - // The signature has the length of the modulus. - let mut sig = vec![0u8; n.value.len()]; - - // As described in [Section 5.2.2 and 5.2.3 of RFC 4880], - // to verify the signature, we need to encode the - // signature data in a PKCS1-v1.5 packet. - // - // [Section 5.2.2 and 5.2.3 of RFC 4880]: - // https://tools.ietf.org/html/rfc4880#section-5.2.2 - rsa::sign_digest_pkcs1(&public, &secret, digest, - hash_algo.oid()?, - &mut rng, &mut sig)?; - - Ok(mpis::Signature::RSA { - s: MPI::new(&sig), - }) - }, - - (DSA, - &PublicKey::DSA { ref p, ref q, ref g, .. }, - &mpis::SecretKey::DSA { ref x }) => { - let params = dsa::Params::new(&p.value, &q.value, &g.value); - let secret = dsa::PrivateKey::new(&x.value); - - let sig = dsa::sign(¶ms, &secret, digest, &mut rng)?; - - Ok(mpis::Signature::DSA { - r: MPI::new(&sig.r()), - s: MPI::new(&sig.s()), - }) - }, - - (EdDSA, - &PublicKey::EdDSA { ref curve, ref q }, - &mpis::SecretKey::EdDSA { ref scalar }) => match curve { - Curve::Ed25519 => { - let public = q.decode_point(&Curve::Ed25519)?.0; - - let mut sig = vec![0; ed25519::ED25519_SIGNATURE_SIZE]; - - // Nettle expects the private key to be exactly - // ED25519_KEY_SIZE bytes long but OpenPGP allows leading - // zeros to be stripped. - // Padding has to be unconditionaly, otherwise we have a - // secret-dependant branch. - let missing = ed25519::ED25519_KEY_SIZE - .saturating_sub(scalar.value.len()); - let mut sec = [0u8; ed25519::ED25519_KEY_SIZE]; - sec[missing..].copy_from_slice(&scalar.value[..]); - - let res = ed25519::sign(public, &sec[..], digest, &mut sig); - unsafe { - memsec::memzero(sec.as_mut_ptr(), - ed25519::ED25519_KEY_SIZE); - } - res?; - - Ok(mpis::Signature::EdDSA { - r: MPI::new(&sig[..32]), - s: MPI::new(&sig[32..]), - }) - }, - _ => Err( - Error::UnsupportedEllipticCurve(curve.clone()).into()), - }, - - (ECDSA, - &PublicKey::ECDSA { ref curve, .. }, - &mpis::SecretKey::ECDSA { ref scalar }) => { - let secret = match curve { - Curve::NistP256 => - ecdsa::PrivateKey::new::<ecdsa::Secp256r1>( - &scalar.value)?, - Curve::NistP384 => - ecdsa::PrivateKey::new::<ecdsa::Secp384r1>( - &scalar.value)?, - Curve::NistP521 => - ecdsa::PrivateKey::new::<ecdsa::Secp521r1>( - &scalar.value)?, - _ => - return Err( - Error::UnsupportedEllipticCurve(curve.clone()) - .into()), - }; - - let sig = ecdsa::sign(&secret, digest, &mut rng); - - Ok(mpis::Signature::ECDSA { - r: MPI::new(&sig.r()), - s: MPI::new(&sig.s()), - }) - }, - - (pk_algo, _, _) => Err(Error::InvalidArgument(format!( - "unsupported combination of algorithm {:?}, key {:?}, \ - and secret key {:?}", - pk_algo, self.public, self.secret)).into()), - } - } -} - impl From<Signature> for Builder { fn from(sig: Signature) -> Self { sig.fields @@ -904,7 +760,10 @@ impl From<Signature> for Packet { #[cfg(test)] mod test { + use nettle::Yarrow; use super::*; + use crypto::KeyPair; + use crypto::mpis::MPI; use TPK; use parse::Parse; diff --git a/openpgp/src/packet/signature/subpacket.rs b/openpgp/src/packet/signature/subpacket.rs index 90b48b3c..6506cca1 100644 --- a/openpgp/src/packet/signature/subpacket.rs +++ b/openpgp/src/packet/signature/subpacket.rs @@ -2238,7 +2238,7 @@ impl signature::Builder { #[test] fn accessors() { use packet::key::SecretKey; - use packet::signature::KeyPair; + use crypto::KeyPair; let pk_algo = PublicKeyAlgorithm::EdDSA; let hash_algo = HashAlgorithm::SHA512; diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index 9deebe65..503ad11c 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -16,6 +16,7 @@ use time; use nettle::{Hash, Yarrow}; use { + crypto::KeyPair, Error, Fingerprint, HashAlgorithm, @@ -31,7 +32,7 @@ use { crypto::SessionKey, packet::SKESK4, packet::SKESK5, - packet::signature::{self, Signature, KeyPair}, + packet::signature::{self, Signature}, packet::Tag, TPK, }; diff --git a/openpgp/src/tpk/builder.rs b/openpgp/src/tpk/builder.rs index 6a1e5c03..fa145720 100644 --- a/openpgp/src/tpk/builder.rs +++ b/openpgp/src/tpk/builder.rs @@ -3,9 +3,10 @@ use packet::{Features, KeyFlags}; use packet::Key; use Result; use packet::UserID; +use crypto::KeyPair; use SymmetricAlgorithm; use HashAlgorithm; -use packet::signature::{self, Signature, KeyPair}; +use packet::signature::{self, Signature}; use TPK; use PublicKeyAlgorithm; use Error; diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs index 5203940a..34788c24 100644 --- a/openpgp/src/tpk/mod.rs +++ b/openpgp/src/tpk/mod.rs @@ -11,6 +11,7 @@ use time; use failure; use { + crypto::KeyPair, Error, Result, RevocationStatus, @@ -18,7 +19,7 @@ use { HashAlgorithm, packet::Tag, packet::key::SecretKey, - packet::signature::{self, Signature, KeyPair}, + packet::signature::{self, Signature}, packet::Key, packet::UserID, packet::UserAttribute, diff --git a/openpgp/src/tsk.rs b/openpgp/src/tsk.rs index 05734be8..d9ec86bf 100644 --- a/openpgp/src/tsk.rs +++ b/openpgp/src/tsk.rs @@ -9,8 +9,9 @@ use { Error, }; +use crypto::KeyPair; use packet::{ - signature::{Signature, KeyPair}, + signature::Signature, Tag, UserID, Key, |