1use crate::{c, cpu, debug, polyfill};
28use core::num::Wrapping;
29
30mod sha1;
31mod sha2;
32
33#[derive(Clone)]
34pub(crate) struct BlockContext {
35 state: State,
36
37 completed_data_blocks: u64,
41
42 pub algorithm: &'static Algorithm,
44}
45
46impl BlockContext {
47 pub(crate) fn new(algorithm: &'static Algorithm) -> Self {
48 Self {
49 state: algorithm.initial_state,
50 completed_data_blocks: 0,
51 algorithm,
52 }
53 }
54
55 #[inline]
56 pub(crate) fn update(&mut self, input: &[u8]) {
57 let num_blocks = input.len() / self.algorithm.block_len;
58 assert_eq!(num_blocks * self.algorithm.block_len, input.len());
59
60 if num_blocks > 0 {
61 unsafe {
62 self.block_data_order(input.as_ptr(), num_blocks, cpu::features());
63 }
64 self.completed_data_blocks = self
65 .completed_data_blocks
66 .checked_add(polyfill::u64_from_usize(num_blocks))
67 .unwrap();
68 }
69 }
70
71 pub(crate) fn finish(mut self, pending: &mut [u8], num_pending: usize) -> Digest {
72 let block_len = self.algorithm.block_len;
73 assert_eq!(pending.len(), block_len);
74 assert!(num_pending <= pending.len());
75
76 let mut padding_pos = num_pending;
77 pending[padding_pos] = 0x80;
78 padding_pos += 1;
79
80 if padding_pos > block_len - self.algorithm.len_len {
81 pending[padding_pos..block_len].fill(0);
82 unsafe { self.block_data_order(pending.as_ptr(), 1, cpu::features()) };
83 padding_pos = 0;
86 }
87
88 pending[padding_pos..(block_len - 8)].fill(0);
89
90 let completed_data_bits = self
92 .completed_data_blocks
93 .checked_mul(polyfill::u64_from_usize(block_len))
94 .unwrap()
95 .checked_add(polyfill::u64_from_usize(num_pending))
96 .unwrap()
97 .checked_mul(8)
98 .unwrap();
99 pending[(block_len - 8)..block_len].copy_from_slice(&u64::to_be_bytes(completed_data_bits));
100
101 unsafe { self.block_data_order(pending.as_ptr(), 1, cpu::features()) };
102
103 Digest {
104 algorithm: self.algorithm,
105 value: (self.algorithm.format_output)(self.state),
106 }
107 }
108
109 unsafe fn block_data_order(
110 &mut self,
111 pending: *const u8,
112 num_blocks: usize,
113 _cpu_features: cpu::Features,
114 ) {
115 unsafe {
117 (self.algorithm.block_data_order)(&mut self.state, pending, num_blocks);
118 }
119 }
120}
121
122#[derive(Clone)]
140pub struct Context {
141 block: BlockContext,
142 pending: [u8; MAX_BLOCK_LEN],
144 num_pending: usize,
145}
146
147impl Context {
148 pub fn new(algorithm: &'static Algorithm) -> Self {
150 Self {
151 block: BlockContext::new(algorithm),
152 pending: [0u8; MAX_BLOCK_LEN],
153 num_pending: 0,
154 }
155 }
156
157 pub(crate) fn clone_from(block: &BlockContext) -> Self {
158 Self {
159 block: block.clone(),
160 pending: [0u8; MAX_BLOCK_LEN],
161 num_pending: 0,
162 }
163 }
164
165 pub fn update(&mut self, data: &[u8]) {
167 let block_len = self.block.algorithm.block_len;
168 if data.len() < block_len - self.num_pending {
169 self.pending[self.num_pending..(self.num_pending + data.len())].copy_from_slice(data);
170 self.num_pending += data.len();
171 return;
172 }
173
174 let mut remaining = data;
175 if self.num_pending > 0 {
176 let to_copy = block_len - self.num_pending;
177 self.pending[self.num_pending..block_len].copy_from_slice(&data[..to_copy]);
178 self.block.update(&self.pending[..block_len]);
179 remaining = &remaining[to_copy..];
180 self.num_pending = 0;
181 }
182
183 let num_blocks = remaining.len() / block_len;
184 let num_to_save_for_later = remaining.len() % block_len;
185 self.block.update(&remaining[..(num_blocks * block_len)]);
186 if num_to_save_for_later > 0 {
187 self.pending[..num_to_save_for_later]
188 .copy_from_slice(&remaining[(remaining.len() - num_to_save_for_later)..]);
189 self.num_pending = num_to_save_for_later;
190 }
191 }
192
193 pub fn finish(mut self) -> Digest {
198 let block_len = self.block.algorithm.block_len;
199 self.block
200 .finish(&mut self.pending[..block_len], self.num_pending)
201 }
202
203 #[inline(always)]
205 pub fn algorithm(&self) -> &'static Algorithm {
206 self.block.algorithm
207 }
208}
209
210pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
226 let mut ctx = Context::new(algorithm);
227 ctx.update(data);
228 ctx.finish()
229}
230
231#[derive(Clone, Copy)]
235pub struct Digest {
236 value: Output,
237 algorithm: &'static Algorithm,
238}
239
240impl Digest {
241 #[inline(always)]
243 pub fn algorithm(&self) -> &'static Algorithm {
244 self.algorithm
245 }
246}
247
248impl AsRef<[u8]> for Digest {
249 #[inline(always)]
250 fn as_ref(&self) -> &[u8] {
251 &self.value.0[..self.algorithm.output_len]
252 }
253}
254
255impl core::fmt::Debug for Digest {
256 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
257 write!(fmt, "{:?}:", self.algorithm)?;
258 debug::write_hex_bytes(fmt, self.as_ref())
259 }
260}
261
262pub struct Algorithm {
264 output_len: usize,
265 chaining_len: usize,
266 block_len: usize,
267
268 len_len: usize,
270
271 block_data_order: unsafe extern "C" fn(state: &mut State, data: *const u8, num: c::size_t),
272 format_output: fn(input: State) -> Output,
273
274 initial_state: State,
275
276 id: AlgorithmID,
277}
278
279#[derive(Debug, Eq, PartialEq)]
280enum AlgorithmID {
281 SHA1,
282 SHA256,
283 SHA384,
284 SHA512,
285 SHA512_256,
286}
287
288impl PartialEq for Algorithm {
289 fn eq(&self, other: &Self) -> bool {
290 self.id == other.id
291 }
292}
293
294impl Eq for Algorithm {}
295
296derive_debug_via_id!(Algorithm);
297
298impl Algorithm {
299 pub fn block_len(&self) -> usize {
301 self.block_len
302 }
303
304 pub fn chaining_len(&self) -> usize {
312 self.chaining_len
313 }
314
315 pub fn output_len(&self) -> usize {
317 self.output_len
318 }
319}
320
321pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
325 output_len: sha1::OUTPUT_LEN,
326 chaining_len: sha1::CHAINING_LEN,
327 block_len: sha1::BLOCK_LEN,
328 len_len: 64 / 8,
329 block_data_order: sha1::block_data_order,
330 format_output: sha256_format_output,
331 initial_state: State {
332 as32: [
333 Wrapping(0x67452301u32),
334 Wrapping(0xefcdab89u32),
335 Wrapping(0x98badcfeu32),
336 Wrapping(0x10325476u32),
337 Wrapping(0xc3d2e1f0u32),
338 Wrapping(0),
339 Wrapping(0),
340 Wrapping(0),
341 ],
342 },
343 id: AlgorithmID::SHA1,
344};
345
346pub static SHA256: Algorithm = Algorithm {
350 output_len: SHA256_OUTPUT_LEN,
351 chaining_len: SHA256_OUTPUT_LEN,
352 block_len: 512 / 8,
353 len_len: 64 / 8,
354 block_data_order: sha2::sha256_block_data_order,
355 format_output: sha256_format_output,
356 initial_state: State {
357 as32: [
358 Wrapping(0x6a09e667u32),
359 Wrapping(0xbb67ae85u32),
360 Wrapping(0x3c6ef372u32),
361 Wrapping(0xa54ff53au32),
362 Wrapping(0x510e527fu32),
363 Wrapping(0x9b05688cu32),
364 Wrapping(0x1f83d9abu32),
365 Wrapping(0x5be0cd19u32),
366 ],
367 },
368 id: AlgorithmID::SHA256,
369};
370
371pub static SHA384: Algorithm = Algorithm {
375 output_len: SHA384_OUTPUT_LEN,
376 chaining_len: SHA512_OUTPUT_LEN,
377 block_len: SHA512_BLOCK_LEN,
378 len_len: SHA512_LEN_LEN,
379 block_data_order: sha2::sha512_block_data_order,
380 format_output: sha512_format_output,
381 initial_state: State {
382 as64: [
383 Wrapping(0xcbbb9d5dc1059ed8),
384 Wrapping(0x629a292a367cd507),
385 Wrapping(0x9159015a3070dd17),
386 Wrapping(0x152fecd8f70e5939),
387 Wrapping(0x67332667ffc00b31),
388 Wrapping(0x8eb44a8768581511),
389 Wrapping(0xdb0c2e0d64f98fa7),
390 Wrapping(0x47b5481dbefa4fa4),
391 ],
392 },
393 id: AlgorithmID::SHA384,
394};
395
396pub static SHA512: Algorithm = Algorithm {
400 output_len: SHA512_OUTPUT_LEN,
401 chaining_len: SHA512_OUTPUT_LEN,
402 block_len: SHA512_BLOCK_LEN,
403 len_len: SHA512_LEN_LEN,
404 block_data_order: sha2::sha512_block_data_order,
405 format_output: sha512_format_output,
406 initial_state: State {
407 as64: [
408 Wrapping(0x6a09e667f3bcc908),
409 Wrapping(0xbb67ae8584caa73b),
410 Wrapping(0x3c6ef372fe94f82b),
411 Wrapping(0xa54ff53a5f1d36f1),
412 Wrapping(0x510e527fade682d1),
413 Wrapping(0x9b05688c2b3e6c1f),
414 Wrapping(0x1f83d9abfb41bd6b),
415 Wrapping(0x5be0cd19137e2179),
416 ],
417 },
418 id: AlgorithmID::SHA512,
419};
420
421pub static SHA512_256: Algorithm = Algorithm {
429 output_len: SHA512_256_OUTPUT_LEN,
430 chaining_len: SHA512_OUTPUT_LEN,
431 block_len: SHA512_BLOCK_LEN,
432 len_len: SHA512_LEN_LEN,
433 block_data_order: sha2::sha512_block_data_order,
434 format_output: sha512_format_output,
435 initial_state: State {
436 as64: [
437 Wrapping(0x22312194fc2bf72c),
438 Wrapping(0x9f555fa3c84c64c2),
439 Wrapping(0x2393b86b6f53b151),
440 Wrapping(0x963877195940eabd),
441 Wrapping(0x96283ee2a88effe3),
442 Wrapping(0xbe5e1e2553863992),
443 Wrapping(0x2b0199fc2c85b8aa),
444 Wrapping(0x0eb72ddc81c52ca2),
445 ],
446 },
447 id: AlgorithmID::SHA512_256,
448};
449
450#[derive(Clone, Copy)] #[repr(C)]
452union State {
453 as64: [Wrapping<u64>; sha2::CHAINING_WORDS],
454 as32: [Wrapping<u32>; sha2::CHAINING_WORDS],
455}
456
457#[derive(Clone, Copy)]
458struct Output([u8; MAX_OUTPUT_LEN]);
459
460pub const MAX_BLOCK_LEN: usize = 1024 / 8;
463
464pub const MAX_OUTPUT_LEN: usize = 512 / 8;
467
468pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
471
472fn sha256_format_output(input: State) -> Output {
473 let input = unsafe { input.as32 };
474 format_output::<_, _, { core::mem::size_of::<u32>() }>(input, u32::to_be_bytes)
475}
476
477fn sha512_format_output(input: State) -> Output {
478 let input = unsafe { input.as64 };
479 format_output::<_, _, { core::mem::size_of::<u64>() }>(input, u64::to_be_bytes)
480}
481
482#[inline]
483fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output
484where
485 F: Fn(T) -> [u8; N],
486 T: Copy,
487{
488 let mut output = Output([0; MAX_OUTPUT_LEN]);
489 output
490 .0
491 .chunks_mut(N)
492 .zip(input.iter().copied().map(|Wrapping(w)| f(w)))
493 .for_each(|(o, i)| {
494 o.copy_from_slice(&i);
495 });
496 output
497}
498
499pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN;
501
502pub const SHA256_OUTPUT_LEN: usize = 256 / 8;
504
505pub const SHA384_OUTPUT_LEN: usize = 384 / 8;
507
508pub const SHA512_OUTPUT_LEN: usize = 512 / 8;
510
511pub const SHA512_256_OUTPUT_LEN: usize = 256 / 8;
513
514const SHA512_BLOCK_LEN: usize = 1024 / 8;
516
517const SHA512_LEN_LEN: usize = 128 / 8;
519
520#[cfg(test)]
521mod tests {
522 mod max_input {
523 extern crate alloc;
524 use super::super::super::digest;
525 use crate::polyfill;
526 use alloc::vec;
527
528 macro_rules! max_input_tests {
529 ( $algorithm_name:ident ) => {
530 mod $algorithm_name {
531 use super::super::super::super::digest;
532
533 #[test]
534 fn max_input_test() {
535 super::max_input_test(&digest::$algorithm_name);
536 }
537
538 #[test]
539 #[should_panic]
540 fn too_long_input_test_block() {
541 super::too_long_input_test_block(&digest::$algorithm_name);
542 }
543
544 #[test]
545 #[should_panic]
546 fn too_long_input_test_byte() {
547 super::too_long_input_test_byte(&digest::$algorithm_name);
548 }
549 }
550 };
551 }
552
553 fn max_input_test(alg: &'static digest::Algorithm) {
554 let mut context = nearly_full_context(alg);
555 let next_input = vec![0u8; alg.block_len - 1];
556 context.update(&next_input);
557 let _ = context.finish(); }
559
560 fn too_long_input_test_block(alg: &'static digest::Algorithm) {
561 let mut context = nearly_full_context(alg);
562 let next_input = vec![0u8; alg.block_len];
563 context.update(&next_input);
564 let _ = context.finish(); }
566
567 fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
568 let mut context = nearly_full_context(alg);
569 let next_input = vec![0u8; alg.block_len - 1];
570 context.update(&next_input); context.update(&[0]);
572 let _ = context.finish(); }
574
575 fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
576 let max_bytes = 1u64 << (64 - 3);
580 let max_blocks = max_bytes / polyfill::u64_from_usize(alg.block_len);
581 digest::Context {
582 block: digest::BlockContext {
583 state: alg.initial_state,
584 completed_data_blocks: max_blocks - 1,
585 algorithm: alg,
586 },
587 pending: [0u8; digest::MAX_BLOCK_LEN],
588 num_pending: 0,
589 }
590 }
591
592 max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
593 max_input_tests!(SHA256);
594 max_input_tests!(SHA384);
595 max_input_tests!(SHA512);
596 }
597}