Skip to content
Closed
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
43 changes: 43 additions & 0 deletions src/algorithms/pad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,29 @@ pub(crate) fn uint_to_zeroizing_be_pad(input: BoxedUint, padded_len: usize) -> Z
out
}

/// Encode a private RSA representative using the modulus width in octets.
///
/// The caller has established that `input` fits in `k` octets. Offsets depend only on the public
/// storage and modulus widths, not on `input`'s value.
///
/// From draft-irtf-cfrg-rsa-guidance-10 §7.2:
/// > I2OSP MUST be constant-time with respect of m.
#[inline]
pub(crate) fn i2osp_modulus_width(input: BoxedUint, k: usize) -> Zeroizing<Vec<u8>> {
debug_assert!(k >= 11);

let input = Zeroizing::new(input);
let bytes = Zeroizing::new(input.to_be_bytes());
let copy_len = bytes.len().min(k);
let mut out = Zeroizing::new(vec![0u8; k]);
out[k - copy_len..].copy_from_slice(&bytes[bytes.len() - copy_len..]);
out
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn be_pad() {
let x = BoxedUint::from(0x0102u64);
Expand All @@ -75,4 +95,27 @@ mod tests {
fn be_pad_rejects_broken_precondition() {
uint_to_zeroizing_be_pad(BoxedUint::from(0x0102u64), 1);
}

#[test]
fn i2osp_modulus_width_uses_octet_width_not_storage_precision() {
// From draft-irtf-cfrg-rsa-guidance-10 §7.2:
// > EM = I2OSP (m, k).
//
// A 2049-bit modulus has `k = 257`, even when BoxedUint stores more bytes.
let k = 257;
let mut expected = vec![0u8; k];
expected[k - 2..].copy_from_slice(&[0x12, 0x34]);

for bits_precision in [2048, 2049] {
let m = BoxedUint::from_be_slice(&[0x12, 0x34], bits_precision).unwrap();
let em = i2osp_modulus_width(m, k);
assert_eq!(em.as_slice(), expected.as_slice());
}

// The most significant octet of a 2049-bit value must also be retained.
expected[0] = 1;
let m = BoxedUint::from_be_slice(&expected, 2049).unwrap();
let em = i2osp_modulus_width(m, k);
assert_eq!(em.as_slice(), expected.as_slice());
}
}
Loading