#![no_std]
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
extern crate arrayvec;
extern crate constant_time_eq;
extern crate cty;
use arrayvec::{ArrayString, ArrayVec};
use constant_time_eq::constant_time_eq;
use core::fmt;
use core::mem;
use cty::c_void;
#[allow(warnings)]
mod sys;
#[cfg(test)]
mod test;
pub fn blake2b_512(input: &[u8]) -> Digest {
blake2b::State::new(64).update(input).finalize()
}
pub fn blake2b_256(input: &[u8]) -> Digest {
blake2b::State::new(32).update(input).finalize()
}
pub fn blake2s_256(input: &[u8]) -> Digest {
blake2s::State::new(32).update(input).finalize()
}
macro_rules! blake2_impl {
{
$name:ident,
$moddoc:meta,
$blockbytes:expr,
$outbytes:expr,
$keybytes:expr,
$saltbytes:expr,
$personalbytes:expr,
$param_type:path,
$state_type:path,
$init_param_fn:path,
$update_fn:path,
$finalize_fn:path,
$node_offset_max:expr,
$xof_length_type:ty,
} => {
#[$moddoc]
pub mod $name {
use super::*;
pub const BLOCKBYTES: usize = $blockbytes;
pub const OUTBYTES: usize = $outbytes;
pub const KEYBYTES: usize = $keybytes;
pub const SALTBYTES: usize = $saltbytes;
pub const PERSONALBYTES: usize = $personalbytes;
#[derive(Clone)]
pub struct Builder {
params: $param_type,
key_block: [u8; BLOCKBYTES as usize],
}
impl Builder {
pub fn new() -> Self {
let mut params: $param_type = unsafe { mem::zeroed() };
params.digest_length = OUTBYTES as u8;
params.fanout = 1;
params.depth = 1;
Self {
params,
key_block: [0; BLOCKBYTES],
}
}
pub fn build(&self) -> State {
let mut state;
let ret = unsafe {
state = State(mem::zeroed());
$init_param_fn(&mut state.0, &self.params)
};
assert_eq!(ret, 0, "BLAKE2 init returned an error");
debug_assert_eq!(self.params.digest_length as usize, state.0.outlen);
if self.params.key_length > 0 {
state.update(&self.key_block);
}
state
}
pub fn digest_length(&mut self, length: usize) -> &mut Self {
assert!(1 <= length && length <= OUTBYTES, "Bad digest length: {}", length);
self.params.digest_length = length as u8;
self
}
pub fn key(&mut self, key: &[u8]) -> &mut Self {
assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
self.key_block = [0; BLOCKBYTES];
self.key_block[..key.len()].copy_from_slice(key);
self.params.key_length = key.len() as u8;
self
}
pub fn fanout(&mut self, fanout: usize) -> &mut Self {
assert!(fanout <= 255, "Bad fanout: {}", fanout);
self.params.fanout = fanout as u8;
self
}
pub fn max_depth(&mut self, depth: usize) -> &mut Self {
assert!(1 <= depth && depth <= 255, "Bad max depth: {}", depth);
self.params.depth = depth as u8;
self
}
pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
self.params.leaf_length = length.to_le();
self
}
pub fn node_offset(&mut self, offset: u64) -> &mut Self {
assert!(offset <= $node_offset_max, "Bad node offset: {}", offset);
self.params.node_offset = (offset as u32).to_le();
self.params.xof_length = ((offset >> 32) as $xof_length_type).to_le();
self
}
pub fn node_depth(&mut self, depth: usize) -> &mut Self {
assert!(depth <= 255, "Bad node depth: {}", depth);
self.params.node_depth = depth as u8;
self
}
pub fn inner_hash_length(&mut self, length: usize) -> &mut Self {
assert!(length <= OUTBYTES, "Bad inner hash length: {}", length);
self.params.inner_length = length as u8;
self
}
pub fn salt(&mut self, salt: &[u8]) -> &mut Self {
assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len());
self.params.salt = [0; SALTBYTES];
self.params.salt[..salt.len()].copy_from_slice(salt);
self
}
pub fn personal(&mut self, personal: &[u8]) -> &mut Self {
assert!(personal.len() <= PERSONALBYTES, "Bad personalization length: {}", personal.len());
self.params.personal = [0; PERSONALBYTES];
self.params.personal[..personal.len()].copy_from_slice(personal);
self
}
}
impl fmt::Debug for Builder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Builder {{ params: ")?;
fmt::Debug::fmt(&self.params, f)?;
let key_str = if self.params.key_length == 0 { "<none>" } else { "<redacted>" };
write!(f, ", key={} }}", key_str)
}
}
#[derive(Clone)]
pub struct State($state_type);
impl State {
pub fn new(digest_length: usize) -> Self {
if digest_length == 0 || digest_length > OUTBYTES {
panic!("Bad digest length: {}", digest_length);
}
Builder::new().digest_length(digest_length).build()
}
pub fn update(&mut self, input: &[u8]) -> &mut Self {
let ret = unsafe {
$update_fn(&mut self.0, input.as_ptr() as *const c_void, input.len())
};
assert_eq!(ret, 0, "BLAKE2 update returned an error");
self
}
pub fn finalize(&mut self) -> Digest {
let mut bytes = ArrayVec::new();
let ret = unsafe {
bytes.set_len(self.0.outlen);
$finalize_fn(&mut self.0, bytes.as_mut_ptr() as *mut c_void, bytes.len())
};
assert_eq!(ret, 0, "BLAKE2 finalize returned an error");
Digest { bytes }
}
pub fn set_last_node(&mut self, val: bool) -> &mut Self {
self.0.last_node = val as u8;
self
}
}
impl fmt::Debug for State {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "State {{ outlen: {}, ... }}", self.0.outlen)
}
}
#[cfg(feature = "std")]
impl std::io::Write for State {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
}
}}
blake2_impl! {
blake2b,
doc="The more common version of BLAKE2, optimized for 64-bit processors.",
128,
64,
64,
16,
16,
sys::blake2b_param,
sys::blake2b_state,
sys::blake2b_init_param,
sys::blake2b_update,
sys::blake2b_final,
u64::max_value(),
u32,
}
blake2_impl! {
blake2s,
doc="The less common version of BLAKE2, optimized for smaller processors.",
64,
32,
32,
8,
8,
sys::blake2s_param,
sys::blake2s_state,
sys::blake2s_init_param,
sys::blake2s_update,
sys::blake2s_final,
((1 << 48) - 1),
u16,
}
#[derive(Clone, Debug)]
pub struct Digest {
pub bytes: ArrayVec<[u8; blake2b::OUTBYTES]>,
}
impl Digest {
pub fn hex(&self) -> ArrayString<[u8; 2 * blake2b::OUTBYTES]> {
use core::fmt::Write;
let mut hexdigest = ArrayString::new();
for &b in &self.bytes {
write!(&mut hexdigest, "{:02x}", b).expect("too many bytes");
}
hexdigest
}
}
impl PartialEq for Digest {
fn eq(&self, other: &Digest) -> bool {
constant_time_eq(&self.bytes, &other.bytes)
}
}
impl Eq for Digest {}