/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ring-0.17.14/src/digest.rs
Line  | Count  | Source  | 
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  |  |         // 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  | 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  |  |                 // 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  |  |  | 
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  |  |  | 
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  |  |                     // 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  |  | { | 
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  |  | }  |