ring/
digest.rs

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