use crate::errors::UnknownCryptoError;
#[cfg(feature = "safe_api")]
use std::io;
construct_public! {
(Digest, test_digest, SHA384_OUTSIZE, SHA384_OUTSIZE)
}
impl_from_trait!(Digest, SHA384_OUTSIZE);
use super::sha2_core::{State, Variant};
use super::w64::WordU64;
pub const SHA384_BLOCKSIZE: usize = 128;
pub const SHA384_OUTSIZE: usize = 48;
const N_CONSTS: usize = 80;
#[derive(Clone)]
pub(crate) struct V384;
impl Variant<WordU64, N_CONSTS> for V384 {
const K: [WordU64; N_CONSTS] = super::sha512::V512::K;
#[rustfmt::skip]
#[allow(clippy::unreadable_literal)]
const H0: [WordU64; 8] = [
WordU64(0xcbbb9d5dc1059ed8), WordU64(0x629a292a367cd507), WordU64(0x9159015a3070dd17), WordU64(0x152fecd8f70e5939),
WordU64(0x67332667ffc00b31), WordU64(0x8eb44a8768581511), WordU64(0xdb0c2e0d64f98fa7), WordU64(0x47b5481dbefa4fa4),
];
fn big_sigma_0(x: WordU64) -> WordU64 {
super::sha512::V512::big_sigma_0(x)
}
fn big_sigma_1(x: WordU64) -> WordU64 {
super::sha512::V512::big_sigma_1(x)
}
fn small_sigma_0(x: WordU64) -> WordU64 {
super::sha512::V512::small_sigma_0(x)
}
fn small_sigma_1(x: WordU64) -> WordU64 {
super::sha512::V512::small_sigma_1(x)
}
}
#[derive(Clone, Debug)]
pub struct Sha384 {
pub(crate) _state: State<WordU64, V384, SHA384_BLOCKSIZE, SHA384_OUTSIZE, N_CONSTS>,
}
impl Default for Sha384 {
fn default() -> Self {
Self::new()
}
}
impl Sha384 {
pub fn new() -> Self {
Self {
_state: State::<WordU64, V384, SHA384_BLOCKSIZE, SHA384_OUTSIZE, N_CONSTS>::_new(),
}
}
pub fn reset(&mut self) {
self._state._reset();
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
self._state._update(data)
}
pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
self._state._finalize(dest)
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
let mut digest = [0u8; SHA384_OUTSIZE];
self._finalize_internal(&mut digest)?;
Ok(Digest::from(digest))
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
let mut ctx = Self::new();
ctx.update(data)?;
ctx.finalize()
}
}
impl crate::hazardous::mac::hmac::HmacHashFunction for Sha384 {
const _BLOCKSIZE: usize = SHA384_BLOCKSIZE;
const _OUTSIZE: usize = SHA384_OUTSIZE;
fn _new() -> Self {
Self::new()
}
fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
self.update(data)
}
fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
self._finalize_internal(dest)
}
fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
let mut ctx = Self::new();
ctx.update(data)?;
ctx._finalize_internal(dest)
}
#[cfg(test)]
fn compare_state_to_other(&self, other: &Self) {
self._state.compare_state_to_other(&other._state);
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
#[cfg(feature = "safe_api")]
impl io::Write for Sha384 {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.update(bytes).map_err(io::Error::other)?;
Ok(bytes.len())
}
fn flush(&mut self) -> Result<(), io::Error> {
Ok(())
}
}
#[cfg(test)]
mod public {
use super::*;
#[test]
fn test_default_equals_new() {
let new = Sha384::new();
let default = Sha384::default();
new._state.compare_state_to_other(&default._state);
}
#[test]
#[cfg(feature = "safe_api")]
fn test_debug_impl() {
let initial_state = Sha384::new();
let debug = format!("{initial_state:?}");
let expected = "Sha384 { _state: State { working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, message_len: [WordU64(0), WordU64(0)], is_finalized: false } }";
assert_eq!(debug, expected);
}
mod test_streaming_interface {
use super::*;
use crate::test_framework::incremental_interface::*;
impl TestableStreamingContext<Digest> for Sha384 {
fn reset(&mut self) -> Result<(), UnknownCryptoError> {
self.reset();
Ok(())
}
fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
self.update(input)
}
fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
self.finalize()
}
fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
Sha384::digest(input)
}
fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
let actual: Digest = Self::one_shot(input)?;
if &actual == expected {
Ok(())
} else {
Err(UnknownCryptoError)
}
}
fn compare_states(state_1: &Sha384, state_2: &Sha384) {
state_1._state.compare_state_to_other(&state_2._state);
}
}
#[test]
fn default_consistency_tests() {
let initial_state: Sha384 = Sha384::new();
let test_runner = StreamingContextConsistencyTester::<Digest, Sha384>::new(
initial_state,
SHA384_BLOCKSIZE,
);
test_runner.run_all_tests();
}
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_input_to_consistency(data: Vec<u8>) -> bool {
let initial_state: Sha384 = Sha384::new();
let test_runner = StreamingContextConsistencyTester::<Digest, Sha384>::new(
initial_state,
SHA384_BLOCKSIZE,
);
test_runner.run_all_tests_property(&data);
true
}
}
#[cfg(feature = "safe_api")]
mod test_io_impls {
use crate::hazardous::hash::sha2::sha384::Sha384;
use std::io::Write;
#[quickcheck]
fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
let mut hasher_a = Sha384::new();
let mut hasher_b = hasher_a.clone();
hasher_a.update(&data).unwrap();
hasher_b.write_all(&data).unwrap();
hasher_b.flush().unwrap();
hasher_a._state.compare_state_to_other(&hasher_b._state);
let hash_a = hasher_a.finalize().unwrap();
let hash_b = hasher_b.finalize().unwrap();
hasher_b.flush().unwrap();
hasher_a._state.compare_state_to_other(&hasher_b._state);
hash_a == hash_b
}
}
}
#[cfg(test)]
mod private {
use super::*;
mod test_increment_mlen {
use super::*;
#[test]
fn test_mlen_increase_values() {
let mut context = Sha384::default();
context._state.increment_mlen(&WordU64::from(1u64));
assert_eq!(context._state.message_len[0], WordU64::from(0u64));
assert_eq!(context._state.message_len[1], WordU64::from(8u64));
context._state.increment_mlen(&WordU64::from(17u64));
assert_eq!(context._state.message_len[0], WordU64::from(0u64));
assert_eq!(context._state.message_len[1], WordU64::from(144u64));
context._state.increment_mlen(&WordU64::from(12u64));
assert_eq!(context._state.message_len[0], WordU64::from(0u64));
assert_eq!(context._state.message_len[1], WordU64::from(240u64));
context._state.increment_mlen(&WordU64::from(u64::MAX / 8));
assert_eq!(context._state.message_len[0], WordU64::from(1u64));
assert_eq!(context._state.message_len[1], WordU64::from(232u64));
}
#[test]
#[should_panic]
fn test_panic_on_second_overflow() {
use crate::hazardous::hash::sha2::sha2_core::Word;
let mut context = Sha384::default();
context._state.message_len = [WordU64::MAX, WordU64::from(u64::MAX - 7)];
context._state.increment_mlen(&WordU64::from(1u64));
}
}
}