diff options
Diffstat (limited to 'openpgp/src/crypto')
-rw-r--r-- | openpgp/src/crypto/aead.rs | 29 | ||||
-rw-r--r-- | openpgp/src/crypto/asymmetric.rs | 60 | ||||
-rw-r--r-- | openpgp/src/crypto/ecdh.rs | 12 | ||||
-rw-r--r-- | openpgp/src/crypto/hash.rs | 122 | ||||
-rw-r--r-- | openpgp/src/crypto/keygrip.rs | 89 | ||||
-rw-r--r-- | openpgp/src/crypto/mem.rs | 24 | ||||
-rw-r--r-- | openpgp/src/crypto/mod.rs | 32 | ||||
-rw-r--r-- | openpgp/src/crypto/mpi.rs (renamed from openpgp/src/crypto/mpis.rs) | 17 | ||||
-rw-r--r-- | openpgp/src/crypto/s2k.rs | 5 | ||||
-rw-r--r-- | openpgp/src/crypto/sexp.rs | 141 | ||||
-rw-r--r-- | openpgp/src/crypto/symmetric.rs | 16 |
11 files changed, 303 insertions, 244 deletions
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs index 03d5c995..61cfd7f7 100644 --- a/openpgp/src/crypto/aead.rs +++ b/openpgp/src/crypto/aead.rs @@ -1,4 +1,5 @@ use std::cmp; +use std::convert::TryInto; use std::fmt; use std::io; @@ -24,6 +25,14 @@ use crate::parse::Cookie; /// malformed AEAD-encrypted messages. const DANGER_DISABLE_AUTHENTICATION: bool = false; +/// Converts a chunk size to a usize. +pub(crate) fn chunk_size_usize(chunk_size: u64) -> Result<usize> { + chunk_size.try_into() + .map_err(|_| Error::InvalidOperation( + format!("AEAD chunk size exceeds size of \ + virtual memory: {}", chunk_size)).into()) +} + impl AEADAlgorithm { /// Returns the digest size of the AEAD algorithm. pub fn digest_size(&self) -> Result<usize> { @@ -54,8 +63,8 @@ impl AEADAlgorithm { } } - /// Creates a nettle context. - pub fn context(&self, sym_algo: SymmetricAlgorithm, key: &[u8], nonce: &[u8]) + /// Creates a Nettle context. + pub(crate) fn context(&self, sym_algo: SymmetricAlgorithm, key: &[u8], nonce: &[u8]) -> Result<Box<dyn aead::Aead>> { match self { AEADAlgorithm::EAX => match sym_algo { @@ -133,9 +142,9 @@ impl<'a> Decryptor<'a> { -> Result<Self> { Ok(Decryptor { - source: source, - sym_algo: sym_algo, - aead: aead, + source, + sym_algo, + aead, key: key.clone(), iv: Vec::from(iv).into_boxed_slice(), ad: [ @@ -148,7 +157,7 @@ impl<'a> Decryptor<'a> { 0, 0, 0, 0, 0, 0, 0, 0, ], digest_size: aead.digest_size()?, - chunk_size: chunk_size, + chunk_size, chunk_index: 0, bytes_decrypted: 0, buffer: Vec::with_capacity(chunk_size), @@ -551,8 +560,8 @@ impl<W: io::Write> Encryptor<W> { Ok(Encryptor { inner: Some(sink), - sym_algo: sym_algo, - aead: aead, + sym_algo, + aead, key: key.clone(), iv: Vec::from(iv).into_boxed_slice(), ad: [ @@ -565,11 +574,11 @@ impl<W: io::Write> Encryptor<W> { 0, 0, 0, 0, 0, 0, 0, 0, ], digest_size: aead.digest_size()?, - chunk_size: chunk_size, + chunk_size, chunk_index: 0, bytes_encrypted: 0, buffer: Vec::with_capacity(chunk_size), - scratch: scratch, + scratch, }) } diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs index b39100e2..534e4912 100644 --- a/openpgp/src/crypto/asymmetric.rs +++ b/openpgp/src/crypto/asymmetric.rs @@ -4,7 +4,7 @@ use nettle::{dsa, ecc, ecdsa, ed25519, rsa, random::Yarrow}; use crate::packet::{self, key, Key}; use crate::crypto::SessionKey; -use crate::crypto::mpis::{self, MPI}; +use crate::crypto::mpi::{self, MPI}; use crate::types::{Curve, HashAlgorithm}; use crate::Error; @@ -22,7 +22,7 @@ pub trait Signer { /// Creates a signature over the `digest` produced by `hash_algo`. fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) - -> Result<mpis::Signature>; + -> Result<mpi::Signature>; } impl Signer for Box<dyn Signer> { @@ -31,7 +31,7 @@ impl Signer for Box<dyn Signer> { } fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) - -> Result<mpis::Signature> { + -> Result<mpi::Signature> { self.as_mut().sign(hash_algo, digest) } } @@ -47,7 +47,7 @@ pub trait Decryptor { fn public(&self) -> &Key<key::PublicParts, key::UnspecifiedRole>; /// Decrypts `ciphertext`, returning the plain session key. - fn decrypt(&mut self, ciphertext: &mpis::Ciphertext, + fn decrypt(&mut self, ciphertext: &mpi::Ciphertext, plaintext_len: Option<usize>) -> Result<SessionKey>; } @@ -73,8 +73,8 @@ impl KeyPair { -> Result<Self> { Ok(Self { - public: public, - secret: secret, + public, + secret, }) } @@ -95,10 +95,10 @@ impl Signer for KeyPair { } fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) - -> Result<mpis::Signature> + -> Result<mpi::Signature> { use crate::PublicKeyAlgorithm::*; - use crate::crypto::mpis::PublicKey; + use crate::crypto::mpi::PublicKey; let mut rng = Yarrow::default(); @@ -108,10 +108,10 @@ impl Signer for KeyPair { { (RSASign, &PublicKey::RSA { ref e, ref n }, - &mpis::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) | + &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) | (RSAEncryptSign, &PublicKey::RSA { ref e, ref n }, - &mpis::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) => { + &mpi::SecretKeyMaterial::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)?; @@ -129,20 +129,20 @@ impl Signer for KeyPair { hash_algo.oid()?, &mut rng, &mut sig)?; - Ok(mpis::Signature::RSA { + Ok(mpi::Signature::RSA { s: MPI::new(&sig), }) }, (DSA, &PublicKey::DSA { ref p, ref q, ref g, .. }, - &mpis::SecretKeyMaterial::DSA { ref x }) => { + &mpi::SecretKeyMaterial::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 { + Ok(mpi::Signature::DSA { r: MPI::new(&sig.r()), s: MPI::new(&sig.s()), }) @@ -150,7 +150,7 @@ impl Signer for KeyPair { (EdDSA, &PublicKey::EdDSA { ref curve, ref q }, - &mpis::SecretKeyMaterial::EdDSA { ref scalar }) => match curve { + &mpi::SecretKeyMaterial::EdDSA { ref scalar }) => match curve { Curve::Ed25519 => { let public = q.decode_point(&Curve::Ed25519)?.0; @@ -173,7 +173,7 @@ impl Signer for KeyPair { } res?; - Ok(mpis::Signature::EdDSA { + Ok(mpi::Signature::EdDSA { r: MPI::new(&sig[..32]), s: MPI::new(&sig[32..]), }) @@ -184,7 +184,7 @@ impl Signer for KeyPair { (ECDSA, &PublicKey::ECDSA { ref curve, .. }, - &mpis::SecretKeyMaterial::ECDSA { ref scalar }) => { + &mpi::SecretKeyMaterial::ECDSA { ref scalar }) => { let secret = match curve { Curve::NistP256 => ecc::Scalar::new::<ecc::Secp256r1>( @@ -203,7 +203,7 @@ impl Signer for KeyPair { let sig = ecdsa::sign(&secret, digest, &mut rng); - Ok(mpis::Signature::ECDSA { + Ok(mpi::Signature::ECDSA { r: MPI::new(&sig.r()), s: MPI::new(&sig.s()), }) @@ -223,19 +223,19 @@ impl Decryptor for KeyPair { } /// Creates a signature over the `digest` produced by `hash_algo`. - fn decrypt(&mut self, ciphertext: &mpis::Ciphertext, + fn decrypt(&mut self, ciphertext: &mpi::Ciphertext, plaintext_len: Option<usize>) -> Result<SessionKey> { use crate::PublicKeyAlgorithm::*; - use crate::crypto::mpis::PublicKey; + use crate::crypto::mpi::PublicKey; self.secret.map( |secret| Ok(match (self.public.mpis(), secret, ciphertext) { (PublicKey::RSA{ ref e, ref n }, - mpis::SecretKeyMaterial::RSA{ ref p, ref q, ref d, .. }, - mpis::Ciphertext::RSA{ ref c }) => { + mpi::SecretKeyMaterial::RSA{ ref p, ref q, ref d, .. }, + mpi::Ciphertext::RSA{ ref c }) => { // Workaround for #440: Make sure c is of the same // length as n. // XXX: Remove once we depend on nettle > 7.0.0. @@ -272,14 +272,14 @@ impl Decryptor for KeyPair { } (PublicKey::ElGamal{ .. }, - mpis::SecretKeyMaterial::ElGamal{ .. }, - mpis::Ciphertext::ElGamal{ .. }) => + mpi::SecretKeyMaterial::ElGamal{ .. }, + mpi::Ciphertext::ElGamal{ .. }) => return Err( Error::UnsupportedPublicKeyAlgorithm(ElGamalEncrypt).into()), (PublicKey::ECDH{ .. }, - mpis::SecretKeyMaterial::ECDH { .. }, - mpis::Ciphertext::ECDH { .. }) => + mpi::SecretKeyMaterial::ECDH { .. }, + mpi::Ciphertext::ECDH { .. }) => crate::crypto::ecdh::decrypt(&self.public, secret, ciphertext)?, (public, secret, ciphertext) => @@ -300,7 +300,7 @@ impl From<KeyPair> for Key<key::SecretParts, key::UnspecifiedRole> { impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { /// Encrypts the given data with this key. - pub fn encrypt(&self, data: &SessionKey) -> Result<mpis::Ciphertext> { + pub fn encrypt(&self, data: &SessionKey) -> Result<mpi::Ciphertext> { use crate::PublicKeyAlgorithm::*; #[allow(deprecated)] @@ -308,14 +308,14 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { RSAEncryptSign | RSAEncrypt => { // Extract the public recipient. match self.mpis() { - mpis::PublicKey::RSA { e, n } => { + mpi::PublicKey::RSA { e, n } => { // The ciphertext has the length of the modulus. let mut esk = vec![0u8; n.value().len()]; let mut rng = Yarrow::default(); let pk = rsa::PublicKey::new(n.value(), e.value())?; rsa::encrypt_pkcs1(&pk, &mut rng, data, &mut esk)?; - Ok(mpis::Ciphertext::RSA { + Ok(mpi::Ciphertext::RSA { c: MPI::new(&esk), }) }, @@ -327,7 +327,7 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { }, } }, - ECDH => crate::crypto::ecdh::encrypt(self.mark_parts_public_ref(), + ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(), data), algo => Err(Error::UnsupportedPublicKeyAlgorithm(algo).into()), } @@ -337,7 +337,7 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { pub fn verify(&self, sig: &packet::Signature, digest: &[u8]) -> Result<()> { use crate::PublicKeyAlgorithm::*; - use crate::crypto::mpis::{PublicKey, Signature}; + use crate::crypto::mpi::{PublicKey, Signature}; #[allow(deprecated)] let ok = match (sig.pk_algo(), self.mpis(), sig.mpis()) { diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs index b191d556..e95ecd58 100644 --- a/openpgp/src/crypto/ecdh.rs +++ b/openpgp/src/crypto/ecdh.rs @@ -19,7 +19,7 @@ use crate::utils::{ }; use crate::crypto::SessionKey; use crate::crypto::mem::Protected; -use crate::crypto::mpis::{MPI, PublicKey, SecretKeyMaterial, Ciphertext}; +use crate::crypto::mpi::{MPI, PublicKey, SecretKeyMaterial, Ciphertext}; use nettle::{cipher, curve25519, mode, mode::Mode, ecc, ecdh, random::Yarrow}; /// Wraps a session key using Elliptic Curve Diffie-Hellman. @@ -343,7 +343,7 @@ fn make_param<P, R>(recipient: &Key<P, R>, + 1 // Public key algorithm ID, + 4 // KDF parameters, + 20 // "Anonymous Sender ", - + fp.as_slice().len()); // Recipients key fingerprint. + + fp.as_bytes().len()); // Recipients key fingerprint. param.push(curve.oid().len() as u8); param.extend_from_slice(curve.oid()); @@ -353,13 +353,13 @@ fn make_param<P, R>(recipient: &Key<P, R>, param.push((*hash).into()); param.push((*sym).into()); param.extend_from_slice(b"Anonymous Sender "); - param.extend_from_slice(fp.as_slice()); + param.extend_from_slice(fp.as_bytes()); assert_eq!(param.len(), 1 + curve.oid().len() // Length and Curve OID, + 1 // Public key algorithm ID, + 4 // KDF parameters, + 20 // "Anonymous Sender ", - + fp.as_slice().len()); // Recipients key fingerprint. + + fp.as_bytes().len()); // Recipients key fingerprint. param } @@ -581,9 +581,9 @@ pub fn aes_key_unwrap(algo: SymmetricAlgorithm, key: &Protected, let mut iv: Protected = vec![0; cipher.block_size()].into(); // For j = 5 to 0 - for j in (0..6_usize).into_iter().map(|x| 5 - x) { + for j in (0..=5).rev() { // For i = n to 1 - for i in (0..n).into_iter().map(|x| n - 1 - x) { + for i in (0..=n-1).rev() { // B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i write_be_u64(&mut tmp[..8], a ^ ((n * j) + i + 1) as u64); &mut tmp[8..].copy_from_slice(&r[8 * i..8 * (i + 1)]); diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs index 87d89b34..6fe9146c 100644 --- a/openpgp/src/crypto/hash.rs +++ b/openpgp/src/crypto/hash.rs @@ -22,6 +22,30 @@ use std::io::{self, Write}; const DUMP_HASHED_VALUES: Option<&str> = None; /// State of a hash function. +/// +/// This provides an abstract interface to the hash functions used in +/// OpenPGP. +/// +/// ```rust +/// # f().unwrap(); fn f() -> sequoia_openpgp::Result<()> { +/// use sequoia_openpgp::types::HashAlgorithm; +/// +/// // Create a context and feed data to it. +/// let mut ctx = HashAlgorithm::SHA512.context()?; +/// ctx.update(&b"The quick brown fox jumps over the lazy dog."[..]); +/// +/// // Extract the digest. +/// let mut digest = vec![0; ctx.digest_size()]; +/// ctx.digest(&mut digest); +/// +/// use sequoia_openpgp::fmt::hex; +/// assert_eq!(&hex::encode(digest), +/// "91EA1245F20D46AE9A037A989F54F1F7\ +/// 90F0A47607EEB8A14D12890CEA77A1BB\ +/// C6C7ED9CF205E67B7F2B8FD4C7DFD3A7\ +/// A8617E45F3C463D481C7E586C39AC1ED"); +/// # Ok(()) } +/// ``` #[derive(Clone)] pub struct Context { algo: HashAlgorithm, @@ -84,7 +108,7 @@ impl HashAlgorithm { } } - /// Creates a new Nettle hash context for this algorithm. + /// Creates a new hash context for this algorithm. /// /// # Errors /// @@ -114,16 +138,14 @@ impl HashAlgorithm { HashAlgorithm::__Nonexhaustive => unreachable!(), }; - if let Some(prefix) = DUMP_HASHED_VALUES { - c.map(|c: Box<dyn nettle::hash::Hash>| { - Context { - algo: self, - ctx: Box::new(HashDumper::new(c, prefix)), - } - }) - } else { - c.map(|c| Context { algo: self, ctx: c }) - } + c.map(|ctx| Context { + algo: self, + ctx: if let Some(prefix) = DUMP_HASHED_VALUES { + Box::new(HashDumper::new(ctx, prefix)) + } else { + ctx + }, + }) } /// Returns the ASN.1 OID of this hash algorithm. @@ -167,9 +189,9 @@ impl HashDumper { }; eprintln!("HashDumper: Writing to {}...", &filename); HashDumper { - h: h, - sink: sink, - filename: filename, + h, + sink, + filename, written: 0, } } @@ -208,16 +230,13 @@ pub trait Hash { impl Hash for UserID { /// Update the Hash with a hash of the user id. fn hash(&self, hash: &mut Context) { - let mut header = [0; 5]; + let len = self.value().len() as u32; + let mut header = [0; 5]; header[0] = 0xB4; - let len = self.value().len() as u32; - header[1] = (len >> 24) as u8; - header[2] = (len >> 16) as u8; - header[3] = (len >> 8) as u8; - header[4] = (len) as u8; + header[1..5].copy_from_slice(&len.to_be_bytes()); - hash.update(&header[..]); + hash.update(header); hash.update(self.value()); } } @@ -225,16 +244,13 @@ impl Hash for UserID { impl Hash for UserAttribute { /// Update the Hash with a hash of the user attribute. fn hash(&self, hash: &mut Context) { - let mut header = [0; 5]; + let len = self.value().len() as u32; + let mut header = [0; 5]; header[0] = 0xD1; - let len = self.value().len() as u32; - header[1] = (len >> 24) as u8; - header[2] = (len >> 16) as u8; - header[3] = (len >> 8) as u8; - header[4] = (len) as u8; + header[1..5].copy_from_slice(&len.to_be_bytes()); - hash.update(&header[..]); + hash.update(&header); hash.update(self.value()); } } @@ -247,18 +263,17 @@ impl<P, R> Hash for Key4<P, R> fn hash(&self, hash: &mut Context) { use crate::serialize::MarshalInto; - // We hash 8 bytes plus the MPIs. But, the len doesn't + // We hash 9 bytes plus the MPIs. But, the len doesn't // include the tag (1 byte) or the length (2 bytes). - let len = (9 - 3) + self.mpis().serialized_len(); + let len = (9 - 3) + self.mpis().serialized_len() as u16; - let mut header : Vec<u8> = Vec::with_capacity(9); + let mut header: Vec<u8> = Vec::with_capacity(9); // Tag. Note: we use this whether header.push(0x99); - // Length (big endian). - header.push(((len >> 8) & 0xFF) as u8); - header.push((len & 0xFF) as u8); + // Length (2 bytes, big endian). + header.extend_from_slice(&len.to_be_bytes()); // Version. header.push(4); @@ -266,12 +281,9 @@ impl<P, R> Hash for Key4<P, R> // Creation time. let creation_time: u32 = Timestamp::try_from(self.creation_time()) - .unwrap_or_else(|_| Timestamp::try_from(0).unwrap()) + .unwrap_or_else(|_| Timestamp::from(0)) .into(); - header.push((creation_time >> 24) as u8); - header.push((creation_time >> 16) as u8); - header.push((creation_time >> 8) as u8); - header.push((creation_time >> 0) as u8); + header.extend_from_slice(&creation_time.to_be_bytes()); // Algorithm. header.push(self.pk_algo().into()); @@ -300,7 +312,7 @@ impl Hash for Signature4 { } } -impl Hash for signature::Builder { +impl Hash for signature::SignatureBuilder { /// Adds the `Signature` to the provided hash context. fn hash(&self, hash: &mut Context) { use crate::serialize::MarshalInto; @@ -328,10 +340,9 @@ impl Hash for signature::Builder { header[2] = self.pk_algo().into(); header[3] = self.hash_algo().into(); - // The length of the hashed area, as a 16-bit endian number. - let len = hashed_area.len(); - header[4] = (len >> 8) as u8; - header[5] = len as u8; + // The length of the hashed area, as a 16-bit big endian number. + let len = hashed_area.len() as u16; + header[4..6].copy_from_slice(&len.to_be_bytes()); hash.update(&header[..]); hash.update(&hashed_area); @@ -349,15 +360,12 @@ impl Hash for signature::Builder { // See https://tools.ietf.org/html/rfc4880#section-5.2.4 let mut trailer = [0u8; 6]; - trailer[0] = 0x4; + trailer[0] = 4; trailer[1] = 0xff; // The signature packet's length, not including the previous // two bytes and the length. - let len = header.len() + hashed_area.len(); - trailer[2] = (len >> 24) as u8; - trailer[3] = (len >> 16) as u8; - trailer[4] = (len >> 8) as u8; - trailer[5] = len as u8; + let len = (header.len() + hashed_area.len()) as u32; + trailer[2..6].copy_from_slice(&len.to_be_bytes()); hash.update(&trailer[..]); } @@ -367,7 +375,7 @@ impl Hash for signature::Builder { impl Signature { /// Computes the message digest of standalone signatures. pub fn hash_standalone<'a, S>(sig: S) -> Result<Vec<u8>> - where S: Into<&'a signature::Builder> + where S: Into<&'a signature::SignatureBuilder> { let sig = sig.into(); let mut h = sig.hash_algo().context()?; @@ -381,7 +389,7 @@ impl Signature { /// Computes the message digest of timestamp signatures. pub fn hash_timestamp<'a, S>(sig: S) -> Result<Vec<u8>> - where S: Into<&'a signature::Builder> + where S: Into<&'a signature::SignatureBuilder> { Self::hash_standalone(sig) } @@ -391,7 +399,7 @@ impl Signature { pub fn hash_direct_key<'a, P, S>(sig: S, key: &Key<P, key::PrimaryRole>) -> Result<Vec<u8>> where P: key::KeyParts, - S: Into<&'a signature::Builder>, + S: Into<&'a signature::SignatureBuilder>, { let sig = sig.into(); @@ -414,7 +422,7 @@ impl Signature { -> Result<Vec<u8>> where P: key::KeyParts, Q: key::KeyParts, - S: Into<&'a signature::Builder> + S: Into<&'a signature::SignatureBuilder> { let sig = sig.into(); @@ -438,7 +446,7 @@ impl Signature { -> Result<Vec<u8>> where P: key::KeyParts, Q: key::KeyParts, - S: Into<&'a signature::Builder> + S: Into<&'a signature::SignatureBuilder> { Self::hash_subkey_binding(sig.into(), key, subkey) } @@ -450,7 +458,7 @@ impl Signature { userid: &UserID) -> Result<Vec<u8>> where P: key::KeyParts, - S: Into<&'a signature::Builder> + S: Into<&'a signature::SignatureBuilder> { let sig = sig.into(); let mut h = sig.hash_algo().context()?; @@ -472,7 +480,7 @@ impl Signature { ua: &UserAttribute) -> Result<Vec<u8>> where P: key::KeyParts, - S: Into<&'a signature::Builder>, + S: Into<&'a signature::SignatureBuilder>, { let sig = sig.into(); diff --git a/openpgp/src/crypto/keygrip.rs b/openpgp/src/crypto/keygrip.rs index 32c58e84..68401e53 100644 --- a/openpgp/src/crypto/keygrip.rs +++ b/openpgp/src/crypto/keygrip.rs @@ -3,7 +3,7 @@ use std::fmt; use crate::Error; use crate::Result; use crate::types::{Curve, HashAlgorithm}; -use crate::crypto::mpis::{MPI, PublicKey}; +use crate::crypto::mpi::{MPI, PublicKey}; /// A proprietary, protocol agnostic identifier for public keys. /// @@ -33,22 +33,15 @@ impl std::str::FromStr for Keygrip { type Err = anyhow::Error; fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { - Self::from_hex(s) - } -} - -impl Keygrip { - /// Parses a keygrip. - pub fn from_hex(hex: &str) -> Result<Self> { - let bytes = crate::fmt::from_hex(hex, true)?; - if bytes.len() != 20 { - return Err(Error::InvalidArgument( - format!("Expected 20 bytes, got {}", bytes.len())).into()); + let bytes = crate::fmt::hex::decode_pretty(s)?; + if bytes.len() == 20 { + let mut digest = [0; 20]; + &mut digest[..].copy_from_slice(&bytes[..]); + Ok(Keygrip(digest)) + } else { + Err(Error::InvalidArgument( + format!("Expected 20 bytes, got {}", bytes.len())).into()) } - - let mut digest = [0; 20]; - &mut digest[..].copy_from_slice(&bytes[..]); - Ok(Keygrip(digest)) } } @@ -301,46 +294,46 @@ mod tests { let keygrips: HashMap<FP, KG> = [ // testy.pgp - (FP::from_hex("3E8877C877274692975189F5D03F6F865226FE8B").unwrap(), - KG::from_hex("71ADDE3BBC0B7F1BFC2DA414C4F473B197763733").unwrap()), - (FP::from_hex("01F187575BD45644046564C149E2118166C92632").unwrap(), - KG::from_hex("CB6149C50DF90DC88626283A6B6C918A1C29E37D").unwrap()), + ("3E8877C877274692975189F5D03F6F865226FE8B".parse::<FP>().unwrap(), + "71ADDE3BBC0B7F1BFC2DA414C4F473B197763733".parse::<KG>().unwrap()), + ("01F187575BD45644046564C149E2118166C92632".parse::<FP>().unwrap(), + "CB6149C50DF90DC88626283A6B6C918A1C29E37D".parse::<KG>().unwrap()), // neal.pgp - (FP::from_hex("8F17777118A33DDA9BA48E62AACB3243630052D9").unwrap(), - KG::from_hex("C45986381F54F967C2F6B104521C8634090F326A").unwrap()), - (FP::from_hex("C03FA6411B03AE12576461187223B56678E02528").unwrap(), - KG::from_hex("BE2FE8C8793141322AC30E3EAFD1E4F9D8DACCC4").unwrap()), - (FP::from_hex("50E6D924308DBF223CFB510AC2B819056C652598").unwrap(), - KG::from_hex("9873FD355DE470DDC151CD9919AC9785C3C2FDDE").unwrap()), - (FP::from_hex("2DC50AB55BE2F3B04C2D2CF8A3506AFB820ABD08").unwrap(), - KG::from_hex("9483454871CC1239D4C2A1416F2742D39A14DB14").unwrap()), + ("8F17777118A33DDA9BA48E62AACB3243630052D9".parse::<FP>().unwrap(), + "C45986381F54F967C2F6B104521C8634090F326A".parse::<KG>().unwrap()), + ("C03FA6411B03AE12576461187223B56678E02528".parse::<FP>().unwrap(), + "BE2FE8C8793141322AC30E3EAFD1E4F9D8DACCC4".parse::<KG>().unwrap()), + ("50E6D924308DBF223CFB510AC2B819056C652598".parse::<FP>().unwrap(), + "9873FD355DE470DDC151CD9919AC9785C3C2FDDE".parse::<KG>().unwrap()), + ("2DC50AB55BE2F3B04C2D2CF8A3506AFB820ABD08".parse::<FP>().unwrap(), + "9483454871CC1239D4C2A1416F2742D39A14DB14".parse::<KG>().unwrap()), // dennis-simon-anton.pgp - (FP::from_hex("5BFBCD2A23E6866B77198C1147606B18E3D45CE9").unwrap(), - KG::from_hex("D3E87BECEF18FB4C56 |