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 /openpgp/src/crypto/asymmetric.rs | |
parent | 3d0ad24698b0d3ec9e43114aa3110d6b28f720df (diff) |
openpgp: Move KeyPair to crypto.
Diffstat (limited to 'openpgp/src/crypto/asymmetric.rs')
-rw-r--r-- | openpgp/src/crypto/asymmetric.rs | 153 |
1 files changed, 150 insertions, 3 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()), + } + } +} |