Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
[default.extend-identifiers]
# typ stands for type, but it's a reserved identifier
typ = "typ"

[files]
extend-exclude = [
"/tests/examples/**",
]
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const-oid = { version = "0.10", default-features = false }
crypto-bigint = { version = "0.7", default-features = false, features = ["zeroize", "alloc"] }
crypto-primes = { version = "0.7", default-features = false }
digest = { version = "0.11", default-features = false, features = ["alloc", "oid"] }
hmac = { version = "0.13.0", default-features = false }
rand_core = { version = "0.10", default-features = false }
sha2 = { version = "0.11.0-rc.5", default-features = false, features = ["oid"] }
signature = { version = "3.0.0-rc.10", default-features = false, features = ["alloc", "digest", "rand_core"] }
zeroize = { version = "1.8", features = ["alloc"] }

Expand All @@ -28,7 +30,6 @@ pkcs1 = { version = "0.8.0-rc.4", optional = true, default-features = false, fea
pkcs8 = { version = "0.11.0-rc.10", optional = true, default-features = false, features = ["alloc", "pem"] }
serdect = { version = "0.4", optional = true }
sha1 = { version = "0.11.0-rc.5", optional = true, default-features = false, features = ["oid"] }
sha2 = { version = "0.11.0-rc.5", optional = true, default-features = false, features = ["oid"] }
spki = { version = "0.8.0-rc.4", optional = true, default-features = false, features = ["alloc"] }
serde = { version = "1.0.184", optional = true, default-features = false, features = ["derive"] }

Expand All @@ -40,7 +41,6 @@ serde_test = "1.0.89"
rand = { version = "0.10", features = ["chacha"] }
rand_core = { version = "0.10", default-features = false }
sha1 = { version = "0.11.0-rc.5", default-features = false, features = ["oid"] }
sha2 = { version = "0.11.0-rc.5", default-features = false, features = ["oid"] }
sha3 = { version = "0.11.0-rc.8", default-features = false, features = ["oid"] }
hex = { version = "0.4.3", features = ["serde"] }
serde_json = "1.0.138"
Expand All @@ -51,7 +51,7 @@ rstest = "0.26.1"
name = "key"

[features]
default = ["std", "encoding"]
default = ["std", "encoding", "getrandom"]
encoding = ["dep:pkcs1", "dep:pkcs8", "dep:spki"]
hazmat = []
getrandom = ["crypto-bigint/getrandom", "crypto-common"]
Expand All @@ -60,7 +60,7 @@ pkcs5 = ["pkcs8/encryption"]
std = ["pkcs1?/std", "pkcs8?/std"]

[package.metadata.docs.rs]
features = ["std", "serde", "hazmat", "sha2"]
features = ["std", "serde", "hazmat"]

[profile.dev]
opt-level = 2
Expand Down
102 changes: 75 additions & 27 deletions src/algorithms/pad.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,111 @@
//! Special handling for converting the BigUint to u8 vectors

use alloc::vec::Vec;
use crypto_bigint::BoxedUint;
use crypto_bigint::{ctutils::CtGt, BoxedUint};
use zeroize::Zeroizing;

use crate::errors::{Error, Result};

/// Returns a new vector of the given length, with 0s left padded.
#[inline]
fn left_pad(input: &[u8], padded_len: usize) -> Result<Vec<u8>> {
if input.len() > padded_len {
return Err(Error::InvalidPadLen);
fn left_pad(input: &[u8], padded_len: usize) -> Vec<u8> {
let mut out = vec![0_u8; padded_len];
for (output_byte, data_byte) in out
.iter_mut()
.rev()
.zip(input.iter().rev().chain(core::iter::repeat(&0_u8)))
{
*output_byte |= *data_byte;
}

let mut out = vec![0u8; padded_len];
out[padded_len - input.len()..].copy_from_slice(input);
Ok(out)
out
}

/// Converts input to the new vector of the given length, using BE and with 0s left padded.
/// In some cases BoxedUint might already have leading zeroes, this function removes them
/// before padding again.
#[inline]
pub(crate) fn uint_to_be_pad(input: BoxedUint, padded_len: usize) -> Result<Vec<u8>> {
let leading_zeros = input.leading_zeros() as usize / 8;
left_pad(&input.to_be_bytes()[leading_zeros..], padded_len)
let leading_zeros = input.leading_zeros() as usize >> 3;
let input_be_bytes = input.to_be_bytes();
if ((input_be_bytes.len() - leading_zeros) as u64)
.ct_gt(&(padded_len as u64))
.into()
{
return Err(Error::InvalidPadLen);
}
Ok(left_pad(&input_be_bytes, padded_len))
}

/// Converts input to the new vector of the given length, using BE and with 0s left padded.
/// In some cases BoxedUint might already have leading zeroes, this function removes them
/// before padding again.
#[inline]
pub(crate) fn uint_to_zeroizing_be_pad(input: BoxedUint, padded_len: usize) -> Result<Vec<u8>> {
let leading_zeros = input.leading_zeros() as usize / 8;

let m = Zeroizing::new(input);
let m = Zeroizing::new(m.to_be_bytes());

left_pad(&m[leading_zeros..], padded_len)
let leading_zero_bytes = input.leading_zeros() as usize >> 3;
let input = Zeroizing::new(input);
let input_be_bytes = Zeroizing::new(input.to_be_bytes());
if ((input_be_bytes.len() - leading_zero_bytes) as u64)
.ct_gt(&(padded_len as u64))
.into()
{
return Err(Error::InvalidPadLen);
}
Ok(left_pad(&input_be_bytes, padded_len))
}

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

#[test]
fn test_left_pad() {
const INPUT_LEN: usize = 3;
let input = vec![0u8; INPUT_LEN];
let input = vec![1u8, 2, 3];

// input len < padded len: left padded with leading zeros
let padded = left_pad(&input, input.len() + 1);
assert_eq!(padded, vec![0, 1, 2, 3]);

// input len == padded len: returned unchanged
let padded = left_pad(&input, input.len());
assert_eq!(padded, vec![1, 2, 3]);

// input len > padded len: truncated, keeping the low-order bytes
let padded = left_pad(&input, input.len() - 1);
assert_eq!(padded, vec![2, 3]);
}

#[test]
fn test_uint_to_be_pad() {
let input = BoxedUint::from(0x1234u32);

// padded_len larger than the value: left padded with zeros
let padded = uint_to_be_pad(input.clone(), 4).unwrap();
assert_eq!(padded, vec![0, 0, 0x12, 0x34]);

// padded_len matches the value's byte length
let padded = uint_to_be_pad(input.clone(), 2).unwrap();
assert_eq!(padded, vec![0x12, 0x34]);

// padded_len smaller than the value's byte length: error
assert_eq!(uint_to_be_pad(input, 1), Err(Error::InvalidPadLen));
}

#[test]
fn test_uint_to_zeroizing_be_pad() {
let input = BoxedUint::from(0x1234u32);

// input len < padded len
let padded = left_pad(&input, INPUT_LEN + 1).unwrap();
assert_eq!(padded.len(), INPUT_LEN + 1);
// padded_len larger than the value: left padded with zeros
let padded = uint_to_zeroizing_be_pad(input.clone(), 4).unwrap();
assert_eq!(padded, vec![0, 0, 0x12, 0x34]);

// input len == padded len
let padded = left_pad(&input, INPUT_LEN).unwrap();
assert_eq!(padded.len(), INPUT_LEN);
// padded_len matches the value's byte length
let padded = uint_to_zeroizing_be_pad(input.clone(), 2).unwrap();
assert_eq!(padded, vec![0x12, 0x34]);

// input len > padded len
let padded = left_pad(&input, INPUT_LEN - 1);
assert!(padded.is_err());
// padded_len smaller than the value's byte length: error
assert_eq!(
uint_to_zeroizing_be_pad(input, 1),
Err(Error::InvalidPadLen)
);
}
}
Loading