Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 39 additions & 25 deletions dsa/src/generate/secret_number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
use crate::{Components, signing_key::SigningKey};
use alloc::vec;
use core::cmp::min;
use crypto_bigint::{BoxedUint, NonZero, RandomBits, Resize};
use crypto_bigint::{BoxedUint, NonZero, NonZeroBoxedUint, RandomBits, Resize};
use digest::{Digest, common::BlockSizeUser};
use rfc6979::KGenerator;
use signature::rand_core::TryCryptoRng;
use zeroize::Zeroizing;

fn truncate_hash(hash: &[u8], desired_size: usize) -> &[u8] {
&hash[(hash.len() - desired_size)..]
}

/// Generate a per-message secret number k deterministically using the method described in RFC 6979
///
/// # Returns
Expand All @@ -23,39 +20,56 @@ fn truncate_hash(hash: &[u8], desired_size: usize) -> &[u8] {
pub(crate) fn secret_number_rfc6979<D>(
signing_key: &SigningKey,
hash: &[u8],
) -> Result<(BoxedUint, BoxedUint), signature::Error>
) -> (BoxedUint, BoxedUint)
where
D: BlockSizeUser + Digest,
{
let q = signing_key.verifying_key().components().q();
let size = (q.bits() / 8) as usize;

// Truncate hash and reduce mod q
// TODO(tarcieri): `rfc6979` now truncates and reduces mod q. some of this may be redundant?
let hash = BoxedUint::from_be_slice(&hash[..min(size, hash.len())], q.bits_precision())
.map_err(|_| signature::Error::new())?;
let hash = (hash % q).to_be_bytes();
let hash = truncate_hash(&hash, size);

let x_bytes = Zeroizing::new(signing_key.x().to_be_bytes());
let x_bytes = truncate_hash(&x_bytes, size);
let mut kgen = init_kgen::<D>(signing_key.x(), hash, q);
let mut buffer = vec![0; qlen(q)];

let mut kgen = rfc6979::KGenerator::<D, BoxedUint>::new(x_bytes, hash, &[], q);

let mut buffer = vec![0; size];
loop {
kgen.fill_next_k(&mut buffer);

let k = BoxedUint::from_be_slice(&buffer, q.bits_precision())
.map_err(|_| signature::Error::new())?;
let k = bytes2uint(&buffer, q);
if let Some(inv_k) = k.invert_mod(q).into() {
if (bool::from(k.is_nonzero())) && (k < **q) {
return Ok((k, inv_k));
if bool::from(k.is_nonzero()) && k < **q {
return (k, inv_k);
}
}
}
}

/// Initialize `KGenerator` from a `hash`, `q`, and the
fn init_kgen<'a, D: BlockSizeUser + Digest>(
x: &NonZeroBoxedUint,
z: &[u8],
q: &'a NonZeroBoxedUint,
) -> KGenerator<'a, D, BoxedUint> {
// Truncate to the right `size` most bytes
fn truncate(b: &[u8], size: usize) -> &[u8] {
&b[(b.len() - size)..]
}

// Truncate hash and reduce mod q
let size = qlen(q);
let z = bytes2uint(&z[..min(size, z.len())], q);
let z = (z % q).to_be_bytes();
let z = truncate(&z, size);

let x = Zeroizing::new(x.to_be_bytes());
let x = truncate(&x, size);

rfc6979::KGenerator::<D, BoxedUint>::new(x, z, &[], q)
}

fn bytes2uint(b: &[u8], q: &NonZeroBoxedUint) -> BoxedUint {
BoxedUint::from_be_slice_truncated(b, q.bits_precision())
}

fn qlen(q: &NonZeroBoxedUint) -> usize {
q.bits().div_ceil(8) as usize
}

/// Generate a per-message secret number k according to Appendix B.2.1
///
/// # Returns
Expand Down
16 changes: 8 additions & 8 deletions dsa/src/signing_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#![cfg(feature = "hazmat")]

use crate::{Components, Signature, VerifyingKey};
use crate::{Components, Signature, VerifyingKey, generate};
use core::{
cmp::min,
fmt::{self, Debug},
Expand Down Expand Up @@ -73,7 +73,7 @@ impl SigningKey {
rng: &mut R,
components: Components,
) -> Result<Self, R::Error> {
crate::generate::signing_keypair(rng, components)
generate::signing_keypair(rng, components)
}

/// DSA public key
Expand All @@ -98,7 +98,7 @@ impl SigningKey {
where
D: BlockSizeUser + Digest,
{
let k_kinv = crate::generate::secret_number_rfc6979::<D>(self, prehash)?;
let k_kinv = generate::secret_number_rfc6979::<D>(self, prehash);
self.sign_prehashed(k_kinv, prehash)
}

Expand Down Expand Up @@ -179,7 +179,7 @@ impl MultipartSigner<Signature> for SigningKey {
impl PrehashSigner<Signature> for SigningKey {
/// Warning: This uses `sha2::Sha256` as the hash function for the digest. If you need to use a different one, use [`SigningKey::sign_prehashed_rfc6979`].
fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature, signature::Error> {
let k_kinv = crate::generate::secret_number_rfc6979::<sha2::Sha256>(self, prehash)?;
let k_kinv = generate::secret_number_rfc6979::<sha2::Sha256>(self, prehash);
self.sign_prehashed(k_kinv, prehash)
}
}
Expand All @@ -192,7 +192,7 @@ impl RandomizedPrehashSigner<Signature> for SigningKey {
) -> Result<Signature, signature::Error> {
let components = self.verifying_key.components();

if let Some(k_kinv) = crate::generate::secret_number(rng, components)? {
if let Some(k_kinv) = generate::secret_number(rng, components)? {
self.sign_prehashed(k_kinv, prehash)
} else {
Err(signature::Error::new())
Expand All @@ -211,7 +211,7 @@ where
let mut digest = D::new();
f(&mut digest)?;
let hash = digest.finalize();
let ks = crate::generate::secret_number_rfc6979::<D>(self, &hash)?;
let ks = generate::secret_number_rfc6979::<D>(self, &hash);

self.sign_prehashed(ks, &hash)
}
Expand All @@ -229,7 +229,7 @@ where
rng: &mut R,
f: F,
) -> Result<Signature, signature::Error> {
let ks = crate::generate::secret_number(rng, self.verifying_key().components())?
let ks = generate::secret_number(rng, self.verifying_key().components())?
.ok_or_else(signature::Error::new)?;
let mut digest = D::new();
f(&mut digest)?;
Expand Down Expand Up @@ -290,7 +290,7 @@ impl<'a> TryFrom<PrivateKeyInfoRef<'a>> for SigningKey {
BoxedUint::from_be_slice(y.as_bytes(), precision)
.map_err(|_| pkcs8::KeyError::Invalid)?
} else {
crate::generate::public_component(&components, &x)
generate::public_component(&components, &x)
.into_option()
.ok_or(pkcs8::KeyError::Invalid)?
.get()
Expand Down
Loading