diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-09-29 10:19:46 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-09-29 11:05:54 +0200 |
commit | 6878e532fcfc44332b1635c79cee3590fe356c65 (patch) | |
tree | 38abb76cffa7f1d3de83d5356d8915c7e8e724e3 /openpgp/src/crypto/backend/cng | |
parent | 705e9a591e000d13aceb7449dc58d5b577a6323d (diff) |
openpgp: Use new padding methods in the CNG backend.
- This makes the code more succinct and also more robust (consider
for example that `field_sz - r.value().len()` may underflow.
Diffstat (limited to 'openpgp/src/crypto/backend/cng')
-rw-r--r-- | openpgp/src/crypto/backend/cng/asymmetric.rs | 58 |
1 files changed, 23 insertions, 35 deletions
diff --git a/openpgp/src/crypto/backend/cng/asymmetric.rs b/openpgp/src/crypto/backend/cng/asymmetric.rs index f05291c9..b43324c3 100644 --- a/openpgp/src/crypto/backend/cng/asymmetric.rs +++ b/openpgp/src/crypto/backend/cng/asymmetric.rs @@ -10,6 +10,7 @@ use crate::crypto::asymmetric::{Decryptor, KeyPair, Signer}; use crate::crypto::mem::Protected; use crate::crypto::mpi; 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}; @@ -265,19 +266,10 @@ impl Signer for KeyPair { // digest or pad it with zeroes (since it's treated as a // big-endian number). // See https://github.com/dotnet/runtime/blob/67d74fca70d4670ad503e23dba9d6bc8a1b5909e/src/libraries/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs#L148. - let mut _digest = vec![]; - let digest = match std::cmp::Ord::cmp(&q.value().len(), &digest.len()) { - std::cmp::Ordering::Equal => digest, - std::cmp::Ordering::Less => &digest[..q.value().len()], - std::cmp::Ordering::Greater => { - let pad = vec![0; q.value().len() - digest.len()]; - _digest = [pad.as_ref(), digest].concat(); - &_digest - } - }; + let digest = pad_truncating(&digest, q.value().len()); assert_eq!(q.value().len(), digest.len()); - let sig = pair.sign(digest, None)?; + let sig = pair.sign(&digest, None)?; // https://tools.ietf.org/html/rfc8032#section-5.1.6 let (r, s) = sig.split_at(sig.len() / 2); @@ -430,32 +422,18 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { (mpi::PublicKey::RSA { e, n }, mpi::Signature::RSA { s }) => { // CNG accepts only full-size signatures. Since for RSA it's a // big-endian number, just left-pad with zeroes as necessary. - let sig_diff = n.value().len().saturating_sub(s.value().len()); - let mut _s: Vec<u8> = vec![]; - let s = if sig_diff > 0 { - _s = [&vec![0u8; sig_diff], s.value()].concat(); - &_s - } else { - s.value() - }; + let s = pad(s.value(), n.value().len()).map_err(bad)?; // CNG supports RSA keys that are at least 512 bit long. // Since it just checks the MPI length rather than data itself, // just pad it with zeroes as necessary. - let mut _n: Vec<u8> = vec![]; - let missing_size = 512usize.saturating_sub(n.value().len()); - let n = if missing_size > 0 { - _n = [&vec![0u8; missing_size], n.value()].concat(); - &_n - } else { - n.value() - }; + let n = pad_at_least(n.value(), 512); let provider = AsymmetricAlgorithm::open(AsymmetricAlgorithmId::Rsa)?; let key = AsymmetricKey::<Rsa, Public>::import_from_parts( &provider, &RsaKeyPublicPayload { - modulus: n, + modulus: &n, pub_exp: e.value(), } )?; @@ -469,7 +447,7 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { let hash = hash_algo.try_into()?; let padding = SignaturePadding::pkcs1(hash); - key.verify(digest, s, Some(padding)).map(|_| true)? + key.verify(digest, &s, Some(padding)).map(|_| true)? }, (mpi::PublicKey::DSA { y, p, q, g }, mpi::Signature::DSA { r, s }) => { use win_crypto_ng::key_blob::{DsaKeyPublicPayload, DsaKeyPublicBlob}; @@ -485,9 +463,14 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { // CNG expects full-sized signatures let field_sz = q.value().len(); - let r = [&vec![0u8; field_sz - r.value().len()], r.value()].concat(); - let s = [&vec![0u8; field_sz - s.value().len()], s.value()].concat(); - let signature = [r, s].concat(); + let mut signature = vec![0u8; 2 * field_sz]; + + // We need to zero-pad them at the front, because + // the MPI encoding drops leading zero bytes. + signature[..field_sz].copy_from_slice( + &r.value_padded(field_sz).map_err(bad)?); + signature[field_sz..].copy_from_slice( + &s.value_padded(field_sz).map_err(bad)?); enum Version { V1, V2 } // 1024-bit DSA keys are handled differently @@ -589,9 +572,14 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> { let (x, y) = q.decode_point(curve)?; // CNG expects full-sized signatures let field_sz = x.len(); - let r = [&vec![0u8; field_sz - r.value().len()], r.value()].concat(); - let s = [&vec![0u8; field_sz - s.value().len()], s.value()].concat(); - let signature = [r, s].concat(); + let mut signature = vec![0u8; 2 * field_sz]; + + // We need to zero-pad them at the front, because + // the MPI encoding drops leading zero bytes. + signature[..field_sz].copy_from_slice( + &r.value_padded(field_sz).map_err(bad)?); + signature[field_sz..].copy_from_slice( + &s.value_padded(field_sz).map_err(bad)?); use cng::key_blob::EccKeyPublicPayload; use cng::asymmetric::{ecc::{NistP256, NistP384, NistP521}, Ecdsa}; |