#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use evercrypt_sys::evercrypt_bindings::*;
#[derive(Debug)]
pub enum Error {
InvalidStateFinished,
ModeUnsupportedForStreaming,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Mode {
Sha1 = Spec_Hash_Definitions_SHA1 as isize,
Sha224 = Spec_Hash_Definitions_SHA2_224 as isize,
Sha256 = Spec_Hash_Definitions_SHA2_256 as isize,
Sha384 = Spec_Hash_Definitions_SHA2_384 as isize,
Sha512 = Spec_Hash_Definitions_SHA2_512 as isize,
Blake2s = Spec_Hash_Definitions_Blake2S as isize,
Blake2b = Spec_Hash_Definitions_Blake2B as isize,
Sha3_224 = 8,
Sha3_256 = 9,
Sha3_384 = 10,
Sha3_512 = 11,
}
#[allow(non_upper_case_globals)]
impl From<u32> for Mode {
fn from(v: u32) -> Mode {
match v {
Spec_Hash_Definitions_SHA1 => Mode::Sha1,
Spec_Hash_Definitions_SHA2_224 => Mode::Sha224,
Spec_Hash_Definitions_SHA2_256 => Mode::Sha256,
Spec_Hash_Definitions_SHA2_384 => Mode::Sha384,
Spec_Hash_Definitions_SHA2_512 => Mode::Sha512,
Spec_Hash_Definitions_Blake2S => Mode::Blake2s,
Spec_Hash_Definitions_Blake2B => Mode::Blake2b,
8 => Mode::Sha3_224,
9 => Mode::Sha3_256,
10 => Mode::Sha3_384,
11 => Mode::Sha3_512,
_ => panic!("Unknown Digest mode {}", v),
}
}
}
impl From<Mode> for Spec_Hash_Definitions_hash_alg {
fn from(v: Mode) -> Spec_Hash_Definitions_hash_alg {
match v {
Mode::Sha1 => Spec_Hash_Definitions_SHA1 as Spec_Hash_Definitions_hash_alg,
Mode::Sha224 => Spec_Hash_Definitions_SHA2_224 as Spec_Hash_Definitions_hash_alg,
Mode::Sha256 => Spec_Hash_Definitions_SHA2_256 as Spec_Hash_Definitions_hash_alg,
Mode::Sha384 => Spec_Hash_Definitions_SHA2_384 as Spec_Hash_Definitions_hash_alg,
Mode::Sha512 => Spec_Hash_Definitions_SHA2_512 as Spec_Hash_Definitions_hash_alg,
Mode::Blake2s => Spec_Hash_Definitions_Blake2S as Spec_Hash_Definitions_hash_alg,
Mode::Blake2b => Spec_Hash_Definitions_Blake2B as Spec_Hash_Definitions_hash_alg,
Mode::Sha3_224 => 8,
Mode::Sha3_256 => 9,
Mode::Sha3_384 => 10,
Mode::Sha3_512 => 11,
}
}
}
pub fn get_digest_size(mode: Mode) -> usize {
match mode {
Mode::Sha1 => 20,
Mode::Sha224 => 28,
Mode::Sha256 => 32,
Mode::Sha384 => 48,
Mode::Sha512 => 64,
Mode::Blake2s => 32,
Mode::Blake2b => 64,
Mode::Sha3_224 => 28,
Mode::Sha3_256 => 32,
Mode::Sha3_384 => 48,
Mode::Sha3_512 => 64,
}
}
fn is_sha3(alg: Mode) -> bool {
match alg {
Mode::Sha3_224 | Mode::Sha3_256 | Mode::Sha3_384 | Mode::Sha3_512 => true,
_ => false,
}
}
pub struct Digest {
mode: Mode,
finished: bool,
c_state: *mut Hacl_Streaming_Functor_state_s___EverCrypt_Hash_state_s____,
}
impl Digest {
pub fn new(alg: Mode) -> Result<Self, Error> {
if is_sha3(alg) {
return Err(Error::ModeUnsupportedForStreaming);
}
let c_state: *mut Hacl_Streaming_Functor_state_s___EverCrypt_Hash_state_s____ =
unsafe { EverCrypt_Hash_Incremental_create_in(alg.into()) };
Ok(Self {
mode: alg,
finished: false,
c_state,
})
}
pub fn update(&mut self, data: &[u8]) -> Result<(), Error> {
if self.finished {
return Err(Error::InvalidStateFinished);
}
unsafe {
EverCrypt_Hash_Incremental_update(self.c_state, data.as_ptr() as _, data.len() as u32);
}
Ok(())
}
pub fn finish(&mut self) -> Result<Vec<u8>, Error> {
if self.finished {
return Err(Error::InvalidStateFinished);
}
let mut out = vec![0u8; get_digest_size(self.mode)];
unsafe {
EverCrypt_Hash_Incremental_finish(self.c_state, out.as_mut_ptr());
EverCrypt_Hash_Incremental_free(self.c_state);
}
self.finished = true;
Ok(out)
}
}
macro_rules! define_plain_digest {
($name:ident, $version:expr, $l:literal) => {
pub fn $name(data: &[u8]) -> [u8; $l] {
let mut out = [0u8; $l];
match $version {
Mode::Sha3_224 => unsafe {
Hacl_SHA3_sha3_224(data.len() as u32, data.as_ptr() as _, out.as_mut_ptr())
},
Mode::Sha3_256 => unsafe {
Hacl_SHA3_sha3_256(data.len() as u32, data.as_ptr() as _, out.as_mut_ptr())
},
Mode::Sha3_384 => unsafe {
Hacl_SHA3_sha3_384(data.len() as u32, data.as_ptr() as _, out.as_mut_ptr())
},
Mode::Sha3_512 => unsafe {
Hacl_SHA3_sha3_512(data.len() as u32, data.as_ptr() as _, out.as_mut_ptr())
},
_ => unsafe {
EverCrypt_Hash_hash(
$version.into(),
out.as_mut_ptr(),
data.as_ptr() as _,
data.len() as u32,
);
},
}
out
}
};
}
define_plain_digest!(sha1, Mode::Sha1, 20);
define_plain_digest!(sha224, Mode::Sha224, 28);
define_plain_digest!(sha256, Mode::Sha256, 32);
define_plain_digest!(sha384, Mode::Sha384, 48);
define_plain_digest!(sha512, Mode::Sha512, 64);
define_plain_digest!(sha3_224, Mode::Sha3_224, 28);
define_plain_digest!(sha3_256, Mode::Sha3_256, 32);
define_plain_digest!(sha3_384, Mode::Sha3_384, 48);
define_plain_digest!(sha3_512, Mode::Sha3_512, 64);
define_plain_digest!(blake2s, Mode::Blake2s, 32);
define_plain_digest!(blake2b, Mode::Blake2b, 64);
pub fn hash(alg: Mode, data: &[u8]) -> Vec<u8> {
match alg {
Mode::Sha1 => sha1(data).to_vec(),
Mode::Sha224 => sha224(data).to_vec(),
Mode::Sha256 => sha256(data).to_vec(),
Mode::Sha384 => sha384(data).to_vec(),
Mode::Sha512 => sha512(data).to_vec(),
Mode::Sha3_224 => sha3_224(data).to_vec(),
Mode::Sha3_256 => sha3_256(data).to_vec(),
Mode::Sha3_384 => sha3_384(data).to_vec(),
Mode::Sha3_512 => sha3_512(data).to_vec(),
Mode::Blake2s => blake2s(data).to_vec(),
Mode::Blake2b => blake2b(data).to_vec(),
}
}
pub fn shake128(data: &[u8], out_len: usize) -> Vec<u8> {
let mut out = vec![0u8; out_len];
unsafe {
Hacl_SHA3_shake128_hacl(
data.len() as u32,
data.as_ptr() as _,
out_len as u32,
out.as_mut_ptr(),
);
}
out
}
pub fn shake256(data: &[u8], out_len: usize) -> Vec<u8> {
let mut out = vec![0u8; out_len];
unsafe {
Hacl_SHA3_shake256_hacl(
data.len() as u32,
data.as_ptr() as _,
out_len as u32,
out.as_mut_ptr(),
);
}
out
}