1 | // Copyright 2015-2019 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | //! SHA-2 and the legacy SHA-1 digest algorithm. |
16 | //! |
17 | //! If all the data is available in a single contiguous slice then the `digest` |
18 | //! function should be used. Otherwise, the digest can be calculated in |
19 | //! multiple steps using `Context`. |
20 | |
21 | use self::{ |
22 | dynstate::DynState, |
23 | sha2::{SHA256_BLOCK_LEN, SHA512_BLOCK_LEN}, |
24 | }; |
25 | use crate::{ |
26 | bits::{BitLength, FromByteLen as _}, |
27 | cpu, debug, error, |
28 | polyfill::{self, slice, sliceutil}, |
29 | }; |
30 | use core::num::Wrapping; |
31 | |
32 | pub(crate) use self::finish_error::FinishError; |
33 | |
34 | mod dynstate; |
35 | mod sha1; |
36 | mod sha2; |
37 | |
38 | #[derive (Clone)] |
39 | pub(crate) struct BlockContext { |
40 | state: DynState, |
41 | |
42 | // Note that SHA-512 has a 128-bit input bit counter, but this |
43 | // implementation only supports up to 2^64-1 input bits for all algorithms, |
44 | // so a 64-bit counter is more than sufficient. |
45 | completed_bytes: u64, |
46 | |
47 | /// The context's algorithm. |
48 | pub algorithm: &'static Algorithm, |
49 | } |
50 | |
51 | impl BlockContext { |
52 | pub(crate) fn new(algorithm: &'static Algorithm) -> Self { |
53 | Self { |
54 | state: algorithm.initial_state.clone(), |
55 | completed_bytes: 0, |
56 | algorithm, |
57 | } |
58 | } |
59 | |
60 | /// Processes all the full blocks in `input`, returning the partial block |
61 | /// at the end, which may be empty. |
62 | pub(crate) fn update<'i>(&mut self, input: &'i [u8], cpu_features: cpu::Features) -> &'i [u8] { |
63 | let (completed_bytes, leftover) = self.block_data_order(input, cpu_features); |
64 | // Using saturated addition here allows `update` to be infallible and |
65 | // panic-free. If we were to reach the maximum value here then `finish` |
66 | // will detect that we processed too much data when it converts this to |
67 | // a bit length. |
68 | self.completed_bytes = self |
69 | .completed_bytes |
70 | .saturating_add(polyfill::u64_from_usize(completed_bytes)); |
71 | leftover |
72 | } |
73 | |
74 | // On input, `block[..num_pending]` is the (possibly-empty) last *partial* |
75 | // chunk of input. It *must* be partial; that is, it is required that |
76 | // `num_pending < self.algorithm.block_len`. |
77 | // |
78 | // `block` may be arbitrarily overwritten. |
79 | pub(crate) fn try_finish( |
80 | mut self, |
81 | block: &mut [u8; MAX_BLOCK_LEN], |
82 | num_pending: usize, |
83 | cpu_features: cpu::Features, |
84 | ) -> Result<Digest, FinishError> { |
85 | let completed_bits = self |
86 | .completed_bytes |
87 | .checked_add(polyfill::u64_from_usize(num_pending)) |
88 | .ok_or_else(|| { |
89 | // Choosing self.completed_bytes here is lossy & somewhat arbitrary. |
90 | InputTooLongError::new(self.completed_bytes) |
91 | }) |
92 | .and_then(BitLength::from_byte_len) |
93 | .map_err(FinishError::input_too_long)?; |
94 | |
95 | let block_len = self.algorithm.block_len(); |
96 | let block = &mut block[..block_len]; |
97 | |
98 | let padding = match block.get_mut(num_pending..) { |
99 | Some([separator, padding @ ..]) => { |
100 | *separator = 0x80; |
101 | padding |
102 | } |
103 | // Precondition violated. |
104 | unreachable => { |
105 | return Err(FinishError::pending_not_a_partial_block( |
106 | unreachable.as_deref(), |
107 | )); |
108 | } |
109 | }; |
110 | |
111 | let padding = match padding |
112 | .len() |
113 | .checked_sub(self.algorithm.block_len.len_len()) |
114 | { |
115 | Some(_) => padding, |
116 | None => { |
117 | padding.fill(0); |
118 | let (completed_bytes, leftover) = self.block_data_order(block, cpu_features); |
119 | debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0)); |
120 | // We don't increase |self.completed_bytes| because the padding |
121 | // isn't data, and so it isn't included in the data length. |
122 | &mut block[..] |
123 | } |
124 | }; |
125 | |
126 | let (to_zero, len) = padding.split_at_mut(padding.len() - 8); |
127 | to_zero.fill(0); |
128 | len.copy_from_slice(&completed_bits.to_be_bytes()); |
129 | |
130 | let (completed_bytes, leftover) = self.block_data_order(block, cpu_features); |
131 | debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0)); |
132 | |
133 | Ok(Digest { |
134 | algorithm: self.algorithm, |
135 | value: self.state.format_output(), |
136 | }) |
137 | } |
138 | |
139 | #[must_use ] |
140 | fn block_data_order<'d>( |
141 | &mut self, |
142 | data: &'d [u8], |
143 | cpu_features: cpu::Features, |
144 | ) -> (usize, &'d [u8]) { |
145 | (self.algorithm.block_data_order)(&mut self.state, data, cpu_features) |
146 | } |
147 | } |
148 | |
149 | pub(crate) type InputTooLongError = error::InputTooLongError<u64>; |
150 | |
151 | cold_exhaustive_error! { |
152 | enum finish_error::FinishError { |
153 | input_too_long => InputTooLong(InputTooLongError), |
154 | pending_not_a_partial_block_inner => PendingNotAPartialBlock(usize), |
155 | } |
156 | } |
157 | |
158 | impl FinishError { |
159 | #[cold ] |
160 | #[inline (never)] |
161 | fn pending_not_a_partial_block(padding: Option<&[u8]>) -> Self { |
162 | match padding { |
163 | None => Self::pending_not_a_partial_block_inner(0), |
164 | Some(padding: &[u8]) => Self::pending_not_a_partial_block_inner(padding.len()), |
165 | } |
166 | } |
167 | } |
168 | |
169 | /// A context for multi-step (Init-Update-Finish) digest calculations. |
170 | /// |
171 | /// # Examples |
172 | /// |
173 | /// ``` |
174 | /// use ring::digest; |
175 | /// |
176 | /// let one_shot = digest::digest(&digest::SHA384, b"hello, world" ); |
177 | /// |
178 | /// let mut ctx = digest::Context::new(&digest::SHA384); |
179 | /// ctx.update(b"hello" ); |
180 | /// ctx.update(b", " ); |
181 | /// ctx.update(b"world" ); |
182 | /// let multi_part = ctx.finish(); |
183 | /// |
184 | /// assert_eq!(&one_shot.as_ref(), &multi_part.as_ref()); |
185 | /// ``` |
186 | #[derive (Clone)] |
187 | pub struct Context { |
188 | block: BlockContext, |
189 | // TODO: More explicitly force 64-bit alignment for |pending|. |
190 | pending: [u8; MAX_BLOCK_LEN], |
191 | |
192 | // Invariant: `self.num_pending < self.block.algorithm.block_len`. |
193 | num_pending: usize, |
194 | } |
195 | |
196 | impl Context { |
197 | /// Constructs a new context. |
198 | pub fn new(algorithm: &'static Algorithm) -> Self { |
199 | Self { |
200 | block: BlockContext::new(algorithm), |
201 | pending: [0u8; MAX_BLOCK_LEN], |
202 | num_pending: 0, |
203 | } |
204 | } |
205 | |
206 | pub(crate) fn clone_from(block: &BlockContext) -> Self { |
207 | Self { |
208 | block: block.clone(), |
209 | pending: [0u8; MAX_BLOCK_LEN], |
210 | num_pending: 0, |
211 | } |
212 | } |
213 | |
214 | /// Updates the digest with all the data in `data`. |
215 | pub fn update(&mut self, data: &[u8]) { |
216 | let cpu_features = cpu::features(); |
217 | |
218 | let block_len = self.block.algorithm.block_len(); |
219 | let buffer = &mut self.pending[..block_len]; |
220 | |
221 | let to_digest = if self.num_pending == 0 { |
222 | data |
223 | } else { |
224 | let buffer_to_fill = match buffer.get_mut(self.num_pending..) { |
225 | Some(buffer_to_fill) => buffer_to_fill, |
226 | None => { |
227 | // Impossible because of the invariant. |
228 | unreachable!(); |
229 | } |
230 | }; |
231 | sliceutil::overwrite_at_start(buffer_to_fill, data); |
232 | match slice::split_at_checked(data, buffer_to_fill.len()) { |
233 | Some((just_copied, to_digest)) => { |
234 | debug_assert_eq!(buffer_to_fill.len(), just_copied.len()); |
235 | debug_assert_eq!(self.num_pending + just_copied.len(), block_len); |
236 | let leftover = self.block.update(buffer, cpu_features); |
237 | debug_assert_eq!(leftover.len(), 0); |
238 | self.num_pending = 0; |
239 | to_digest |
240 | } |
241 | None => { |
242 | self.num_pending += data.len(); |
243 | // If `data` isn't enough to complete a block, buffer it and stop. |
244 | debug_assert!(self.num_pending < block_len); |
245 | return; |
246 | } |
247 | } |
248 | }; |
249 | |
250 | let leftover = self.block.update(to_digest, cpu_features); |
251 | sliceutil::overwrite_at_start(buffer, leftover); |
252 | self.num_pending = leftover.len(); |
253 | debug_assert!(self.num_pending < block_len); |
254 | } |
255 | |
256 | /// Finalizes the digest calculation and returns the digest value. |
257 | /// |
258 | /// `finish` consumes the context so it cannot be (mis-)used after `finish` |
259 | /// has been called. |
260 | pub fn finish(self) -> Digest { |
261 | let cpu = cpu::features(); |
262 | self.try_finish(cpu) |
263 | .map_err(error::erase::<InputTooLongError>) |
264 | .unwrap() |
265 | } |
266 | |
267 | pub(crate) fn try_finish( |
268 | mut self, |
269 | cpu_features: cpu::Features, |
270 | ) -> Result<Digest, InputTooLongError> { |
271 | self.block |
272 | .try_finish(&mut self.pending, self.num_pending, cpu_features) |
273 | .map_err(|err| match err { |
274 | FinishError::InputTooLong(i) => i, |
275 | FinishError::PendingNotAPartialBlock(_) => { |
276 | // Due to invariant. |
277 | unreachable!() |
278 | } |
279 | }) |
280 | } |
281 | |
282 | /// The algorithm that this context is using. |
283 | #[inline (always)] |
284 | pub fn algorithm(&self) -> &'static Algorithm { |
285 | self.block.algorithm |
286 | } |
287 | } |
288 | |
289 | /// Returns the digest of `data` using the given digest algorithm. |
290 | /// |
291 | /// # Examples: |
292 | /// |
293 | /// ``` |
294 | /// # #[cfg (feature = "alloc" )] |
295 | /// # { |
296 | /// use ring::{digest, test}; |
297 | /// let expected_hex = "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b" ; |
298 | /// let expected: Vec<u8> = test::from_hex(expected_hex).unwrap(); |
299 | /// let actual = digest::digest(&digest::SHA256, b"hello, world" ); |
300 | /// |
301 | /// assert_eq!(&expected, &actual.as_ref()); |
302 | /// # } |
303 | /// ``` |
304 | pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest { |
305 | let cpu: Features = cpu::features(); |
306 | DigestResult::compute_from(algorithm, data, cpu) |
307 | .map_err(op:error::erase::<InputTooLongError>) |
308 | .unwrap() |
309 | } |
310 | |
311 | /// A calculated digest value. |
312 | /// |
313 | /// Use [`Self::as_ref`] to get the value as a `&[u8]`. |
314 | #[derive (Clone, Copy)] |
315 | pub struct Digest { |
316 | value: Output, |
317 | algorithm: &'static Algorithm, |
318 | } |
319 | |
320 | impl Digest { |
321 | pub(crate) fn compute_from( |
322 | algorithm: &'static Algorithm, |
323 | data: &[u8], |
324 | cpu: cpu::Features, |
325 | ) -> Result<Self, InputTooLongError> { |
326 | let mut ctx: Context = Context::new(algorithm); |
327 | ctx.update(data); |
328 | ctx.try_finish(cpu) |
329 | } |
330 | |
331 | /// The algorithm that was used to calculate the digest value. |
332 | #[inline (always)] |
333 | pub fn algorithm(&self) -> &'static Algorithm { |
334 | self.algorithm |
335 | } |
336 | } |
337 | |
338 | impl AsRef<[u8]> for Digest { |
339 | #[inline (always)] |
340 | fn as_ref(&self) -> &[u8] { |
341 | &self.value.0[..self.algorithm.output_len()] |
342 | } |
343 | } |
344 | |
345 | impl core::fmt::Debug for Digest { |
346 | fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { |
347 | write!(fmt, " {:?}:" , self.algorithm)?; |
348 | debug::write_hex_bytes(fmt, self.as_ref()) |
349 | } |
350 | } |
351 | |
352 | /// A digest algorithm. |
353 | pub struct Algorithm { |
354 | output_len: OutputLen, |
355 | chaining_len: usize, |
356 | block_len: BlockLen, |
357 | |
358 | /// `block_data_order` processes all the full blocks of data in `data`. It |
359 | /// returns the number of bytes processed and the unprocessed data, which |
360 | /// is guaranteed to be less than `block_len` bytes long. |
361 | block_data_order: for<'d> fn( |
362 | state: &mut DynState, |
363 | data: &'d [u8], |
364 | cpu_features: cpu::Features, |
365 | ) -> (usize, &'d [u8]), |
366 | |
367 | initial_state: DynState, |
368 | |
369 | id: AlgorithmID, |
370 | } |
371 | |
372 | #[derive (Debug, Eq, PartialEq)] |
373 | enum AlgorithmID { |
374 | SHA1, |
375 | SHA256, |
376 | SHA384, |
377 | SHA512, |
378 | SHA512_256, |
379 | } |
380 | |
381 | impl PartialEq for Algorithm { |
382 | fn eq(&self, other: &Self) -> bool { |
383 | self.id == other.id |
384 | } |
385 | } |
386 | |
387 | impl Eq for Algorithm {} |
388 | |
389 | derive_debug_via_id!(Algorithm); |
390 | |
391 | impl Algorithm { |
392 | /// The internal block length. |
393 | pub fn block_len(&self) -> usize { |
394 | self.block_len.into() |
395 | } |
396 | |
397 | /// The size of the chaining value of the digest function, in bytes. |
398 | /// |
399 | /// For non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal |
400 | /// to [`Self::output_len()`]. For truncated algorithms (e.g. SHA-384, |
401 | /// SHA-512/256), this is equal to the length before truncation. This is |
402 | /// mostly helpful for determining the size of an HMAC key that is |
403 | /// appropriate for the digest algorithm. |
404 | pub fn chaining_len(&self) -> usize { |
405 | self.chaining_len |
406 | } |
407 | |
408 | /// The length of a finalized digest. |
409 | pub fn output_len(&self) -> usize { |
410 | self.output_len.into() |
411 | } |
412 | } |
413 | |
414 | /// SHA-1 as specified in [FIPS 180-4]. Deprecated. |
415 | /// |
416 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
417 | pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm { |
418 | output_len: sha1::OUTPUT_LEN, |
419 | chaining_len: sha1::CHAINING_LEN, |
420 | block_len: sha1::BLOCK_LEN, |
421 | block_data_order: dynstate::sha1_block_data_order, |
422 | initial_state: DynState::new32([ |
423 | Wrapping(0x67452301u32), |
424 | Wrapping(0xefcdab89u32), |
425 | Wrapping(0x98badcfeu32), |
426 | Wrapping(0x10325476u32), |
427 | Wrapping(0xc3d2e1f0u32), |
428 | Wrapping(0), |
429 | Wrapping(0), |
430 | Wrapping(0), |
431 | ]), |
432 | id: AlgorithmID::SHA1, |
433 | }; |
434 | |
435 | /// SHA-256 as specified in [FIPS 180-4]. |
436 | /// |
437 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
438 | pub static SHA256: Algorithm = Algorithm { |
439 | output_len: OutputLen::_256, |
440 | chaining_len: SHA256_OUTPUT_LEN, |
441 | block_len: SHA256_BLOCK_LEN, |
442 | block_data_order: dynstate::sha256_block_data_order, |
443 | initial_state: DynState::new32([ |
444 | Wrapping(0x6a09e667u32), |
445 | Wrapping(0xbb67ae85u32), |
446 | Wrapping(0x3c6ef372u32), |
447 | Wrapping(0xa54ff53au32), |
448 | Wrapping(0x510e527fu32), |
449 | Wrapping(0x9b05688cu32), |
450 | Wrapping(0x1f83d9abu32), |
451 | Wrapping(0x5be0cd19u32), |
452 | ]), |
453 | id: AlgorithmID::SHA256, |
454 | }; |
455 | |
456 | /// SHA-384 as specified in [FIPS 180-4]. |
457 | /// |
458 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
459 | pub static SHA384: Algorithm = Algorithm { |
460 | output_len: OutputLen::_384, |
461 | chaining_len: SHA512_OUTPUT_LEN, |
462 | block_len: SHA512_BLOCK_LEN, |
463 | block_data_order: dynstate::sha512_block_data_order, |
464 | initial_state: DynState::new64([ |
465 | Wrapping(0xcbbb9d5dc1059ed8), |
466 | Wrapping(0x629a292a367cd507), |
467 | Wrapping(0x9159015a3070dd17), |
468 | Wrapping(0x152fecd8f70e5939), |
469 | Wrapping(0x67332667ffc00b31), |
470 | Wrapping(0x8eb44a8768581511), |
471 | Wrapping(0xdb0c2e0d64f98fa7), |
472 | Wrapping(0x47b5481dbefa4fa4), |
473 | ]), |
474 | id: AlgorithmID::SHA384, |
475 | }; |
476 | |
477 | /// SHA-512 as specified in [FIPS 180-4]. |
478 | /// |
479 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
480 | pub static SHA512: Algorithm = Algorithm { |
481 | output_len: OutputLen::_512, |
482 | chaining_len: SHA512_OUTPUT_LEN, |
483 | block_len: SHA512_BLOCK_LEN, |
484 | block_data_order: dynstate::sha512_block_data_order, |
485 | initial_state: DynState::new64([ |
486 | Wrapping(0x6a09e667f3bcc908), |
487 | Wrapping(0xbb67ae8584caa73b), |
488 | Wrapping(0x3c6ef372fe94f82b), |
489 | Wrapping(0xa54ff53a5f1d36f1), |
490 | Wrapping(0x510e527fade682d1), |
491 | Wrapping(0x9b05688c2b3e6c1f), |
492 | Wrapping(0x1f83d9abfb41bd6b), |
493 | Wrapping(0x5be0cd19137e2179), |
494 | ]), |
495 | id: AlgorithmID::SHA512, |
496 | }; |
497 | |
498 | /// SHA-512/256 as specified in [FIPS 180-4]. |
499 | /// |
500 | /// This is *not* the same as just truncating the output of SHA-512, as |
501 | /// SHA-512/256 has its own initial state distinct from SHA-512's initial |
502 | /// state. |
503 | /// |
504 | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
505 | pub static SHA512_256: Algorithm = Algorithm { |
506 | output_len: OutputLen::_256, |
507 | chaining_len: SHA512_OUTPUT_LEN, |
508 | block_len: SHA512_BLOCK_LEN, |
509 | block_data_order: dynstate::sha512_block_data_order, |
510 | initial_state: DynState::new64([ |
511 | Wrapping(0x22312194fc2bf72c), |
512 | Wrapping(0x9f555fa3c84c64c2), |
513 | Wrapping(0x2393b86b6f53b151), |
514 | Wrapping(0x963877195940eabd), |
515 | Wrapping(0x96283ee2a88effe3), |
516 | Wrapping(0xbe5e1e2553863992), |
517 | Wrapping(0x2b0199fc2c85b8aa), |
518 | Wrapping(0x0eb72ddc81c52ca2), |
519 | ]), |
520 | id: AlgorithmID::SHA512_256, |
521 | }; |
522 | |
523 | #[derive (Clone, Copy)] |
524 | struct Output([u8; MAX_OUTPUT_LEN]); |
525 | |
526 | /// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms |
527 | /// in this module. |
528 | pub const MAX_BLOCK_LEN: usize = BlockLen::MAX.into(); |
529 | |
530 | /// The maximum output length ([`Algorithm::output_len()`]) of all the |
531 | /// algorithms in this module. |
532 | pub const MAX_OUTPUT_LEN: usize = OutputLen::MAX.into(); |
533 | |
534 | /// The maximum chaining length ([`Algorithm::chaining_len()`]) of all the |
535 | /// algorithms in this module. |
536 | pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN; |
537 | |
538 | #[inline ] |
539 | fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output |
540 | where |
541 | F: Fn(T) -> [u8; N], |
542 | T: Copy, |
543 | { |
544 | let mut output: Output = Output([0; MAX_OUTPUT_LEN]); |
545 | outputimpl Iterator |
546 | .0 |
547 | .chunks_mut(N) |
548 | .zip(input.iter().copied().map(|Wrapping(w: T)| f(w))) |
549 | .for_each(|(o: &mut [u8], i: [u8; N])| { |
550 | o.copy_from_slice(&i); |
551 | }); |
552 | output |
553 | } |
554 | |
555 | /// The length of the output of SHA-1, in bytes. |
556 | pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN.into(); |
557 | |
558 | /// The length of the output of SHA-256, in bytes. |
559 | pub const SHA256_OUTPUT_LEN: usize = OutputLen::_256.into(); |
560 | |
561 | /// The length of the output of SHA-384, in bytes. |
562 | pub const SHA384_OUTPUT_LEN: usize = OutputLen::_384.into(); |
563 | |
564 | /// The length of the output of SHA-512, in bytes. |
565 | pub const SHA512_OUTPUT_LEN: usize = OutputLen::_512.into(); |
566 | |
567 | /// The length of the output of SHA-512/256, in bytes. |
568 | pub const SHA512_256_OUTPUT_LEN: usize = OutputLen::_256.into(); |
569 | |
570 | #[derive (Clone, Copy)] |
571 | enum BlockLen { |
572 | _512 = 512 / 8, |
573 | _1024 = 1024 / 8, // MAX |
574 | } |
575 | |
576 | impl BlockLen { |
577 | const MAX: Self = Self::_1024; |
578 | #[inline (always)] |
579 | const fn into(self) -> usize { |
580 | self as usize |
581 | } |
582 | |
583 | #[inline (always)] |
584 | const fn len_len(self) -> usize { |
585 | let len_len: LenLen = match self { |
586 | BlockLen::_512 => LenLen::_64, |
587 | BlockLen::_1024 => LenLen::_128, |
588 | }; |
589 | len_len as usize |
590 | } |
591 | } |
592 | |
593 | #[derive (Clone, Copy)] |
594 | enum LenLen { |
595 | _64 = 64 / 8, |
596 | _128 = 128 / 8, |
597 | } |
598 | |
599 | #[derive (Clone, Copy)] |
600 | enum OutputLen { |
601 | _160 = 160 / 8, |
602 | _256 = 256 / 8, |
603 | _384 = 384 / 8, |
604 | _512 = 512 / 8, // MAX |
605 | } |
606 | |
607 | impl OutputLen { |
608 | const MAX: Self = Self::_512; |
609 | |
610 | #[inline (always)] |
611 | const fn into(self) -> usize { |
612 | self as usize |
613 | } |
614 | } |
615 | |
616 | #[cfg (test)] |
617 | mod tests { |
618 | mod max_input { |
619 | extern crate alloc; |
620 | use super::super::super::digest; |
621 | use crate::polyfill::u64_from_usize; |
622 | use alloc::vec; |
623 | |
624 | macro_rules! max_input_tests { |
625 | ( $algorithm_name:ident ) => { |
626 | mod $algorithm_name { |
627 | use super::super::super::super::digest; |
628 | |
629 | #[test] |
630 | fn max_input_test() { |
631 | super::max_input_test(&digest::$algorithm_name); |
632 | } |
633 | |
634 | #[test] |
635 | #[should_panic] |
636 | fn too_long_input_test_block() { |
637 | super::too_long_input_test_block(&digest::$algorithm_name); |
638 | } |
639 | |
640 | #[test] |
641 | #[should_panic] |
642 | fn too_long_input_test_byte() { |
643 | super::too_long_input_test_byte(&digest::$algorithm_name); |
644 | } |
645 | } |
646 | }; |
647 | } |
648 | |
649 | fn max_input_test(alg: &'static digest::Algorithm) { |
650 | let mut context = nearly_full_context(alg); |
651 | let next_input = vec![0u8; alg.block_len() - 1]; |
652 | context.update(&next_input); |
653 | let _ = context.finish(); // no panic |
654 | } |
655 | |
656 | fn too_long_input_test_block(alg: &'static digest::Algorithm) { |
657 | let mut context = nearly_full_context(alg); |
658 | let next_input = vec![0u8; alg.block_len()]; |
659 | context.update(&next_input); |
660 | let _ = context.finish(); // should panic |
661 | } |
662 | |
663 | fn too_long_input_test_byte(alg: &'static digest::Algorithm) { |
664 | let mut context = nearly_full_context(alg); |
665 | let next_input = vec![0u8; alg.block_len() - 1]; |
666 | context.update(&next_input); |
667 | context.update(&[0]); |
668 | let _ = context.finish(); // should panic |
669 | } |
670 | |
671 | fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context { |
672 | // All implementations currently support up to 2^64-1 bits |
673 | // of input; according to the spec, SHA-384 and SHA-512 |
674 | // support up to 2^128-1, but that's not implemented yet. |
675 | let max_bytes = 1u64 << (64 - 3); |
676 | let max_blocks = max_bytes / u64_from_usize(alg.block_len()); |
677 | let completed_bytes = (max_blocks - 1) * u64_from_usize(alg.block_len()); |
678 | digest::Context { |
679 | block: digest::BlockContext { |
680 | state: alg.initial_state.clone(), |
681 | completed_bytes, |
682 | algorithm: alg, |
683 | }, |
684 | pending: [0u8; digest::MAX_BLOCK_LEN], |
685 | num_pending: 0, |
686 | } |
687 | } |
688 | |
689 | max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY); |
690 | max_input_tests!(SHA256); |
691 | max_input_tests!(SHA384); |
692 | max_input_tests!(SHA512); |
693 | } |
694 | } |
695 | |