/rust/registry/src/index.crates.io-6f17d22bba15001f/ring-0.17.14/src/digest.rs
Line | Count | Source (jump to first uncovered line) |
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 AUTHOR DISCLAIMS ALL WARRANTIES |
8 | | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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 | 0 | pub(crate) fn new(algorithm: &'static Algorithm) -> Self { |
53 | 0 | Self { |
54 | 0 | state: algorithm.initial_state.clone(), |
55 | 0 | completed_bytes: 0, |
56 | 0 | algorithm, |
57 | 0 | } |
58 | 0 | } |
59 | | |
60 | | /// Processes all the full blocks in `input`, returning the partial block |
61 | | /// at the end, which may be empty. |
62 | 0 | pub(crate) fn update<'i>(&mut self, input: &'i [u8], cpu_features: cpu::Features) -> &'i [u8] { |
63 | 0 | let (completed_bytes, leftover) = self.block_data_order(input, cpu_features); |
64 | 0 | // Using saturated addition here allows `update` to be infallible and |
65 | 0 | // panic-free. If we were to reach the maximum value here then `finish` |
66 | 0 | // will detect that we processed too much data when it converts this to |
67 | 0 | // a bit length. |
68 | 0 | self.completed_bytes = self |
69 | 0 | .completed_bytes |
70 | 0 | .saturating_add(polyfill::u64_from_usize(completed_bytes)); |
71 | 0 | leftover |
72 | 0 | } |
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 | 0 | pub(crate) fn try_finish( |
80 | 0 | mut self, |
81 | 0 | block: &mut [u8; MAX_BLOCK_LEN], |
82 | 0 | num_pending: usize, |
83 | 0 | cpu_features: cpu::Features, |
84 | 0 | ) -> Result<Digest, FinishError> { |
85 | 0 | let completed_bits = self |
86 | 0 | .completed_bytes |
87 | 0 | .checked_add(polyfill::u64_from_usize(num_pending)) |
88 | 0 | .ok_or_else(|| { |
89 | 0 | // Choosing self.completed_bytes here is lossy & somewhat arbitrary. |
90 | 0 | InputTooLongError::new(self.completed_bytes) |
91 | 0 | }) |
92 | 0 | .and_then(BitLength::from_byte_len) |
93 | 0 | .map_err(FinishError::input_too_long)?; |
94 | | |
95 | 0 | let block_len = self.algorithm.block_len(); |
96 | 0 | let block = &mut block[..block_len]; |
97 | | |
98 | 0 | let padding = match block.get_mut(num_pending..) { |
99 | 0 | Some([separator, padding @ ..]) => { |
100 | 0 | *separator = 0x80; |
101 | 0 | padding |
102 | | } |
103 | | // Precondition violated. |
104 | 0 | unreachable => { |
105 | 0 | return Err(FinishError::pending_not_a_partial_block( |
106 | 0 | unreachable.as_deref(), |
107 | 0 | )); |
108 | | } |
109 | | }; |
110 | | |
111 | 0 | let padding = match padding |
112 | 0 | .len() |
113 | 0 | .checked_sub(self.algorithm.block_len.len_len()) |
114 | | { |
115 | 0 | Some(_) => padding, |
116 | | None => { |
117 | 0 | padding.fill(0); |
118 | 0 | let (completed_bytes, leftover) = self.block_data_order(block, cpu_features); |
119 | 0 | 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 | 0 | &mut block[..] |
123 | | } |
124 | | }; |
125 | | |
126 | 0 | let (to_zero, len) = padding.split_at_mut(padding.len() - 8); |
127 | 0 | to_zero.fill(0); |
128 | 0 | len.copy_from_slice(&completed_bits.to_be_bytes()); |
129 | 0 |
|
130 | 0 | let (completed_bytes, leftover) = self.block_data_order(block, cpu_features); |
131 | 0 | debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0)); |
132 | | |
133 | 0 | Ok(Digest { |
134 | 0 | algorithm: self.algorithm, |
135 | 0 | value: self.state.format_output(), |
136 | 0 | }) |
137 | 0 | } |
138 | | |
139 | | #[must_use] |
140 | 0 | fn block_data_order<'d>( |
141 | 0 | &mut self, |
142 | 0 | data: &'d [u8], |
143 | 0 | cpu_features: cpu::Features, |
144 | 0 | ) -> (usize, &'d [u8]) { |
145 | 0 | (self.algorithm.block_data_order)(&mut self.state, data, cpu_features) |
146 | 0 | } |
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 | 0 | fn pending_not_a_partial_block(padding: Option<&[u8]>) -> Self { |
162 | 0 | match padding { |
163 | 0 | None => Self::pending_not_a_partial_block_inner(0), |
164 | 0 | Some(padding) => Self::pending_not_a_partial_block_inner(padding.len()), |
165 | | } |
166 | 0 | } |
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 | 0 | pub fn new(algorithm: &'static Algorithm) -> Self { |
199 | 0 | Self { |
200 | 0 | block: BlockContext::new(algorithm), |
201 | 0 | pending: [0u8; MAX_BLOCK_LEN], |
202 | 0 | num_pending: 0, |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | 0 | pub(crate) fn clone_from(block: &BlockContext) -> Self { |
207 | 0 | Self { |
208 | 0 | block: block.clone(), |
209 | 0 | pending: [0u8; MAX_BLOCK_LEN], |
210 | 0 | num_pending: 0, |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | /// Updates the digest with all the data in `data`. |
215 | 0 | pub fn update(&mut self, data: &[u8]) { |
216 | 0 | let cpu_features = cpu::features(); |
217 | 0 |
|
218 | 0 | let block_len = self.block.algorithm.block_len(); |
219 | 0 | let buffer = &mut self.pending[..block_len]; |
220 | | |
221 | 0 | let to_digest = if self.num_pending == 0 { |
222 | 0 | data |
223 | | } else { |
224 | 0 | let buffer_to_fill = match buffer.get_mut(self.num_pending..) { |
225 | 0 | Some(buffer_to_fill) => buffer_to_fill, |
226 | | None => { |
227 | | // Impossible because of the invariant. |
228 | 0 | unreachable!(); |
229 | | } |
230 | | }; |
231 | 0 | sliceutil::overwrite_at_start(buffer_to_fill, data); |
232 | 0 | match slice::split_at_checked(data, buffer_to_fill.len()) { |
233 | 0 | Some((just_copied, to_digest)) => { |
234 | 0 | debug_assert_eq!(buffer_to_fill.len(), just_copied.len()); |
235 | 0 | debug_assert_eq!(self.num_pending + just_copied.len(), block_len); |
236 | 0 | let leftover = self.block.update(buffer, cpu_features); |
237 | 0 | debug_assert_eq!(leftover.len(), 0); |
238 | 0 | self.num_pending = 0; |
239 | 0 | to_digest |
240 | | } |
241 | | None => { |
242 | 0 | self.num_pending += data.len(); |
243 | 0 | // If `data` isn't enough to complete a block, buffer it and stop. |
244 | 0 | debug_assert!(self.num_pending < block_len); |
245 | 0 | return; |
246 | | } |
247 | | } |
248 | | }; |
249 | | |
250 | 0 | let leftover = self.block.update(to_digest, cpu_features); |
251 | 0 | sliceutil::overwrite_at_start(buffer, leftover); |
252 | 0 | self.num_pending = leftover.len(); |
253 | 0 | debug_assert!(self.num_pending < block_len); |
254 | 0 | } |
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 | 0 | pub fn finish(self) -> Digest { |
261 | 0 | let cpu = cpu::features(); |
262 | 0 | self.try_finish(cpu) |
263 | 0 | .map_err(error::erase::<InputTooLongError>) |
264 | 0 | .unwrap() |
265 | 0 | } |
266 | | |
267 | 0 | pub(crate) fn try_finish( |
268 | 0 | mut self, |
269 | 0 | cpu_features: cpu::Features, |
270 | 0 | ) -> Result<Digest, InputTooLongError> { |
271 | 0 | self.block |
272 | 0 | .try_finish(&mut self.pending, self.num_pending, cpu_features) |
273 | 0 | .map_err(|err| match err { |
274 | 0 | FinishError::InputTooLong(i) => i, |
275 | | FinishError::PendingNotAPartialBlock(_) => { |
276 | | // Due to invariant. |
277 | 0 | unreachable!() |
278 | | } |
279 | 0 | }) |
280 | 0 | } |
281 | | |
282 | | /// The algorithm that this context is using. |
283 | | #[inline(always)] |
284 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
285 | 0 | self.block.algorithm |
286 | 0 | } |
287 | | } |
288 | | |
289 | | /// Returns the digest of `data` using the given digest algorithm. |
290 | 0 | pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest { |
291 | 0 | let cpu = cpu::features(); |
292 | 0 | Digest::compute_from(algorithm, data, cpu) |
293 | 0 | .map_err(error::erase::<InputTooLongError>) |
294 | 0 | .unwrap() |
295 | 0 | } |
296 | | |
297 | | /// A calculated digest value. |
298 | | /// |
299 | | /// Use [`Self::as_ref`] to get the value as a `&[u8]`. |
300 | | #[derive(Clone, Copy)] |
301 | | pub struct Digest { |
302 | | value: Output, |
303 | | algorithm: &'static Algorithm, |
304 | | } |
305 | | |
306 | | impl Digest { |
307 | 0 | pub(crate) fn compute_from( |
308 | 0 | algorithm: &'static Algorithm, |
309 | 0 | data: &[u8], |
310 | 0 | cpu: cpu::Features, |
311 | 0 | ) -> Result<Self, InputTooLongError> { |
312 | 0 | let mut ctx = Context::new(algorithm); |
313 | 0 | ctx.update(data); |
314 | 0 | ctx.try_finish(cpu) |
315 | 0 | } |
316 | | |
317 | | /// The algorithm that was used to calculate the digest value. |
318 | | #[inline(always)] |
319 | 0 | pub fn algorithm(&self) -> &'static Algorithm { |
320 | 0 | self.algorithm |
321 | 0 | } |
322 | | } |
323 | | |
324 | | impl AsRef<[u8]> for Digest { |
325 | | #[inline(always)] |
326 | 0 | fn as_ref(&self) -> &[u8] { |
327 | 0 | &self.value.0[..self.algorithm.output_len()] |
328 | 0 | } |
329 | | } |
330 | | |
331 | | impl core::fmt::Debug for Digest { |
332 | 0 | fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { |
333 | 0 | write!(fmt, "{:?}:", self.algorithm)?; |
334 | 0 | debug::write_hex_bytes(fmt, self.as_ref()) |
335 | 0 | } |
336 | | } |
337 | | |
338 | | /// A digest algorithm. |
339 | | pub struct Algorithm { |
340 | | output_len: OutputLen, |
341 | | chaining_len: usize, |
342 | | block_len: BlockLen, |
343 | | |
344 | | /// `block_data_order` processes all the full blocks of data in `data`. It |
345 | | /// returns the number of bytes processed and the unprocessed data, which |
346 | | /// is guaranteed to be less than `block_len` bytes long. |
347 | | block_data_order: for<'d> fn( |
348 | | state: &mut DynState, |
349 | | data: &'d [u8], |
350 | | cpu_features: cpu::Features, |
351 | | ) -> (usize, &'d [u8]), |
352 | | |
353 | | initial_state: DynState, |
354 | | |
355 | | id: AlgorithmID, |
356 | | } |
357 | | |
358 | | #[derive(Debug, Eq, PartialEq)] |
359 | | enum AlgorithmID { |
360 | | SHA1, |
361 | | SHA256, |
362 | | SHA384, |
363 | | SHA512, |
364 | | SHA512_256, |
365 | | } |
366 | | |
367 | | impl PartialEq for Algorithm { |
368 | 0 | fn eq(&self, other: &Self) -> bool { |
369 | 0 | self.id == other.id |
370 | 0 | } |
371 | | } |
372 | | |
373 | | impl Eq for Algorithm {} |
374 | | |
375 | | derive_debug_via_id!(Algorithm); |
376 | | |
377 | | impl Algorithm { |
378 | | /// The internal block length. |
379 | 0 | pub fn block_len(&self) -> usize { |
380 | 0 | self.block_len.into() |
381 | 0 | } |
382 | | |
383 | | /// The size of the chaining value of the digest function, in bytes. |
384 | | /// |
385 | | /// For non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal |
386 | | /// to [`Self::output_len()`]. For truncated algorithms (e.g. SHA-384, |
387 | | /// SHA-512/256), this is equal to the length before truncation. This is |
388 | | /// mostly helpful for determining the size of an HMAC key that is |
389 | | /// appropriate for the digest algorithm. |
390 | 0 | pub fn chaining_len(&self) -> usize { |
391 | 0 | self.chaining_len |
392 | 0 | } |
393 | | |
394 | | /// The length of a finalized digest. |
395 | 0 | pub fn output_len(&self) -> usize { |
396 | 0 | self.output_len.into() |
397 | 0 | } |
398 | | } |
399 | | |
400 | | /// SHA-1 as specified in [FIPS 180-4]. Deprecated. |
401 | | /// |
402 | | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
403 | | pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm { |
404 | | output_len: sha1::OUTPUT_LEN, |
405 | | chaining_len: sha1::CHAINING_LEN, |
406 | | block_len: sha1::BLOCK_LEN, |
407 | | block_data_order: dynstate::sha1_block_data_order, |
408 | | initial_state: DynState::new32([ |
409 | | Wrapping(0x67452301u32), |
410 | | Wrapping(0xefcdab89u32), |
411 | | Wrapping(0x98badcfeu32), |
412 | | Wrapping(0x10325476u32), |
413 | | Wrapping(0xc3d2e1f0u32), |
414 | | Wrapping(0), |
415 | | Wrapping(0), |
416 | | Wrapping(0), |
417 | | ]), |
418 | | id: AlgorithmID::SHA1, |
419 | | }; |
420 | | |
421 | | /// SHA-256 as specified in [FIPS 180-4]. |
422 | | /// |
423 | | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
424 | | pub static SHA256: Algorithm = Algorithm { |
425 | | output_len: OutputLen::_256, |
426 | | chaining_len: SHA256_OUTPUT_LEN, |
427 | | block_len: SHA256_BLOCK_LEN, |
428 | | block_data_order: dynstate::sha256_block_data_order, |
429 | | initial_state: DynState::new32([ |
430 | | Wrapping(0x6a09e667u32), |
431 | | Wrapping(0xbb67ae85u32), |
432 | | Wrapping(0x3c6ef372u32), |
433 | | Wrapping(0xa54ff53au32), |
434 | | Wrapping(0x510e527fu32), |
435 | | Wrapping(0x9b05688cu32), |
436 | | Wrapping(0x1f83d9abu32), |
437 | | Wrapping(0x5be0cd19u32), |
438 | | ]), |
439 | | id: AlgorithmID::SHA256, |
440 | | }; |
441 | | |
442 | | /// SHA-384 as specified in [FIPS 180-4]. |
443 | | /// |
444 | | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
445 | | pub static SHA384: Algorithm = Algorithm { |
446 | | output_len: OutputLen::_384, |
447 | | chaining_len: SHA512_OUTPUT_LEN, |
448 | | block_len: SHA512_BLOCK_LEN, |
449 | | block_data_order: dynstate::sha512_block_data_order, |
450 | | initial_state: DynState::new64([ |
451 | | Wrapping(0xcbbb9d5dc1059ed8), |
452 | | Wrapping(0x629a292a367cd507), |
453 | | Wrapping(0x9159015a3070dd17), |
454 | | Wrapping(0x152fecd8f70e5939), |
455 | | Wrapping(0x67332667ffc00b31), |
456 | | Wrapping(0x8eb44a8768581511), |
457 | | Wrapping(0xdb0c2e0d64f98fa7), |
458 | | Wrapping(0x47b5481dbefa4fa4), |
459 | | ]), |
460 | | id: AlgorithmID::SHA384, |
461 | | }; |
462 | | |
463 | | /// SHA-512 as specified in [FIPS 180-4]. |
464 | | /// |
465 | | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
466 | | pub static SHA512: Algorithm = Algorithm { |
467 | | output_len: OutputLen::_512, |
468 | | chaining_len: SHA512_OUTPUT_LEN, |
469 | | block_len: SHA512_BLOCK_LEN, |
470 | | block_data_order: dynstate::sha512_block_data_order, |
471 | | initial_state: DynState::new64([ |
472 | | Wrapping(0x6a09e667f3bcc908), |
473 | | Wrapping(0xbb67ae8584caa73b), |
474 | | Wrapping(0x3c6ef372fe94f82b), |
475 | | Wrapping(0xa54ff53a5f1d36f1), |
476 | | Wrapping(0x510e527fade682d1), |
477 | | Wrapping(0x9b05688c2b3e6c1f), |
478 | | Wrapping(0x1f83d9abfb41bd6b), |
479 | | Wrapping(0x5be0cd19137e2179), |
480 | | ]), |
481 | | id: AlgorithmID::SHA512, |
482 | | }; |
483 | | |
484 | | /// SHA-512/256 as specified in [FIPS 180-4]. |
485 | | /// |
486 | | /// This is *not* the same as just truncating the output of SHA-512, as |
487 | | /// SHA-512/256 has its own initial state distinct from SHA-512's initial |
488 | | /// state. |
489 | | /// |
490 | | /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf |
491 | | pub static SHA512_256: Algorithm = Algorithm { |
492 | | output_len: OutputLen::_256, |
493 | | chaining_len: SHA512_OUTPUT_LEN, |
494 | | block_len: SHA512_BLOCK_LEN, |
495 | | block_data_order: dynstate::sha512_block_data_order, |
496 | | initial_state: DynState::new64([ |
497 | | Wrapping(0x22312194fc2bf72c), |
498 | | Wrapping(0x9f555fa3c84c64c2), |
499 | | Wrapping(0x2393b86b6f53b151), |
500 | | Wrapping(0x963877195940eabd), |
501 | | Wrapping(0x96283ee2a88effe3), |
502 | | Wrapping(0xbe5e1e2553863992), |
503 | | Wrapping(0x2b0199fc2c85b8aa), |
504 | | Wrapping(0x0eb72ddc81c52ca2), |
505 | | ]), |
506 | | id: AlgorithmID::SHA512_256, |
507 | | }; |
508 | | |
509 | | #[derive(Clone, Copy)] |
510 | | struct Output([u8; MAX_OUTPUT_LEN]); |
511 | | |
512 | | /// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms |
513 | | /// in this module. |
514 | | pub const MAX_BLOCK_LEN: usize = BlockLen::MAX.into(); |
515 | | |
516 | | /// The maximum output length ([`Algorithm::output_len()`]) of all the |
517 | | /// algorithms in this module. |
518 | | pub const MAX_OUTPUT_LEN: usize = OutputLen::MAX.into(); |
519 | | |
520 | | /// The maximum chaining length ([`Algorithm::chaining_len()`]) of all the |
521 | | /// algorithms in this module. |
522 | | pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN; |
523 | | |
524 | | #[inline] |
525 | 0 | fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output |
526 | 0 | where |
527 | 0 | F: Fn(T) -> [u8; N], |
528 | 0 | T: Copy, |
529 | 0 | { |
530 | 0 | let mut output = Output([0; MAX_OUTPUT_LEN]); |
531 | 0 | output |
532 | 0 | .0 |
533 | 0 | .chunks_mut(N) |
534 | 0 | .zip(input.iter().copied().map(|Wrapping(w)| f(w))) Unexecuted instantiation: ring::digest::format_output::<u32, <u32>::to_be_bytes, 4>::{closure#0} Unexecuted instantiation: ring::digest::format_output::<u64, <u64>::to_be_bytes, 8>::{closure#0} |
535 | 0 | .for_each(|(o, i)| { |
536 | 0 | o.copy_from_slice(&i); |
537 | 0 | }); Unexecuted instantiation: ring::digest::format_output::<u32, <u32>::to_be_bytes, 4>::{closure#1} Unexecuted instantiation: ring::digest::format_output::<u64, <u64>::to_be_bytes, 8>::{closure#1} |
538 | 0 | output |
539 | 0 | } Unexecuted instantiation: ring::digest::format_output::<u32, <u32>::to_be_bytes, 4> Unexecuted instantiation: ring::digest::format_output::<u64, <u64>::to_be_bytes, 8> |
540 | | |
541 | | /// The length of the output of SHA-1, in bytes. |
542 | | pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN.into(); |
543 | | |
544 | | /// The length of the output of SHA-256, in bytes. |
545 | | pub const SHA256_OUTPUT_LEN: usize = OutputLen::_256.into(); |
546 | | |
547 | | /// The length of the output of SHA-384, in bytes. |
548 | | pub const SHA384_OUTPUT_LEN: usize = OutputLen::_384.into(); |
549 | | |
550 | | /// The length of the output of SHA-512, in bytes. |
551 | | pub const SHA512_OUTPUT_LEN: usize = OutputLen::_512.into(); |
552 | | |
553 | | /// The length of the output of SHA-512/256, in bytes. |
554 | | pub const SHA512_256_OUTPUT_LEN: usize = OutputLen::_256.into(); |
555 | | |
556 | | #[derive(Clone, Copy)] |
557 | | enum BlockLen { |
558 | | _512 = 512 / 8, |
559 | | _1024 = 1024 / 8, // MAX |
560 | | } |
561 | | |
562 | | impl BlockLen { |
563 | | const MAX: Self = Self::_1024; |
564 | | #[inline(always)] |
565 | 0 | const fn into(self) -> usize { |
566 | 0 | self as usize |
567 | 0 | } |
568 | | |
569 | | #[inline(always)] |
570 | 0 | const fn len_len(self) -> usize { |
571 | 0 | let len_len = match self { |
572 | 0 | BlockLen::_512 => LenLen::_64, |
573 | 0 | BlockLen::_1024 => LenLen::_128, |
574 | | }; |
575 | 0 | len_len as usize |
576 | 0 | } |
577 | | } |
578 | | |
579 | | #[derive(Clone, Copy)] |
580 | | enum LenLen { |
581 | | _64 = 64 / 8, |
582 | | _128 = 128 / 8, |
583 | | } |
584 | | |
585 | | #[derive(Clone, Copy)] |
586 | | enum OutputLen { |
587 | | _160 = 160 / 8, |
588 | | _256 = 256 / 8, |
589 | | _384 = 384 / 8, |
590 | | _512 = 512 / 8, // MAX |
591 | | } |
592 | | |
593 | | impl OutputLen { |
594 | | const MAX: Self = Self::_512; |
595 | | |
596 | | #[inline(always)] |
597 | 0 | const fn into(self) -> usize { |
598 | 0 | self as usize |
599 | 0 | } |
600 | | } |
601 | | |
602 | | #[cfg(test)] |
603 | | mod tests { |
604 | | mod max_input { |
605 | | extern crate alloc; |
606 | | use super::super::super::digest; |
607 | | use crate::polyfill::u64_from_usize; |
608 | | use alloc::vec; |
609 | | |
610 | | macro_rules! max_input_tests { |
611 | | ( $algorithm_name:ident ) => { |
612 | | mod $algorithm_name { |
613 | | use super::super::super::super::digest; |
614 | | |
615 | | #[test] |
616 | | fn max_input_test() { |
617 | | super::max_input_test(&digest::$algorithm_name); |
618 | | } |
619 | | |
620 | | #[test] |
621 | | #[should_panic] |
622 | | fn too_long_input_test_block() { |
623 | | super::too_long_input_test_block(&digest::$algorithm_name); |
624 | | } |
625 | | |
626 | | #[test] |
627 | | #[should_panic] |
628 | | fn too_long_input_test_byte() { |
629 | | super::too_long_input_test_byte(&digest::$algorithm_name); |
630 | | } |
631 | | } |
632 | | }; |
633 | | } |
634 | | |
635 | | fn max_input_test(alg: &'static digest::Algorithm) { |
636 | | let mut context = nearly_full_context(alg); |
637 | | let next_input = vec![0u8; alg.block_len() - 1]; |
638 | | context.update(&next_input); |
639 | | let _ = context.finish(); // no panic |
640 | | } |
641 | | |
642 | | fn too_long_input_test_block(alg: &'static digest::Algorithm) { |
643 | | let mut context = nearly_full_context(alg); |
644 | | let next_input = vec![0u8; alg.block_len()]; |
645 | | context.update(&next_input); |
646 | | let _ = context.finish(); // should panic |
647 | | } |
648 | | |
649 | | fn too_long_input_test_byte(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 | | context.update(&[0]); |
654 | | let _ = context.finish(); // should panic |
655 | | } |
656 | | |
657 | | fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context { |
658 | | // All implementations currently support up to 2^64-1 bits |
659 | | // of input; according to the spec, SHA-384 and SHA-512 |
660 | | // support up to 2^128-1, but that's not implemented yet. |
661 | | let max_bytes = 1u64 << (64 - 3); |
662 | | let max_blocks = max_bytes / u64_from_usize(alg.block_len()); |
663 | | let completed_bytes = (max_blocks - 1) * u64_from_usize(alg.block_len()); |
664 | | digest::Context { |
665 | | block: digest::BlockContext { |
666 | | state: alg.initial_state.clone(), |
667 | | completed_bytes, |
668 | | algorithm: alg, |
669 | | }, |
670 | | pending: [0u8; digest::MAX_BLOCK_LEN], |
671 | | num_pending: 0, |
672 | | } |
673 | | } |
674 | | |
675 | | max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY); |
676 | | max_input_tests!(SHA256); |
677 | | max_input_tests!(SHA384); |
678 | | max_input_tests!(SHA512); |
679 | | } |
680 | | } |