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::{
28    c, cpu, debug,
29    endian::{self, BigEndian},
30    polyfill,
31};
32use core::num::Wrapping;
33
34mod sha1;
35mod sha2;
36
37#[derive(Clone)]
38pub(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
52impl BlockContext {
53    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]
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
77    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)]
138pub 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
145impl Context {
146    /// Constructs a new context.
147    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
155    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.
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.
196    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)]
204    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/// ```
224pub 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)]
234pub struct Digest {
235    value: Output,
236    algorithm: &'static Algorithm,
237}
238
239impl Digest {
240    /// The algorithm that was used to calculate the digest value.
241    #[inline(always)]
242    pub fn algorithm(&self) -> &'static Algorithm {
243        self.algorithm
244    }
245}
246
247impl AsRef<[u8]> for Digest {
248    #[inline(always)]
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
255impl core::fmt::Debug for Digest {
256    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.
263pub 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)]
290enum AlgorithmID {
291    SHA1,
292    SHA256,
293    SHA384,
294    SHA512,
295    SHA512_256,
296}
297
298impl PartialEq for Algorithm {
299    fn eq(&self, other: &Self) -> bool {
300        self.id == other.id
301    }
302}
303
304impl Eq for Algorithm {}
305
306derive_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
311pub 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
336pub 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
361pub 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
386pub 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
415pub 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)]
439union State {
440    as64: [Wrapping<u64>; sha2::CHAINING_WORDS],
441    as32: [Wrapping<u32>; sha2::CHAINING_WORDS],
442}
443
444#[derive(Clone, Copy)]
445#[repr(C)]
446union 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.
453pub const MAX_BLOCK_LEN: usize = 1024 / 8;
454
455/// The maximum output length (`Algorithm::output_len`) of all the algorithms
456/// in this module.
457pub const MAX_OUTPUT_LEN: usize = 512 / 8;
458
459/// The maximum chaining length (`Algorithm::chaining_len`) of all the
460/// algorithms in this module.
461pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
462
463fn 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
479fn 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.
496pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN;
497
498/// The length of the output of SHA-256, in bytes.
499pub const SHA256_OUTPUT_LEN: usize = 256 / 8;
500
501/// The length of the output of SHA-384, in bytes.
502pub const SHA384_OUTPUT_LEN: usize = 384 / 8;
503
504/// The length of the output of SHA-512, in bytes.
505pub const SHA512_OUTPUT_LEN: usize = 512 / 8;
506
507/// The length of the output of SHA-512/256, in bytes.
508pub const SHA512_256_OUTPUT_LEN: usize = 256 / 8;
509
510/// The length of a block for SHA-512-based algorithms, in bytes.
511const SHA512_BLOCK_LEN: usize = 1024 / 8;
512
513/// The length of the length field for SHA-512-based algorithms, in bytes.
514const SHA512_LEN_LEN: usize = 128 / 8;
515
516#[cfg(test)]
517mod 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
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
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
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
571        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}