Skip to content

Commit 47329ec

Browse files
committed
Uncap HKDF salt length restriction
1 parent be28b72 commit 47329ec

File tree

1 file changed

+48
-29
lines changed

1 file changed

+48
-29
lines changed

aws-lc-rs/src/hkdf.rs

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,6 @@ pub const HKDF_SHA384: Algorithm = Algorithm(hmac::HMAC_SHA384);
7070
/// HKDF using HMAC-SHA-512.
7171
pub const HKDF_SHA512: Algorithm = Algorithm(hmac::HMAC_SHA512);
7272

73-
/// General Salt length's for HKDF don't normally exceed 256 bits.
74-
/// We set the limit to something tolerable, so that the Salt structure can be stack allocatable.
75-
const MAX_HKDF_SALT_LEN: usize = 80;
7673

7774
/// General Info length's for HKDF don't normally exceed 256 bits.
7875
/// We set the default capacity to a value larger than should be needed
@@ -92,8 +89,7 @@ impl KeyType for Algorithm {
9289
/// A salt for HKDF operations.
9390
pub struct Salt {
9491
algorithm: Algorithm,
95-
bytes: [u8; MAX_HKDF_SALT_LEN],
96-
len: usize,
92+
bytes: Box<[u8]>,
9793
}
9894

9995
#[allow(clippy::missing_fields_in_debug)]
@@ -107,6 +103,7 @@ impl fmt::Debug for Salt {
107103

108104
impl Drop for Salt {
109105
fn drop(&mut self) {
106+
// Box<[u8]> implements Zeroize, so we can call it directly
110107
self.bytes.zeroize();
111108
}
112109
}
@@ -128,23 +125,18 @@ impl Salt {
128125
// * `value.len() > 0` is true
129126
//
130127
/// # Panics
131-
/// `new` panics if the salt length exceeds the limit
128+
/// `new` panics if salt creation fails
132129
#[must_use]
133130
pub fn new(algorithm: Algorithm, value: &[u8]) -> Self {
134-
Salt::try_new(algorithm, value).expect("Salt length limit exceeded.")
131+
Salt::try_new(algorithm, value).expect("Failed to create Salt")
135132
}
136133

137134
fn try_new(algorithm: Algorithm, value: &[u8]) -> Result<Salt, Unspecified> {
138-
let salt_len = value.len();
139-
if salt_len > MAX_HKDF_SALT_LEN {
140-
return Err(Unspecified);
141-
}
142-
let mut salt_bytes = [0u8; MAX_HKDF_SALT_LEN];
143-
salt_bytes[0..salt_len].copy_from_slice(value);
135+
// No length restriction anymore - convert slice to boxed slice
136+
let bytes = value.to_vec().into_boxed_slice();
144137
Ok(Self {
145138
algorithm,
146-
bytes: salt_bytes,
147-
len: salt_len,
139+
bytes,
148140
})
149141
}
150142

@@ -161,8 +153,7 @@ impl Salt {
161153
algorithm: self.algorithm,
162154
mode: PrkMode::ExtractExpand {
163155
secret: Arc::from(ZeroizeBoxSlice::from(secret)),
164-
salt: self.bytes,
165-
salt_len: self.len,
156+
salt: self.bytes.clone(),
166157
},
167158
}
168159
}
@@ -175,19 +166,16 @@ impl Salt {
175166
}
176167
}
177168

178-
#[allow(clippy::assertions_on_constants)]
179-
const _: () = assert!(MAX_HKDF_PRK_LEN <= MAX_HKDF_SALT_LEN);
180169

181170
impl From<Okm<'_, Algorithm>> for Salt {
182171
fn from(okm: Okm<'_, Algorithm>) -> Self {
183-
let algorithm = okm.prk.algorithm;
184-
let mut salt_bytes = [0u8; MAX_HKDF_SALT_LEN];
172+
let algorithm = okm.len;
185173
let salt_len = okm.len().len();
186-
okm.fill(&mut salt_bytes[..salt_len]).unwrap();
174+
let mut salt_bytes = vec![0u8; salt_len];
175+
okm.fill(&mut salt_bytes).unwrap();
187176
Self {
188177
algorithm,
189-
bytes: salt_bytes,
190-
len: salt_len,
178+
bytes: salt_bytes.into_boxed_slice(),
191179
}
192180
}
193181
}
@@ -207,8 +195,7 @@ enum PrkMode {
207195
},
208196
ExtractExpand {
209197
secret: Arc<ZeroizeBoxSlice<u8>>,
210-
salt: [u8; MAX_HKDF_SALT_LEN],
211-
salt_len: usize,
198+
salt: Box<[u8]>,
212199
},
213200
}
214201

@@ -233,7 +220,6 @@ impl PrkMode {
233220
PrkMode::ExtractExpand {
234221
secret,
235222
salt,
236-
salt_len,
237223
} => {
238224
if 1 != indicator_check!(unsafe {
239225
HKDF(
@@ -243,7 +229,7 @@ impl PrkMode {
243229
secret.as_ptr(),
244230
secret.len(),
245231
salt.as_ptr(),
246-
*salt_len,
232+
salt.len(),
247233
info.as_ptr(),
248234
info.len(),
249235
)
@@ -377,7 +363,7 @@ impl Prk {
377363

378364
impl From<Okm<'_, Algorithm>> for Prk {
379365
fn from(okm: Okm<Algorithm>) -> Self {
380-
let algorithm = okm.len;
366+
let algorithm = okm.prk.algorithm;
381367
let key_len = okm.len.len();
382368
let mut key_bytes = [0u8; MAX_HKDF_PRK_LEN];
383369
okm.fill(&mut key_bytes[0..key_len]).unwrap();
@@ -503,4 +489,37 @@ mod tests {
503489
format!("{okm:?}")
504490
);
505491
}
492+
493+
#[test]
494+
fn test_long_salt() {
495+
// Test with a salt longer than the previous 80-byte limit
496+
let long_salt = vec![0x42u8; 100];
497+
498+
// This should work now that we removed the MAX_HKDF_SALT_LEN restriction
499+
let salt = Salt::new(HKDF_SHA256, &long_salt);
500+
501+
// Test the extract operation still works
502+
let secret = b"test secret key material";
503+
let prk = salt.extract(secret);
504+
505+
// Test expand operation
506+
let info_data = b"test context info";
507+
let info = [info_data.as_slice()];
508+
let okm = prk.expand(&info, HKDF_SHA256).unwrap();
509+
510+
// Fill output buffer
511+
let mut output = [0u8; 32];
512+
okm.fill(&mut output).unwrap();
513+
514+
// Test with an even longer salt to demonstrate flexibility
515+
let very_long_salt = vec![0x55u8; 500];
516+
let very_long_salt_obj = Salt::new(HKDF_SHA256, &very_long_salt);
517+
let prk2 = very_long_salt_obj.extract(secret);
518+
let okm2 = prk2.expand(&info, HKDF_SHA256).unwrap();
519+
let mut output2 = [0u8; 32];
520+
okm2.fill(&mut output2).unwrap();
521+
522+
// Verify outputs are different (they should be due to different salts)
523+
assert_ne!(output, output2);
524+
}
506525
}

0 commit comments

Comments
 (0)