1#![allow(non_snake_case)]
31use crate::fips::indicator_check;
32use crate::{debug, derive_debug_via_id};
33
34pub(crate) mod digest_ctx;
35mod sha;
36use crate::aws_lc::{
37 EVP_DigestFinal, EVP_DigestUpdate, EVP_sha1, EVP_sha224, EVP_sha256, EVP_sha384, EVP_sha3_256,
38 EVP_sha3_384, EVP_sha3_512, EVP_sha512, EVP_sha512_256, EVP_MD,
39};
40use crate::error::Unspecified;
41use crate::ptr::ConstPointer;
42use core::mem::MaybeUninit;
43use digest_ctx::DigestContext;
44pub use sha::{
45 SHA1_FOR_LEGACY_USE_ONLY, SHA1_OUTPUT_LEN, SHA224, SHA224_OUTPUT_LEN, SHA256,
46 SHA256_OUTPUT_LEN, SHA384, SHA384_OUTPUT_LEN, SHA3_256, SHA3_384, SHA3_512, SHA512, SHA512_256,
47 SHA512_256_OUTPUT_LEN, SHA512_OUTPUT_LEN,
48};
49use std::os::raw::c_uint;
52
53#[derive(Clone)]
64pub struct Context {
65 pub(crate) algorithm: &'static Algorithm,
67 digest_ctx: DigestContext,
68 msg_len: u64,
75 max_input_reached: bool,
76}
77
78impl Context {
79 #[must_use]
86 pub fn new(algorithm: &'static Algorithm) -> Self {
87 Self {
88 algorithm,
89 digest_ctx: DigestContext::new(algorithm).unwrap(),
90 msg_len: 0u64,
91 max_input_reached: false,
92 }
93 }
94
95 #[inline]
100 pub fn update(&mut self, data: &[u8]) {
101 Self::try_update(self, data).expect("digest update failed");
102 }
103
104 #[inline]
105 fn try_update(&mut self, data: &[u8]) -> Result<(), Unspecified> {
106 unsafe {
107 let (msg_len, overflowed) = self.msg_len.overflowing_add(data.len() as u64);
110 if overflowed || msg_len > self.algorithm.max_input_len {
111 return Err(Unspecified);
112 }
113
114 self.msg_len = msg_len;
115 self.max_input_reached = self.msg_len == self.algorithm.max_input_len;
116
117 if 1 != EVP_DigestUpdate(
119 self.digest_ctx.as_mut_ptr(),
120 data.as_ptr().cast(),
121 data.len(),
122 ) {
123 return Err(Unspecified);
124 }
125 Ok(())
126 }
127 }
128
129 #[inline]
137 #[must_use]
138 pub fn finish(self) -> Digest {
139 Self::try_finish(self).expect("EVP_DigestFinal failed")
140 }
141
142 #[inline]
143 fn try_finish(mut self) -> Result<Digest, Unspecified> {
144 let mut output = [0u8; MAX_OUTPUT_LEN];
145 let mut out_len = MaybeUninit::<c_uint>::uninit();
146 if 1 != indicator_check!(unsafe {
147 EVP_DigestFinal(
148 self.digest_ctx.as_mut_ptr(),
149 output.as_mut_ptr(),
150 out_len.as_mut_ptr(),
151 )
152 }) {
153 return Err(Unspecified);
154 }
155
156 Ok(Digest {
157 algorithm: self.algorithm,
158 digest_msg: output,
159 digest_len: self.algorithm.output_len,
160 })
161 }
162
163 #[inline]
165 #[must_use]
166 pub fn algorithm(&self) -> &'static Algorithm {
167 self.algorithm
168 }
169}
170
171#[inline]
195#[must_use]
196pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
197 let mut output = [0u8; MAX_OUTPUT_LEN];
198 (algorithm.one_shot_hash)(data, &mut output);
199
200 Digest {
201 algorithm,
202 digest_msg: output,
203 digest_len: algorithm.output_len,
204 }
205}
206
207#[derive(Clone, Copy)]
211pub struct Digest {
212 digest_msg: [u8; MAX_OUTPUT_LEN],
215 digest_len: usize,
216
217 algorithm: &'static Algorithm,
218}
219
220impl Digest {
221 #[inline]
223 #[must_use]
224 pub fn algorithm(&self) -> &'static Algorithm {
225 self.algorithm
226 }
227}
228
229impl AsRef<[u8]> for Digest {
230 #[inline]
231 fn as_ref(&self) -> &[u8] {
232 &self.digest_msg[..self.digest_len]
233 }
234}
235
236impl core::fmt::Debug for Digest {
237 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
238 write!(fmt, "{:?}:", self.algorithm)?;
239 debug::write_hex_bytes(fmt, self.as_ref())
240 }
241}
242
243pub struct Algorithm {
245 pub output_len: usize,
247
248 #[deprecated]
258 pub chaining_len: usize,
259
260 pub block_len: usize,
262
263 max_input_len: u64,
265
266 one_shot_hash: fn(msg: &[u8], output: &mut [u8]),
267
268 pub(crate) id: AlgorithmID,
269}
270
271unsafe impl Send for Algorithm {}
272
273impl Algorithm {
274 #[inline]
276 #[must_use]
277 pub fn output_len(&self) -> usize {
278 self.output_len
279 }
280
281 #[deprecated]
291 #[inline]
292 #[must_use]
293 pub fn chaining_len(&self) -> usize {
294 #![allow(deprecated)]
296 self.chaining_len
297 }
298
299 #[inline]
301 #[must_use]
302 pub fn block_len(&self) -> usize {
303 self.block_len
304 }
305}
306
307#[derive(Clone, Copy, Debug, Eq, PartialEq)]
308pub(crate) enum AlgorithmID {
309 SHA1,
310 SHA224,
311 SHA256,
312 SHA384,
313 SHA512,
314 SHA512_256,
315 SHA3_256,
316 SHA3_384,
317 SHA3_512,
318}
319
320impl PartialEq for Algorithm {
321 fn eq(&self, other: &Self) -> bool {
322 self.id == other.id
323 }
324}
325
326impl Eq for Algorithm {}
327
328derive_debug_via_id!(Algorithm);
329
330pub const MAX_BLOCK_LEN: usize = 1024 / 8;
333
334pub const MAX_OUTPUT_LEN: usize = 512 / 8;
337
338pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
341
342pub(crate) fn match_digest_type(algorithm_id: &AlgorithmID) -> ConstPointer<EVP_MD> {
344 unsafe {
345 ConstPointer::new(match algorithm_id {
346 AlgorithmID::SHA1 => EVP_sha1(),
347 AlgorithmID::SHA224 => EVP_sha224(),
348 AlgorithmID::SHA256 => EVP_sha256(),
349 AlgorithmID::SHA384 => EVP_sha384(),
350 AlgorithmID::SHA512 => EVP_sha512(),
351 AlgorithmID::SHA512_256 => EVP_sha512_256(),
352 AlgorithmID::SHA3_256 => EVP_sha3_256(),
353 AlgorithmID::SHA3_384 => EVP_sha3_384(),
354 AlgorithmID::SHA3_512 => EVP_sha3_512(),
355 })
356 .unwrap_or_else(|()| panic!("Digest algorithm not found: {algorithm_id:?}"))
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 #[cfg(feature = "fips")]
363 mod fips;
364
365 mod max_input {
366 extern crate alloc;
367
368 use super::super::super::digest;
369 use crate::digest::digest_ctx::DigestContext;
370 use crate::digest::Digest;
371 use alloc::vec;
372
373 macro_rules! max_input_tests {
374 ( $algorithm_name:ident ) => {
375 mod $algorithm_name {
376 use super::super::super::super::digest;
377
378 #[test]
379 fn max_input_test() {
380 super::max_input_test(&digest::$algorithm_name);
381 }
382 #[test]
383 #[should_panic(expected = "digest update failed")]
384 fn too_long_input_test_block() {
385 super::too_long_input_test_block(&digest::$algorithm_name);
386 }
387
388 #[test]
389 #[should_panic(expected = "digest update failed")]
390 fn too_long_input_test_byte() {
391 super::too_long_input_test_byte(&digest::$algorithm_name);
392 }
393 }
394 };
395 }
396
397 fn max_input_test(alg: &'static digest::Algorithm) {
398 let mut context = nearly_full_context(alg);
399 let next_input = vec![0u8; alg.block_len - 1];
400 context.update(&next_input);
401 let _: Digest = context.finish(); }
403
404 fn too_long_input_test_block(alg: &'static digest::Algorithm) {
405 let mut context = nearly_full_context(alg);
406 let next_input = vec![0u8; alg.block_len];
407 context.update(&next_input);
408 let _: Digest = context.finish(); }
410
411 fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
412 let mut context = nearly_full_context(alg);
413 let next_input = vec![0u8; alg.block_len - 1];
414 context.update(&next_input); context.update(&[0]);
416 let _: Digest = context.finish(); }
418
419 fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
420 let block_len = alg.block_len as u64;
423 digest::Context {
424 algorithm: alg,
425 digest_ctx: DigestContext::new(alg).unwrap(),
426 msg_len: alg.max_input_len - block_len + 1,
427 max_input_reached: false,
428 }
429 }
430
431 max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
432 max_input_tests!(SHA224);
433 max_input_tests!(SHA256);
434 max_input_tests!(SHA384);
435 max_input_tests!(SHA512);
436 max_input_tests!(SHA3_384);
437 max_input_tests!(SHA3_512);
438 }
439
440 #[test]
441 fn digest_coverage() {
442 use crate::digest;
443
444 for alg in [
445 &digest::SHA1_FOR_LEGACY_USE_ONLY,
446 &digest::SHA224,
447 &digest::SHA256,
448 &digest::SHA384,
449 &digest::SHA512,
450 &digest::SHA3_384,
451 &digest::SHA3_512,
452 ] {
453 let mut ctx = digest::Context::new(alg);
455 ctx.update(b"hello, world");
456 let ctx_clone = ctx.clone();
457 assert_eq!(ctx_clone.algorithm(), ctx.algorithm());
458
459 let orig_digest = ctx.finish();
460 let clone_digest = ctx_clone.finish();
461 assert_eq!(orig_digest.algorithm(), clone_digest.algorithm());
462 assert_eq!(orig_digest.as_ref(), clone_digest.as_ref());
463 assert_eq!(orig_digest.clone().as_ref(), clone_digest.as_ref());
464 }
465 }
466}