Skip to main content

bssl_crypto/
digest.rs

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