rustls/crypto/
hash.rs

1use alloc::boxed::Box;
2
3use super::enums::HashAlgorithm;
4
5/// Describes a single cryptographic hash function.
6///
7/// This interface can do both one-shot and incremental hashing, using
8/// [`Hash::hash()`] and [`Hash::start()`] respectively.
9pub trait Hash: Send + Sync {
10    /// Start an incremental hash computation.
11    fn start(&self) -> Box<dyn Context>;
12
13    /// Return the output of this hash function with input `data`.
14    fn hash(&self, data: &[u8]) -> Output;
15
16    /// The length in bytes of this hash function's output.
17    fn output_len(&self) -> usize;
18
19    /// Which hash function this is, eg, `HashAlgorithm::SHA256`.
20    fn algorithm(&self) -> HashAlgorithm;
21
22    /// Return `true` if this is backed by a FIPS-approved implementation.
23    fn fips(&self) -> bool {
24        false
25    }
26}
27
28/// A hash output, stored as a value.
29pub struct Output {
30    buf: [u8; Self::MAX_LEN],
31    used: usize,
32}
33
34impl Output {
35    /// Build a `hash::Output` from a slice of no more than `Output::MAX_LEN` bytes.
36    pub fn new(bytes: &[u8]) -> Self {
37        let mut output = Self {
38            buf: [0u8; Self::MAX_LEN],
39            used: bytes.len(),
40        };
41        debug_assert!(bytes.len() <= Self::MAX_LEN);
42        output.buf[..bytes.len()].copy_from_slice(bytes);
43        output
44    }
45
46    /// Maximum supported hash output size: supports up to SHA512.
47    pub const MAX_LEN: usize = 64;
48}
49
50impl AsRef<[u8]> for Output {
51    fn as_ref(&self) -> &[u8] {
52        &self.buf[..self.used]
53    }
54}
55
56/// How to incrementally compute a hash.
57pub trait Context: Send + Sync {
58    /// Finish the computation, returning the resulting output.
59    ///
60    /// The computation remains valid, and more data can be added later with
61    /// [`Context::update()`].
62    ///
63    /// Compare with [`Context::finish()`] which consumes the computation
64    /// and prevents any further data being added.  This can be more efficient
65    /// because it avoids a hash context copy to apply Merkle-Damgård padding
66    /// (if required).
67    fn fork_finish(&self) -> Output;
68
69    /// Fork the computation, producing another context that has the
70    /// same prefix as this one.
71    fn fork(&self) -> Box<dyn Context>;
72
73    /// Terminate and finish the computation, returning the resulting output.
74    ///
75    /// Further data cannot be added after this, because the context is consumed.
76    /// Compare [`Context::fork_finish()`].
77    fn finish(self: Box<Self>) -> Output;
78
79    /// Add `data` to computation.
80    fn update(&mut self, data: &[u8]);
81}
82
83#[cfg(all(test, feature = "aws-lc-rs"))]
84pub(crate) struct FakeHash;
85
86#[cfg(all(test, feature = "aws-lc-rs"))]
87impl Hash for FakeHash {
88    fn algorithm(&self) -> HashAlgorithm {
89        todo!()
90    }
91
92    fn fips(&self) -> bool {
93        false
94    }
95
96    fn hash(&self, _bytes: &[u8]) -> Output {
97        todo!()
98    }
99
100    fn output_len(&self) -> usize {
101        todo!()
102    }
103
104    fn start(&self) -> Box<dyn Context> {
105        Box::new(FakeHashContext)
106    }
107}
108
109#[cfg(all(test, feature = "aws-lc-rs"))]
110struct FakeHashContext;
111
112#[cfg(all(test, feature = "aws-lc-rs"))]
113impl Context for FakeHashContext {
114    fn fork_finish(&self) -> Output {
115        todo!()
116    }
117
118    fn fork(&self) -> Box<dyn Context> {
119        todo!()
120    }
121
122    fn finish(self: Box<Self>) -> Output {
123        todo!()
124    }
125
126    fn update(&mut self, _data: &[u8]) {}
127}