blob: e5578e5f8b22e7cef4ce2bd0b43ddaa8ad6c5b76 [file] [log] [blame]
/* Copyright (c) 2023, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//! 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);
//! ```
use crate::{sealed, FfiSlice, ForeignTypeRef};
use alloc::vec::Vec;
use bssl_sys;
#[non_exhaustive]
#[doc(hidden)]
pub struct MdRef;
unsafe impl ForeignTypeRef for MdRef {
type CType = bssl_sys::EVP_MD;
}
/// Used internally to parameterize other primitives.
pub trait Algorithm {
/// The size of the resulting digest.
const OUTPUT_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<u8>;
}
/// 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,
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,
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,
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,
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,
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")
);
}
}