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::{c, cpu, debug, polyfill};
28use core::num::Wrapping;
29
30mod sha1;
31mod sha2;
32
33#[derive(Clone)]
34pub(crate) struct BlockContext {
35    state: State,
36
37    // Note that SHA-512 has a 128-bit input bit counter, but this
38    // implementation only supports up to 2^64-1 input bits for all algorithms,
39    // so a 64-bit counter is more than sufficient.
40    completed_data_blocks: u64,
41
42    /// The context's algorithm.
43    pub algorithm: &'static Algorithm,
44}
45
46impl BlockContext {
47    pub(crate) fn new(algorithm: &'static Algorithm) -> Self {
48        Self {
49            state: algorithm.initial_state,
50            completed_data_blocks: 0,
51            algorithm,
52        }
53    }
54
55    #[inline]
56    pub(crate) fn update(&mut self, input: &[u8]) {
57        let num_blocks = input.len() / self.algorithm.block_len;
58        assert_eq!(num_blocks * self.algorithm.block_len, input.len());
59
60        if num_blocks > 0 {
61            unsafe {
62                self.block_data_order(input.as_ptr(), num_blocks, cpu::features());
63            }
64            self.completed_data_blocks = self
65                .completed_data_blocks
66                .checked_add(polyfill::u64_from_usize(num_blocks))
67                .unwrap();
68        }
69    }
70
71    pub(crate) fn finish(mut self, pending: &mut [u8], num_pending: usize) -> Digest {
72        let block_len = self.algorithm.block_len;
73        assert_eq!(pending.len(), block_len);
74        assert!(num_pending <= pending.len());
75
76        let mut padding_pos = num_pending;
77        pending[padding_pos] = 0x80;
78        padding_pos += 1;
79
80        if padding_pos > block_len - self.algorithm.len_len {
81            pending[padding_pos..block_len].fill(0);
82            unsafe { self.block_data_order(pending.as_ptr(), 1, cpu::features()) };
83            // We don't increase |self.completed_data_blocks| because the
84            // padding isn't data, and so it isn't included in the data length.
85            padding_pos = 0;
86        }
87
88        pending[padding_pos..(block_len - 8)].fill(0);
89
90        // Output the length, in bits, in big endian order.
91        let completed_data_bits = self
92            .completed_data_blocks
93            .checked_mul(polyfill::u64_from_usize(block_len))
94            .unwrap()
95            .checked_add(polyfill::u64_from_usize(num_pending))
96            .unwrap()
97            .checked_mul(8)
98            .unwrap();
99        pending[(block_len - 8)..block_len].copy_from_slice(&u64::to_be_bytes(completed_data_bits));
100
101        unsafe { self.block_data_order(pending.as_ptr(), 1, cpu::features()) };
102
103        Digest {
104            algorithm: self.algorithm,
105            value: (self.algorithm.format_output)(self.state),
106        }
107    }
108
109    unsafe fn block_data_order(
110        &mut self,
111        pending: *const u8,
112        num_blocks: usize,
113        _cpu_features: cpu::Features,
114    ) {
115        // CPU features are inspected by assembly implementations.
116        unsafe {
117            (self.algorithm.block_data_order)(&mut self.state, pending, num_blocks);
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)]
140pub 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
147impl Context {
148    /// Constructs a new context.
149    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
157    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`.
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.
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 [`Self::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        &self.value.0[..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    output_len: usize,
265    chaining_len: usize,
266    block_len: usize,
267
268    /// The length of the length in the padding.
269    len_len: usize,
270
271    block_data_order: unsafe extern "C" fn(state: &mut State, data: *const u8, num: c::size_t),
272    format_output: fn(input: State) -> Output,
273
274    initial_state: State,
275
276    id: AlgorithmID,
277}
278
279#[derive(Debug, Eq, PartialEq)]
280enum AlgorithmID {
281    SHA1,
282    SHA256,
283    SHA384,
284    SHA512,
285    SHA512_256,
286}
287
288impl PartialEq for Algorithm {
289    fn eq(&self, other: &Self) -> bool {
290        self.id == other.id
291    }
292}
293
294impl Eq for Algorithm {}
295
296derive_debug_via_id!(Algorithm);
297
298impl Algorithm {
299    /// The internal block length.
300    pub fn block_len(&self) -> usize {
301        self.block_len
302    }
303
304    /// The size of the chaining value of the digest function, in bytes.
305    ///
306    /// For non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal
307    /// to [`Self::output_len()`]. For truncated algorithms (e.g. SHA-384,
308    /// SHA-512/256), this is equal to the length before truncation. This is
309    /// mostly helpful for determining the size of an HMAC key that is
310    /// appropriate for the digest algorithm.
311    pub fn chaining_len(&self) -> usize {
312        self.chaining_len
313    }
314
315    /// The length of a finalized digest.
316    pub fn output_len(&self) -> usize {
317        self.output_len
318    }
319}
320
321/// SHA-1 as specified in [FIPS 180-4]. Deprecated.
322///
323/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
324pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
325    output_len: sha1::OUTPUT_LEN,
326    chaining_len: sha1::CHAINING_LEN,
327    block_len: sha1::BLOCK_LEN,
328    len_len: 64 / 8,
329    block_data_order: sha1::block_data_order,
330    format_output: sha256_format_output,
331    initial_state: State {
332        as32: [
333            Wrapping(0x67452301u32),
334            Wrapping(0xefcdab89u32),
335            Wrapping(0x98badcfeu32),
336            Wrapping(0x10325476u32),
337            Wrapping(0xc3d2e1f0u32),
338            Wrapping(0),
339            Wrapping(0),
340            Wrapping(0),
341        ],
342    },
343    id: AlgorithmID::SHA1,
344};
345
346/// SHA-256 as specified in [FIPS 180-4].
347///
348/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
349pub static SHA256: Algorithm = Algorithm {
350    output_len: SHA256_OUTPUT_LEN,
351    chaining_len: SHA256_OUTPUT_LEN,
352    block_len: 512 / 8,
353    len_len: 64 / 8,
354    block_data_order: sha2::sha256_block_data_order,
355    format_output: sha256_format_output,
356    initial_state: State {
357        as32: [
358            Wrapping(0x6a09e667u32),
359            Wrapping(0xbb67ae85u32),
360            Wrapping(0x3c6ef372u32),
361            Wrapping(0xa54ff53au32),
362            Wrapping(0x510e527fu32),
363            Wrapping(0x9b05688cu32),
364            Wrapping(0x1f83d9abu32),
365            Wrapping(0x5be0cd19u32),
366        ],
367    },
368    id: AlgorithmID::SHA256,
369};
370
371/// SHA-384 as specified in [FIPS 180-4].
372///
373/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
374pub static SHA384: Algorithm = Algorithm {
375    output_len: SHA384_OUTPUT_LEN,
376    chaining_len: SHA512_OUTPUT_LEN,
377    block_len: SHA512_BLOCK_LEN,
378    len_len: SHA512_LEN_LEN,
379    block_data_order: sha2::sha512_block_data_order,
380    format_output: sha512_format_output,
381    initial_state: State {
382        as64: [
383            Wrapping(0xcbbb9d5dc1059ed8),
384            Wrapping(0x629a292a367cd507),
385            Wrapping(0x9159015a3070dd17),
386            Wrapping(0x152fecd8f70e5939),
387            Wrapping(0x67332667ffc00b31),
388            Wrapping(0x8eb44a8768581511),
389            Wrapping(0xdb0c2e0d64f98fa7),
390            Wrapping(0x47b5481dbefa4fa4),
391        ],
392    },
393    id: AlgorithmID::SHA384,
394};
395
396/// SHA-512 as specified in [FIPS 180-4].
397///
398/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
399pub static SHA512: Algorithm = Algorithm {
400    output_len: SHA512_OUTPUT_LEN,
401    chaining_len: SHA512_OUTPUT_LEN,
402    block_len: SHA512_BLOCK_LEN,
403    len_len: SHA512_LEN_LEN,
404    block_data_order: sha2::sha512_block_data_order,
405    format_output: sha512_format_output,
406    initial_state: State {
407        as64: [
408            Wrapping(0x6a09e667f3bcc908),
409            Wrapping(0xbb67ae8584caa73b),
410            Wrapping(0x3c6ef372fe94f82b),
411            Wrapping(0xa54ff53a5f1d36f1),
412            Wrapping(0x510e527fade682d1),
413            Wrapping(0x9b05688c2b3e6c1f),
414            Wrapping(0x1f83d9abfb41bd6b),
415            Wrapping(0x5be0cd19137e2179),
416        ],
417    },
418    id: AlgorithmID::SHA512,
419};
420
421/// SHA-512/256 as specified in [FIPS 180-4].
422///
423/// This is *not* the same as just truncating the output of SHA-512, as
424/// SHA-512/256 has its own initial state distinct from SHA-512's initial
425/// state.
426///
427/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
428pub static SHA512_256: Algorithm = Algorithm {
429    output_len: SHA512_256_OUTPUT_LEN,
430    chaining_len: SHA512_OUTPUT_LEN,
431    block_len: SHA512_BLOCK_LEN,
432    len_len: SHA512_LEN_LEN,
433    block_data_order: sha2::sha512_block_data_order,
434    format_output: sha512_format_output,
435    initial_state: State {
436        as64: [
437            Wrapping(0x22312194fc2bf72c),
438            Wrapping(0x9f555fa3c84c64c2),
439            Wrapping(0x2393b86b6f53b151),
440            Wrapping(0x963877195940eabd),
441            Wrapping(0x96283ee2a88effe3),
442            Wrapping(0xbe5e1e2553863992),
443            Wrapping(0x2b0199fc2c85b8aa),
444            Wrapping(0x0eb72ddc81c52ca2),
445        ],
446    },
447    id: AlgorithmID::SHA512_256,
448};
449
450#[derive(Clone, Copy)] // XXX: Why do we need to be `Copy`?
451#[repr(C)]
452union State {
453    as64: [Wrapping<u64>; sha2::CHAINING_WORDS],
454    as32: [Wrapping<u32>; sha2::CHAINING_WORDS],
455}
456
457#[derive(Clone, Copy)]
458struct Output([u8; MAX_OUTPUT_LEN]);
459
460/// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms
461/// in this module.
462pub const MAX_BLOCK_LEN: usize = 1024 / 8;
463
464/// The maximum output length ([`Algorithm::output_len()`]) of all the
465/// algorithms in this module.
466pub const MAX_OUTPUT_LEN: usize = 512 / 8;
467
468/// The maximum chaining length ([`Algorithm::chaining_len()`]) of all the
469/// algorithms in this module.
470pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
471
472fn sha256_format_output(input: State) -> Output {
473    let input = unsafe { input.as32 };
474    format_output::<_, _, { core::mem::size_of::<u32>() }>(input, u32::to_be_bytes)
475}
476
477fn sha512_format_output(input: State) -> Output {
478    let input = unsafe { input.as64 };
479    format_output::<_, _, { core::mem::size_of::<u64>() }>(input, u64::to_be_bytes)
480}
481
482#[inline]
483fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output
484where
485    F: Fn(T) -> [u8; N],
486    T: Copy,
487{
488    let mut output = Output([0; MAX_OUTPUT_LEN]);
489    output
490        .0
491        .chunks_mut(N)
492        .zip(input.iter().copied().map(|Wrapping(w)| f(w)))
493        .for_each(|(o, i)| {
494            o.copy_from_slice(&i);
495        });
496    output
497}
498
499/// The length of the output of SHA-1, in bytes.
500pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN;
501
502/// The length of the output of SHA-256, in bytes.
503pub const SHA256_OUTPUT_LEN: usize = 256 / 8;
504
505/// The length of the output of SHA-384, in bytes.
506pub const SHA384_OUTPUT_LEN: usize = 384 / 8;
507
508/// The length of the output of SHA-512, in bytes.
509pub const SHA512_OUTPUT_LEN: usize = 512 / 8;
510
511/// The length of the output of SHA-512/256, in bytes.
512pub const SHA512_256_OUTPUT_LEN: usize = 256 / 8;
513
514/// The length of a block for SHA-512-based algorithms, in bytes.
515const SHA512_BLOCK_LEN: usize = 1024 / 8;
516
517/// The length of the length field for SHA-512-based algorithms, in bytes.
518const SHA512_LEN_LEN: usize = 128 / 8;
519
520#[cfg(test)]
521mod tests {
522    mod max_input {
523        extern crate alloc;
524        use super::super::super::digest;
525        use crate::polyfill;
526        use alloc::vec;
527
528        macro_rules! max_input_tests {
529            ( $algorithm_name:ident ) => {
530                mod $algorithm_name {
531                    use super::super::super::super::digest;
532
533                    #[test]
534                    fn max_input_test() {
535                        super::max_input_test(&digest::$algorithm_name);
536                    }
537
538                    #[test]
539                    #[should_panic]
540                    fn too_long_input_test_block() {
541                        super::too_long_input_test_block(&digest::$algorithm_name);
542                    }
543
544                    #[test]
545                    #[should_panic]
546                    fn too_long_input_test_byte() {
547                        super::too_long_input_test_byte(&digest::$algorithm_name);
548                    }
549                }
550            };
551        }
552
553        fn max_input_test(alg: &'static digest::Algorithm) {
554            let mut context = nearly_full_context(alg);
555            let next_input = vec![0u8; alg.block_len - 1];
556            context.update(&next_input);
557            let _ = context.finish(); // no panic
558        }
559
560        fn too_long_input_test_block(alg: &'static digest::Algorithm) {
561            let mut context = nearly_full_context(alg);
562            let next_input = vec![0u8; alg.block_len];
563            context.update(&next_input);
564            let _ = context.finish(); // should panic
565        }
566
567        fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
568            let mut context = nearly_full_context(alg);
569            let next_input = vec![0u8; alg.block_len - 1];
570            context.update(&next_input); // no panic
571            context.update(&[0]);
572            let _ = context.finish(); // should panic
573        }
574
575        fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
576            // All implementations currently support up to 2^64-1 bits
577            // of input; according to the spec, SHA-384 and SHA-512
578            // support up to 2^128-1, but that's not implemented yet.
579            let max_bytes = 1u64 << (64 - 3);
580            let max_blocks = max_bytes / polyfill::u64_from_usize(alg.block_len);
581            digest::Context {
582                block: digest::BlockContext {
583                    state: alg.initial_state,
584                    completed_data_blocks: max_blocks - 1,
585                    algorithm: alg,
586                },
587                pending: [0u8; digest::MAX_BLOCK_LEN],
588                num_pending: 0,
589            }
590        }
591
592        max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
593        max_input_tests!(SHA256);
594        max_input_tests!(SHA384);
595        max_input_tests!(SHA512);
596    }
597}