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