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