// Copyright 2023 The BoringSSL Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Hash functions. //! //! ``` //! use bssl_crypto::digest; //! //! // One-shot hashing. //! let digest: [u8; 32] = digest::Sha256::hash(b"hello"); //! //! // Incremental hashing. //! let mut ctx = digest::Sha256::new(); //! ctx.update(b"hel"); //! ctx.update(b"lo"); //! let digest2: [u8; 32] = ctx.digest(); //! //! assert_eq!(digest, digest2); //! //! // Hashing with dynamic dispatch. //! #[cfg(feature = "std")] //! { //! fn update_hash(ctx: &mut dyn std::io::Write) { //! ctx.write(b"hel"); //! ctx.write(b"lo"); //! } //! //! let mut ctx = digest::Sha256::new(); //! update_hash(&mut ctx); //! assert_eq!(ctx.digest(), digest); //! } //! ``` use crate::{sealed, FfiSlice, ForeignTypeRef}; use alloc::vec::Vec; #[non_exhaustive] #[doc(hidden)] pub struct MdRef; unsafe impl ForeignTypeRef for MdRef { type CType = bssl_sys::EVP_MD; } /// Provides the ability to hash in an algorithm-agnostic manner. pub trait Algorithm { /// The size of the resulting digest. const OUTPUT_LEN: usize; /// The block length (in bytes). const BLOCK_LEN: usize; /// Gets a reference to a message digest algorithm to be used by the HKDF implementation. #[doc(hidden)] fn get_md(_: sealed::Sealed) -> &'static MdRef; /// Hashes a message. fn hash_to_vec(input: &[u8]) -> Vec; /// Create a new context for incremental hashing. fn new() -> Self; /// Hash the contents of `input`. fn update(&mut self, input: &[u8]); /// Finish the hashing and return the digest. fn digest_to_vec(self) -> Vec; } /// The insecure SHA-1 hash algorithm. /// /// Some existing protocols depend on SHA-1 and so it is provided here, but it /// does not provide collision resistance and should not be used if at all /// avoidable. Use SHA-256 instead. #[derive(Clone)] pub struct InsecureSha1 { ctx: bssl_sys::SHA_CTX, } unsafe_iuf_algo!( InsecureSha1, 20, 64, EVP_sha1, SHA1, SHA1_Init, SHA1_Update, SHA1_Final ); /// The SHA-256 hash algorithm. #[derive(Clone)] pub struct Sha256 { ctx: bssl_sys::SHA256_CTX, } unsafe_iuf_algo!( Sha256, 32, 64, EVP_sha256, SHA256, SHA256_Init, SHA256_Update, SHA256_Final ); /// The SHA-384 hash algorithm. #[derive(Clone)] pub struct Sha384 { ctx: bssl_sys::SHA512_CTX, } unsafe_iuf_algo!( Sha384, 48, 128, EVP_sha384, SHA384, SHA384_Init, SHA384_Update, SHA384_Final ); /// The SHA-512 hash algorithm. #[derive(Clone)] pub struct Sha512 { ctx: bssl_sys::SHA512_CTX, } unsafe_iuf_algo!( Sha512, 64, 128, EVP_sha512, SHA512, SHA512_Init, SHA512_Update, SHA512_Final ); /// The SHA-512/256 hash algorithm. #[derive(Clone)] pub struct Sha512_256 { ctx: bssl_sys::SHA512_CTX, } unsafe_iuf_algo!( Sha512_256, 32, 128, EVP_sha512_256, SHA512_256, SHA512_256_Init, SHA512_256_Update, SHA512_256_Final ); #[cfg(test)] mod test { use super::*; use crate::test_helpers::decode_hex; #[test] fn sha256_c_type() { unsafe { assert_eq!( MdRef::from_ptr(bssl_sys::EVP_sha256() as *mut _).as_ptr(), bssl_sys::EVP_sha256() as *mut _ ) } } #[test] fn sha512_c_type() { unsafe { assert_eq!( MdRef::from_ptr(bssl_sys::EVP_sha512() as *mut _).as_ptr(), bssl_sys::EVP_sha512() as *mut _ ) } } #[test] fn sha1() { assert_eq!( decode_hex("a9993e364706816aba3e25717850c26c9cd0d89d"), InsecureSha1::hash(b"abc") ); } #[test] fn sha256() { let msg: [u8; 4] = decode_hex("74ba2521"); let expected_digest: [u8; 32] = decode_hex("b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e"); assert_eq!(Sha256::hash(&msg), expected_digest); let mut ctx = Sha256::new(); ctx.update(&msg); assert_eq!(expected_digest, ctx.digest()); let mut ctx = Sha256::new(); ctx.update(&msg[0..1]); let mut ctx2 = ctx.clone(); ctx2.update(&msg[1..]); assert_eq!(expected_digest, ctx2.digest()); } #[test] fn sha384() { assert_eq!( decode_hex("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"), Sha384::hash(b"abc") ); } #[test] fn sha512() { let msg: [u8; 4] = decode_hex("23be86d5"); let expected_digest: [u8; 64] = decode_hex(concat!( "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2", "ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb" )); assert_eq!(Sha512::hash(&msg), expected_digest); let mut ctx = Sha512::new(); ctx.update(&msg); assert_eq!(expected_digest, ctx.digest()); } #[test] fn sha512_256() { assert_eq!( decode_hex("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"), Sha512_256::hash(b"abc") ); } }