• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Note on why are we doing things the hard way: It would be easy to implement
22 // this using the C `EVP_MD`/`EVP_MD_CTX` interface. However, if we were to do
23 // things that way, we'd have a hard dependency on `malloc` and other overhead.
24 // The goal for this implementation is to drive the overhead as close to zero
25 // as possible.
26 
27 use crate::polyfill::array_map::Map;
28 use crate::{
29     c, cpu, debug,
30     endian::{ArrayEncoding, BigEndian},
31     polyfill,
32 };
33 use core::num::Wrapping;
34 
35 mod sha1;
36 mod sha2;
37 
38 #[derive(Clone)]
39 pub(crate) struct BlockContext {
40     state: State,
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_data_blocks: u64,
46 
47     /// The context's algorithm.
48     pub algorithm: &'static Algorithm,
49 
50     cpu_features: cpu::Features,
51 }
52 
53 impl BlockContext {
new(algorithm: &'static Algorithm) -> Self54     pub(crate) fn new(algorithm: &'static Algorithm) -> Self {
55         Self {
56             state: algorithm.initial_state,
57             completed_data_blocks: 0,
58             algorithm,
59             cpu_features: cpu::features(),
60         }
61     }
62 
63     #[inline]
update(&mut self, input: &[u8])64     pub(crate) fn update(&mut self, input: &[u8]) {
65         let num_blocks = input.len() / self.algorithm.block_len;
66         assert_eq!(num_blocks * self.algorithm.block_len, input.len());
67 
68         if num_blocks > 0 {
69             let _cpu_features = self.cpu_features;
70             unsafe {
71                 (self.algorithm.block_data_order)(&mut self.state, input.as_ptr(), num_blocks);
72             }
73             self.completed_data_blocks = self
74                 .completed_data_blocks
75                 .checked_add(polyfill::u64_from_usize(num_blocks))
76                 .unwrap();
77         }
78     }
79 
finish(mut self, pending: &mut [u8], num_pending: usize) -> Digest80     pub(crate) fn finish(mut self, pending: &mut [u8], num_pending: usize) -> Digest {
81         let block_len = self.algorithm.block_len;
82         assert_eq!(pending.len(), block_len);
83         assert!(num_pending <= pending.len());
84 
85         let mut padding_pos = num_pending;
86         pending[padding_pos] = 0x80;
87         padding_pos += 1;
88 
89         if padding_pos > block_len - self.algorithm.len_len {
90             polyfill::slice::fill(&mut pending[padding_pos..block_len], 0);
91             unsafe {
92                 (self.algorithm.block_data_order)(&mut self.state, pending.as_ptr(), 1);
93             }
94             // We don't increase |self.completed_data_blocks| because the
95             // padding isn't data, and so it isn't included in the data length.
96             padding_pos = 0;
97         }
98 
99         polyfill::slice::fill(&mut pending[padding_pos..(block_len - 8)], 0);
100 
101         // Output the length, in bits, in big endian order.
102         let completed_data_bits = self
103             .completed_data_blocks
104             .checked_mul(polyfill::u64_from_usize(block_len))
105             .unwrap()
106             .checked_add(polyfill::u64_from_usize(num_pending))
107             .unwrap()
108             .checked_mul(8)
109             .unwrap();
110         pending[(block_len - 8)..block_len].copy_from_slice(&u64::to_be_bytes(completed_data_bits));
111 
112         unsafe {
113             (self.algorithm.block_data_order)(&mut self.state, pending.as_ptr(), 1);
114         }
115 
116         Digest {
117             algorithm: self.algorithm,
118             value: (self.algorithm.format_output)(self.state),
119         }
120     }
121 }
122 
123 /// A context for multi-step (Init-Update-Finish) digest calculations.
124 ///
125 /// # Examples
126 ///
127 /// ```
128 /// use ring::digest;
129 ///
130 /// let one_shot = digest::digest(&digest::SHA384, b"hello, world");
131 ///
132 /// let mut ctx = digest::Context::new(&digest::SHA384);
133 /// ctx.update(b"hello");
134 /// ctx.update(b", ");
135 /// ctx.update(b"world");
136 /// let multi_part = ctx.finish();
137 ///
138 /// assert_eq!(&one_shot.as_ref(), &multi_part.as_ref());
139 /// ```
140 #[derive(Clone)]
141 pub struct Context {
142     block: BlockContext,
143     // TODO: More explicitly force 64-bit alignment for |pending|.
144     pending: [u8; MAX_BLOCK_LEN],
145     num_pending: usize,
146 }
147 
148 impl Context {
149     /// Constructs a new context.
new(algorithm: &'static Algorithm) -> Self150     pub fn new(algorithm: &'static Algorithm) -> Self {
151         Self {
152             block: BlockContext::new(algorithm),
153             pending: [0u8; MAX_BLOCK_LEN],
154             num_pending: 0,
155         }
156     }
157 
clone_from(block: &BlockContext) -> Self158     pub(crate) fn clone_from(block: &BlockContext) -> Self {
159         Self {
160             block: block.clone(),
161             pending: [0u8; MAX_BLOCK_LEN],
162             num_pending: 0,
163         }
164     }
165 
166     /// Updates the digest with all the data in `data`. `update` may be called
167     /// zero or more times until `finish` is called. It must not be called
168     /// after `finish` has been called.
update(&mut self, data: &[u8])169     pub fn update(&mut self, data: &[u8]) {
170         let block_len = self.block.algorithm.block_len;
171         if data.len() < block_len - self.num_pending {
172             self.pending[self.num_pending..(self.num_pending + data.len())].copy_from_slice(data);
173             self.num_pending += data.len();
174             return;
175         }
176 
177         let mut remaining = data;
178         if self.num_pending > 0 {
179             let to_copy = block_len - self.num_pending;
180             self.pending[self.num_pending..block_len].copy_from_slice(&data[..to_copy]);
181             self.block.update(&self.pending[..block_len]);
182             remaining = &remaining[to_copy..];
183             self.num_pending = 0;
184         }
185 
186         let num_blocks = remaining.len() / block_len;
187         let num_to_save_for_later = remaining.len() % block_len;
188         self.block.update(&remaining[..(num_blocks * block_len)]);
189         if num_to_save_for_later > 0 {
190             self.pending[..num_to_save_for_later]
191                 .copy_from_slice(&remaining[(remaining.len() - num_to_save_for_later)..]);
192             self.num_pending = num_to_save_for_later;
193         }
194     }
195 
196     /// Finalizes the digest calculation and returns the digest value. `finish`
197     /// consumes the context so it cannot be (mis-)used after `finish` has been
198     /// called.
finish(mut self) -> Digest199     pub fn finish(mut self) -> Digest {
200         let block_len = self.block.algorithm.block_len;
201         self.block
202             .finish(&mut self.pending[..block_len], self.num_pending)
203     }
204 
205     /// The algorithm that this context is using.
206     #[inline(always)]
algorithm(&self) -> &'static Algorithm207     pub fn algorithm(&self) -> &'static Algorithm {
208         self.block.algorithm
209     }
210 }
211 
212 /// Returns the digest of `data` using the given digest algorithm.
213 ///
214 /// # Examples:
215 ///
216 /// ```
217 /// # #[cfg(feature = "alloc")]
218 /// # {
219 /// use ring::{digest, test};
220 /// let expected_hex = "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b";
221 /// let expected: Vec<u8> = test::from_hex(expected_hex).unwrap();
222 /// let actual = digest::digest(&digest::SHA256, b"hello, world");
223 ///
224 /// assert_eq!(&expected, &actual.as_ref());
225 /// # }
226 /// ```
digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest227 pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
228     let mut ctx = Context::new(algorithm);
229     ctx.update(data);
230     ctx.finish()
231 }
232 
233 /// A calculated digest value.
234 ///
235 /// Use `as_ref` to get the value as a `&[u8]`.
236 #[derive(Clone, Copy)]
237 pub struct Digest {
238     value: Output,
239     algorithm: &'static Algorithm,
240 }
241 
242 impl Digest {
243     /// The algorithm that was used to calculate the digest value.
244     #[inline(always)]
algorithm(&self) -> &'static Algorithm245     pub fn algorithm(&self) -> &'static Algorithm {
246         self.algorithm
247     }
248 }
249 
250 impl AsRef<[u8]> for Digest {
251     #[inline(always)]
as_ref(&self) -> &[u8]252     fn as_ref(&self) -> &[u8] {
253         let as64 = unsafe { &self.value.as64 };
254         &as64.as_byte_array()[..self.algorithm.output_len]
255     }
256 }
257 
258 impl core::fmt::Debug for Digest {
fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result259     fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
260         write!(fmt, "{:?}:", self.algorithm)?;
261         debug::write_hex_bytes(fmt, self.as_ref())
262     }
263 }
264 
265 /// A digest algorithm.
266 pub struct Algorithm {
267     /// The length of a finalized digest.
268     pub output_len: usize,
269 
270     /// The size of the chaining value of the digest function, in bytes. For
271     /// non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal to
272     /// `output_len`. For truncated algorithms (e.g. SHA-384, SHA-512/256),
273     /// this is equal to the length before truncation. This is mostly helpful
274     /// for determining the size of an HMAC key that is appropriate for the
275     /// digest algorithm.
276     pub chaining_len: usize,
277 
278     /// The internal block length.
279     pub block_len: usize,
280 
281     /// The length of the length in the padding.
282     len_len: usize,
283 
284     block_data_order: unsafe extern "C" fn(state: &mut State, data: *const u8, num: c::size_t),
285     format_output: fn(input: State) -> Output,
286 
287     initial_state: State,
288 
289     id: AlgorithmID,
290 }
291 
292 #[derive(Debug, Eq, PartialEq)]
293 enum AlgorithmID {
294     SHA1,
295     SHA256,
296     SHA384,
297     SHA512,
298     SHA512_256,
299 }
300 
301 impl PartialEq for Algorithm {
eq(&self, other: &Self) -> bool302     fn eq(&self, other: &Self) -> bool {
303         self.id == other.id
304     }
305 }
306 
307 impl Eq for Algorithm {}
308 
309 derive_debug_via_id!(Algorithm);
310 
311 /// SHA-1 as specified in [FIPS 180-4]. Deprecated.
312 ///
313 /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
314 pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
315     output_len: sha1::OUTPUT_LEN,
316     chaining_len: sha1::CHAINING_LEN,
317     block_len: sha1::BLOCK_LEN,
318     len_len: 64 / 8,
319     block_data_order: sha1::block_data_order,
320     format_output: sha256_format_output,
321     initial_state: State {
322         as32: [
323             Wrapping(0x67452301u32),
324             Wrapping(0xefcdab89u32),
325             Wrapping(0x98badcfeu32),
326             Wrapping(0x10325476u32),
327             Wrapping(0xc3d2e1f0u32),
328             Wrapping(0),
329             Wrapping(0),
330             Wrapping(0),
331         ],
332     },
333     id: AlgorithmID::SHA1,
334 };
335 
336 /// SHA-256 as specified in [FIPS 180-4].
337 ///
338 /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
339 pub static SHA256: Algorithm = Algorithm {
340     output_len: SHA256_OUTPUT_LEN,
341     chaining_len: SHA256_OUTPUT_LEN,
342     block_len: 512 / 8,
343     len_len: 64 / 8,
344     block_data_order: sha2::sha256_block_data_order,
345     format_output: sha256_format_output,
346     initial_state: State {
347         as32: [
348             Wrapping(0x6a09e667u32),
349             Wrapping(0xbb67ae85u32),
350             Wrapping(0x3c6ef372u32),
351             Wrapping(0xa54ff53au32),
352             Wrapping(0x510e527fu32),
353             Wrapping(0x9b05688cu32),
354             Wrapping(0x1f83d9abu32),
355             Wrapping(0x5be0cd19u32),
356         ],
357     },
358     id: AlgorithmID::SHA256,
359 };
360 
361 /// SHA-384 as specified in [FIPS 180-4].
362 ///
363 /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
364 pub static SHA384: Algorithm = Algorithm {
365     output_len: SHA384_OUTPUT_LEN,
366     chaining_len: SHA512_OUTPUT_LEN,
367     block_len: SHA512_BLOCK_LEN,
368     len_len: SHA512_LEN_LEN,
369     block_data_order: sha2::sha512_block_data_order,
370     format_output: sha512_format_output,
371     initial_state: State {
372         as64: [
373             Wrapping(0xcbbb9d5dc1059ed8),
374             Wrapping(0x629a292a367cd507),
375             Wrapping(0x9159015a3070dd17),
376             Wrapping(0x152fecd8f70e5939),
377             Wrapping(0x67332667ffc00b31),
378             Wrapping(0x8eb44a8768581511),
379             Wrapping(0xdb0c2e0d64f98fa7),
380             Wrapping(0x47b5481dbefa4fa4),
381         ],
382     },
383     id: AlgorithmID::SHA384,
384 };
385 
386 /// SHA-512 as specified in [FIPS 180-4].
387 ///
388 /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
389 pub static SHA512: Algorithm = Algorithm {
390     output_len: SHA512_OUTPUT_LEN,
391     chaining_len: SHA512_OUTPUT_LEN,
392     block_len: SHA512_BLOCK_LEN,
393     len_len: SHA512_LEN_LEN,
394     block_data_order: sha2::sha512_block_data_order,
395     format_output: sha512_format_output,
396     initial_state: State {
397         as64: [
398             Wrapping(0x6a09e667f3bcc908),
399             Wrapping(0xbb67ae8584caa73b),
400             Wrapping(0x3c6ef372fe94f82b),
401             Wrapping(0xa54ff53a5f1d36f1),
402             Wrapping(0x510e527fade682d1),
403             Wrapping(0x9b05688c2b3e6c1f),
404             Wrapping(0x1f83d9abfb41bd6b),
405             Wrapping(0x5be0cd19137e2179),
406         ],
407     },
408     id: AlgorithmID::SHA512,
409 };
410 
411 /// SHA-512/256 as specified in [FIPS 180-4].
412 ///
413 /// This is *not* the same as just truncating the output of SHA-512, as
414 /// SHA-512/256 has its own initial state distinct from SHA-512's initial
415 /// state.
416 ///
417 /// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
418 pub static SHA512_256: Algorithm = Algorithm {
419     output_len: SHA512_256_OUTPUT_LEN,
420     chaining_len: SHA512_OUTPUT_LEN,
421     block_len: SHA512_BLOCK_LEN,
422     len_len: SHA512_LEN_LEN,
423     block_data_order: sha2::sha512_block_data_order,
424     format_output: sha512_format_output,
425     initial_state: State {
426         as64: [
427             Wrapping(0x22312194fc2bf72c),
428             Wrapping(0x9f555fa3c84c64c2),
429             Wrapping(0x2393b86b6f53b151),
430             Wrapping(0x963877195940eabd),
431             Wrapping(0x96283ee2a88effe3),
432             Wrapping(0xbe5e1e2553863992),
433             Wrapping(0x2b0199fc2c85b8aa),
434             Wrapping(0x0eb72ddc81c52ca2),
435         ],
436     },
437     id: AlgorithmID::SHA512_256,
438 };
439 
440 #[derive(Clone, Copy)] // XXX: Why do we need to be `Copy`?
441 #[repr(C)]
442 union State {
443     as64: [Wrapping<u64>; sha2::CHAINING_WORDS],
444     as32: [Wrapping<u32>; sha2::CHAINING_WORDS],
445 }
446 
447 #[derive(Clone, Copy)]
448 #[repr(C)]
449 union Output {
450     as64: [BigEndian<u64>; 512 / 8 / core::mem::size_of::<BigEndian<u64>>()],
451     as32: [BigEndian<u32>; 256 / 8 / core::mem::size_of::<BigEndian<u32>>()],
452 }
453 
454 /// The maximum block length (`Algorithm::block_len`) of all the algorithms in
455 /// this module.
456 pub const MAX_BLOCK_LEN: usize = 1024 / 8;
457 
458 /// The maximum output length (`Algorithm::output_len`) of all the algorithms
459 /// in this module.
460 pub const MAX_OUTPUT_LEN: usize = 512 / 8;
461 
462 /// The maximum chaining length (`Algorithm::chaining_len`) of all the
463 /// algorithms in this module.
464 pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
465 
sha256_format_output(input: State) -> Output466 fn sha256_format_output(input: State) -> Output {
467     let input = unsafe { &input.as32 };
468     Output {
469         as32: input.array_map(BigEndian::from),
470     }
471 }
472 
sha512_format_output(input: State) -> Output473 fn sha512_format_output(input: State) -> Output {
474     let input = unsafe { &input.as64 };
475     Output {
476         as64: input.array_map(BigEndian::from),
477     }
478 }
479 
480 /// The length of the output of SHA-1, in bytes.
481 pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN;
482 
483 /// The length of the output of SHA-256, in bytes.
484 pub const SHA256_OUTPUT_LEN: usize = 256 / 8;
485 
486 /// The length of the output of SHA-384, in bytes.
487 pub const SHA384_OUTPUT_LEN: usize = 384 / 8;
488 
489 /// The length of the output of SHA-512, in bytes.
490 pub const SHA512_OUTPUT_LEN: usize = 512 / 8;
491 
492 /// The length of the output of SHA-512/256, in bytes.
493 pub const SHA512_256_OUTPUT_LEN: usize = 256 / 8;
494 
495 /// The length of a block for SHA-512-based algorithms, in bytes.
496 const SHA512_BLOCK_LEN: usize = 1024 / 8;
497 
498 /// The length of the length field for SHA-512-based algorithms, in bytes.
499 const SHA512_LEN_LEN: usize = 128 / 8;
500 
501 #[cfg(test)]
502 mod tests {
503 
504     mod max_input {
505         use super::super::super::digest;
506         use crate::polyfill;
507         use alloc::vec;
508 
509         macro_rules! max_input_tests {
510             ( $algorithm_name:ident ) => {
511                 mod $algorithm_name {
512                     use super::super::super::super::digest;
513 
514                     #[test]
515                     fn max_input_test() {
516                         super::max_input_test(&digest::$algorithm_name);
517                     }
518 
519                     #[test]
520                     #[should_panic]
521                     fn too_long_input_test_block() {
522                         super::too_long_input_test_block(&digest::$algorithm_name);
523                     }
524 
525                     #[test]
526                     #[should_panic]
527                     fn too_long_input_test_byte() {
528                         super::too_long_input_test_byte(&digest::$algorithm_name);
529                     }
530                 }
531             };
532         }
533 
max_input_test(alg: &'static digest::Algorithm)534         fn max_input_test(alg: &'static digest::Algorithm) {
535             let mut context = nearly_full_context(alg);
536             let next_input = vec![0u8; alg.block_len - 1];
537             context.update(&next_input);
538             let _ = context.finish(); // no panic
539         }
540 
too_long_input_test_block(alg: &'static digest::Algorithm)541         fn too_long_input_test_block(alg: &'static digest::Algorithm) {
542             let mut context = nearly_full_context(alg);
543             let next_input = vec![0u8; alg.block_len];
544             context.update(&next_input);
545             let _ = context.finish(); // should panic
546         }
547 
too_long_input_test_byte(alg: &'static digest::Algorithm)548         fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
549             let mut context = nearly_full_context(alg);
550             let next_input = vec![0u8; alg.block_len - 1];
551             context.update(&next_input); // no panic
552             context.update(&[0]);
553             let _ = context.finish(); // should panic
554         }
555 
nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context556         fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
557             // All implementations currently support up to 2^64-1 bits
558             // of input; according to the spec, SHA-384 and SHA-512
559             // support up to 2^128-1, but that's not implemented yet.
560             let max_bytes = 1u64 << (64 - 3);
561             let max_blocks = max_bytes / polyfill::u64_from_usize(alg.block_len);
562             digest::Context {
563                 block: digest::BlockContext {
564                     state: alg.initial_state,
565                     completed_data_blocks: max_blocks - 1,
566                     algorithm: alg,
567                     cpu_features: crate::cpu::features(),
568                 },
569                 pending: [0u8; digest::MAX_BLOCK_LEN],
570                 num_pending: 0,
571             }
572         }
573 
574         max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
575         max_input_tests!(SHA256);
576         max_input_tests!(SHA384);
577         max_input_tests!(SHA512);
578     }
579 }
580