Skip to main content

bssl_crypto/
digest.rs

1/* Copyright 2023 The BoringSSL Authors
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 AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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
16//! Hash functions.
17//!
18//! ```
19//! use bssl_crypto::digest;
20//!
21//! // One-shot hashing.
22//! let digest: [u8; 32] = digest::Sha256::hash(b"hello");
23//!
24//! // Incremental hashing.
25//! let mut ctx = digest::Sha256::new();
26//! ctx.update(b"hel");
27//! ctx.update(b"lo");
28//! let digest2: [u8; 32] = ctx.digest();
29//!
30//! assert_eq!(digest, digest2);
31//!
32//! // Hashing with dynamic dispatch.
33//! #[cfg(feature = "std")]
34//! {
35//!     fn update_hash(ctx: &mut dyn std::io::Write) {
36//!         ctx.write(b"hel");
37//!         ctx.write(b"lo");
38//!     }
39//!
40//!     let mut ctx = digest::Sha256::new();
41//!     update_hash(&mut ctx);
42//!     assert_eq!(ctx.digest(), digest);
43//! }
44//! ```
45
46use crate::{sealed, FfiSlice, ForeignTypeRef};
47use alloc::vec::Vec;
48
49#[non_exhaustive]
50#[doc(hidden)]
51pub struct MdRef;
52
53unsafe impl ForeignTypeRef for MdRef {
54    type CType = bssl_sys::EVP_MD;
55}
56
57/// Provides the ability to hash in an algorithm-agnostic manner.
58pub trait Algorithm {
59    /// The size of the resulting digest.
60    const OUTPUT_LEN: usize;
61    /// The block length (in bytes).
62    const BLOCK_LEN: usize;
63
64    /// Gets a reference to a message digest algorithm to be used by the HKDF implementation.
65    #[doc(hidden)]
66    fn get_md(_: sealed::Sealed) -> &'static MdRef;
67
68    /// Hashes a message.
69    fn hash_to_vec(input: &[u8]) -> Vec<u8>;
70
71    /// Create a new context for incremental hashing.
72    fn new() -> Self;
73
74    /// Hash the contents of `input`.
75    fn update(&mut self, input: &[u8]);
76
77    /// Finish the hashing and return the digest.
78    fn digest_to_vec(self) -> Vec<u8>;
79}
80
81/// The insecure SHA-1 hash algorithm.
82///
83/// Some existing protocols depend on SHA-1 and so it is provided here, but it
84/// does not provide collision resistance and should not be used if at all
85/// avoidable. Use SHA-256 instead.
86#[derive(Clone)]
87pub struct InsecureSha1 {
88    ctx: bssl_sys::SHA_CTX,
89}
90
91unsafe_iuf_algo!(
92    InsecureSha1,
93    20,
94    64,
95    EVP_sha1,
96    SHA1,
97    SHA1_Init,
98    SHA1_Update,
99    SHA1_Final
100);
101
102/// The SHA-256 hash algorithm.
103#[derive(Clone)]
104pub struct Sha256 {
105    ctx: bssl_sys::SHA256_CTX,
106}
107
108unsafe_iuf_algo!(
109    Sha256,
110    32,
111    64,
112    EVP_sha256,
113    SHA256,
114    SHA256_Init,
115    SHA256_Update,
116    SHA256_Final
117);
118
119/// The SHA-384 hash algorithm.
120#[derive(Clone)]
121pub struct Sha384 {
122    ctx: bssl_sys::SHA512_CTX,
123}
124
125unsafe_iuf_algo!(
126    Sha384,
127    48,
128    128,
129    EVP_sha384,
130    SHA384,
131    SHA384_Init,
132    SHA384_Update,
133    SHA384_Final
134);
135
136/// The SHA-512 hash algorithm.
137#[derive(Clone)]
138pub struct Sha512 {
139    ctx: bssl_sys::SHA512_CTX,
140}
141
142unsafe_iuf_algo!(
143    Sha512,
144    64,
145    128,
146    EVP_sha512,
147    SHA512,
148    SHA512_Init,
149    SHA512_Update,
150    SHA512_Final
151);
152
153/// The SHA-512/256 hash algorithm.
154#[derive(Clone)]
155pub struct Sha512_256 {
156    ctx: bssl_sys::SHA512_CTX,
157}
158
159unsafe_iuf_algo!(
160    Sha512_256,
161    32,
162    128,
163    EVP_sha512_256,
164    SHA512_256,
165    SHA512_256_Init,
166    SHA512_256_Update,
167    SHA512_256_Final
168);
169
170#[cfg(test)]
171mod test {
172    use super::*;
173    use crate::test_helpers::decode_hex;
174
175    #[test]
176    fn sha256_c_type() {
177        unsafe {
178            assert_eq!(
179                MdRef::from_ptr(bssl_sys::EVP_sha256() as *mut _).as_ptr(),
180                bssl_sys::EVP_sha256() as *mut _
181            )
182        }
183    }
184
185    #[test]
186    fn sha512_c_type() {
187        unsafe {
188            assert_eq!(
189                MdRef::from_ptr(bssl_sys::EVP_sha512() as *mut _).as_ptr(),
190                bssl_sys::EVP_sha512() as *mut _
191            )
192        }
193    }
194
195    #[test]
196    fn sha1() {
197        assert_eq!(
198            decode_hex("a9993e364706816aba3e25717850c26c9cd0d89d"),
199            InsecureSha1::hash(b"abc")
200        );
201    }
202
203    #[test]
204    fn sha256() {
205        let msg: [u8; 4] = decode_hex("74ba2521");
206        let expected_digest: [u8; 32] =
207            decode_hex("b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e");
208
209        assert_eq!(Sha256::hash(&msg), expected_digest);
210
211        let mut ctx = Sha256::new();
212        ctx.update(&msg);
213        assert_eq!(expected_digest, ctx.digest());
214
215        let mut ctx = Sha256::new();
216        ctx.update(&msg[0..1]);
217        let mut ctx2 = ctx.clone();
218        ctx2.update(&msg[1..]);
219        assert_eq!(expected_digest, ctx2.digest());
220    }
221
222    #[test]
223    fn sha384() {
224        assert_eq!(
225            decode_hex("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"),
226            Sha384::hash(b"abc")
227        );
228    }
229
230    #[test]
231    fn sha512() {
232        let msg: [u8; 4] = decode_hex("23be86d5");
233        let expected_digest: [u8; 64] = decode_hex(concat!(
234            "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2",
235            "ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb"
236        ));
237
238        assert_eq!(Sha512::hash(&msg), expected_digest);
239
240        let mut ctx = Sha512::new();
241        ctx.update(&msg);
242        assert_eq!(expected_digest, ctx.digest());
243    }
244
245    #[test]
246    fn sha512_256() {
247        assert_eq!(
248            decode_hex("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"),
249            Sha512_256::hash(b"abc")
250        );
251    }
252}