Skip to content

Commit 3728f18

Browse files
authored
Uncap HKDF salt length restriction (#951)
1 parent be28b72 commit 3728f18

File tree

1 file changed

+45
-39
lines changed

1 file changed

+45
-39
lines changed

aws-lc-rs/src/hkdf.rs

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +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;
76-
7773
/// General Info length's for HKDF don't normally exceed 256 bits.
7874
/// We set the default capacity to a value larger than should be needed
7975
/// so that the value passed to |`HKDF_expand`| is only allocated once.
@@ -92,8 +88,7 @@ impl KeyType for Algorithm {
9288
/// A salt for HKDF operations.
9389
pub struct Salt {
9490
algorithm: Algorithm,
95-
bytes: [u8; MAX_HKDF_SALT_LEN],
96-
len: usize,
91+
bytes: Box<[u8]>,
9792
}
9893

9994
#[allow(clippy::missing_fields_in_debug)]
@@ -107,6 +102,7 @@ impl fmt::Debug for Salt {
107102

108103
impl Drop for Salt {
109104
fn drop(&mut self) {
105+
// Box<[u8]> implements Zeroize, so we can call it directly
110106
self.bytes.zeroize();
111107
}
112108
}
@@ -128,24 +124,11 @@ impl Salt {
128124
// * `value.len() > 0` is true
129125
//
130126
/// # Panics
131-
/// `new` panics if the salt length exceeds the limit
127+
/// `new` panics if salt creation fails
132128
#[must_use]
133129
pub fn new(algorithm: Algorithm, value: &[u8]) -> Self {
134-
Salt::try_new(algorithm, value).expect("Salt length limit exceeded.")
135-
}
136-
137-
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);
144-
Ok(Self {
145-
algorithm,
146-
bytes: salt_bytes,
147-
len: salt_len,
148-
})
130+
let bytes = value.to_vec().into_boxed_slice();
131+
Self { algorithm, bytes }
149132
}
150133

151134
/// The [HKDF-Extract] operation.
@@ -161,8 +144,7 @@ impl Salt {
161144
algorithm: self.algorithm,
162145
mode: PrkMode::ExtractExpand {
163146
secret: Arc::from(ZeroizeBoxSlice::from(secret)),
164-
salt: self.bytes,
165-
salt_len: self.len,
147+
salt: self.bytes.clone(),
166148
},
167149
}
168150
}
@@ -175,19 +157,15 @@ impl Salt {
175157
}
176158
}
177159

178-
#[allow(clippy::assertions_on_constants)]
179-
const _: () = assert!(MAX_HKDF_PRK_LEN <= MAX_HKDF_SALT_LEN);
180-
181160
impl From<Okm<'_, Algorithm>> for Salt {
182161
fn from(okm: Okm<'_, Algorithm>) -> Self {
183162
let algorithm = okm.prk.algorithm;
184-
let mut salt_bytes = [0u8; MAX_HKDF_SALT_LEN];
185163
let salt_len = okm.len().len();
186-
okm.fill(&mut salt_bytes[..salt_len]).unwrap();
164+
let mut salt_bytes = vec![0u8; salt_len];
165+
okm.fill(&mut salt_bytes).unwrap();
187166
Self {
188167
algorithm,
189-
bytes: salt_bytes,
190-
len: salt_len,
168+
bytes: salt_bytes.into_boxed_slice(),
191169
}
192170
}
193171
}
@@ -207,8 +185,7 @@ enum PrkMode {
207185
},
208186
ExtractExpand {
209187
secret: Arc<ZeroizeBoxSlice<u8>>,
210-
salt: [u8; MAX_HKDF_SALT_LEN],
211-
salt_len: usize,
188+
salt: Box<[u8]>,
212189
},
213190
}
214191

@@ -230,11 +207,7 @@ impl PrkMode {
230207
return Err(Unspecified);
231208
}
232209
},
233-
PrkMode::ExtractExpand {
234-
secret,
235-
salt,
236-
salt_len,
237-
} => {
210+
PrkMode::ExtractExpand { secret, salt } => {
238211
if 1 != indicator_check!(unsafe {
239212
HKDF(
240213
out.as_mut_ptr(),
@@ -243,7 +216,7 @@ impl PrkMode {
243216
secret.as_ptr(),
244217
secret.len(),
245218
salt.as_ptr(),
246-
*salt_len,
219+
salt.len(),
247220
info.as_ptr(),
248221
info.len(),
249222
)
@@ -503,4 +476,37 @@ mod tests {
503476
format!("{okm:?}")
504477
);
505478
}
479+
480+
#[test]
481+
fn test_long_salt() {
482+
// Test with a salt longer than the previous 80-byte limit
483+
let long_salt = vec![0x42u8; 100];
484+
485+
// This should work now that we removed the MAX_HKDF_SALT_LEN restriction
486+
let salt = Salt::new(HKDF_SHA256, &long_salt);
487+
488+
// Test the extract operation still works
489+
let secret = b"test secret key material";
490+
let prk = salt.extract(secret);
491+
492+
// Test expand operation
493+
let info_data = b"test context info";
494+
let info = [info_data.as_slice()];
495+
let okm = prk.expand(&info, HKDF_SHA256).unwrap();
496+
497+
// Fill output buffer
498+
let mut output = [0u8; 32];
499+
okm.fill(&mut output).unwrap();
500+
501+
// Test with an even longer salt to demonstrate flexibility
502+
let very_long_salt = vec![0x55u8; 500];
503+
let very_long_salt_obj = Salt::new(HKDF_SHA256, &very_long_salt);
504+
let prk2 = very_long_salt_obj.extract(secret);
505+
let okm2 = prk2.expand(&info, HKDF_SHA256).unwrap();
506+
let mut output2 = [0u8; 32];
507+
okm2.fill(&mut output2).unwrap();
508+
509+
// Verify outputs are different (they should be due to different salts)
510+
assert_ne!(output, output2);
511+
}
506512
}

0 commit comments

Comments
 (0)