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