blake2b_ref/
wrapper.rs

1use crate::blake2b_ref::{
2    blake2b_final, blake2b_init_key_with_param, blake2b_init_param, blake2b_param, blake2b_state,
3    blake2b_update, size_t, BLAKE2B_KEYBYTES, BLAKE2B_OUTBYTES, BLAKE2B_PERSONALBYTES,
4    BLAKE2B_SALTBYTES,
5};
6use crate::libc::*;
7
8pub struct Blake2b {
9    pub(crate) state: blake2b_state,
10}
11
12pub struct Blake2bBuilder {
13    pub(crate) state: blake2b_state,
14    pub(crate) param: blake2b_param,
15    pub(crate) key_len: usize,
16    pub(crate) key: [u8; BLAKE2B_KEYBYTES as usize],
17}
18
19impl Blake2bBuilder {
20    pub fn new(out_len: usize) -> Self {
21        assert!(out_len >= 1 && out_len <= BLAKE2B_OUTBYTES as usize);
22        let param = blake2b_param {
23            digest_length: out_len as u8,
24            key_length: 0,
25            fanout: 1,
26            depth: 1,
27            leaf_length: 0,
28            node_offset: 0,
29            xof_length: 0,
30            node_depth: 0,
31            inner_length: 0,
32            reserved: [0u8; 14usize],
33            salt: [0u8; BLAKE2B_SALTBYTES as usize],
34            personal: [0u8; BLAKE2B_PERSONALBYTES as usize],
35        };
36        let state = unsafe { ::core::mem::MaybeUninit::zeroed().assume_init() }; // initialize when build called
37        let key_len = 0;
38        let key = [0u8; BLAKE2B_KEYBYTES as usize];
39
40        Blake2bBuilder {
41            param,
42            state,
43            key_len,
44            key,
45        }
46    }
47
48    pub fn salt(mut self, salt: &[u8]) -> Blake2bBuilder {
49        let len = salt.len();
50        assert!(len <= BLAKE2B_SALTBYTES as usize);
51
52        unsafe {
53            ::core::ptr::copy_nonoverlapping(salt.as_ptr(), self.param.salt.as_mut_ptr(), len);
54        }
55        self
56    }
57
58    pub fn personal(mut self, personal: &[u8]) -> Blake2bBuilder {
59        let len = personal.len();
60        assert!(len <= BLAKE2B_PERSONALBYTES as usize);
61
62        unsafe {
63            ::core::ptr::copy_nonoverlapping(
64                personal.as_ptr(),
65                self.param.personal.as_mut_ptr(),
66                len,
67            );
68        }
69        self
70    }
71
72    pub fn key(mut self, key: &[u8]) -> Blake2bBuilder {
73        let key_len = key.len();
74        assert!(key_len <= BLAKE2B_KEYBYTES as usize);
75        self.param.key_length = key_len as u8;
76        self.key_len = key_len;
77
78        unsafe {
79            ::core::ptr::copy_nonoverlapping(key.as_ptr(), self.key.as_mut_ptr(), key_len);
80        }
81        self
82    }
83
84    pub fn build(self) -> Blake2b {
85        let Blake2bBuilder {
86            mut state,
87            param,
88            key,
89            key_len,
90        } = self;
91        if self.key_len == 0 {
92            unsafe {
93                blake2b_init_param(
94                    &mut state as *mut blake2b_state,
95                    &param as *const blake2b_param,
96                );
97            }
98        } else {
99            unsafe {
100                blake2b_init_key_with_param(
101                    &mut state as *mut blake2b_state,
102                    &param as *const blake2b_param,
103                    key.as_ptr() as *const c_void,
104                    key_len as size_t,
105                );
106            }
107        }
108        Blake2b { state }
109    }
110}
111
112impl Blake2b {
113    pub fn update(&mut self, data: &[u8]) {
114        unsafe {
115            blake2b_update(
116                &mut self.state as *mut blake2b_state,
117                data.as_ptr() as *const c_void,
118                data.len() as size_t,
119            );
120        }
121    }
122
123    pub fn finalize(mut self, dst: &mut [u8]) {
124        unsafe {
125            blake2b_final(
126                &mut self.state as *mut blake2b_state,
127                dst.as_mut_ptr() as *mut c_void,
128                dst.len() as size_t,
129            );
130        }
131    }
132}
133
134pub fn blake2b(key: &[u8], data: &[u8], dst: &mut [u8]) {
135    let mut blake2b = Blake2bBuilder::new(dst.len()).key(key).build();
136    blake2b.update(data);
137    blake2b.finalize(dst)
138}
139
140#[cfg(test)]
141mod tests {
142    use super::Blake2bBuilder;
143    use faster_hex::{hex_decode, hex_string};
144    use serde_derive::Deserialize;
145    use std::fs::File;
146    use std::io::BufReader;
147    use std::path::Path;
148
149    #[derive(Deserialize, Debug)]
150    struct TestItem {
151        outlen: usize,
152        out: String,
153        input: String,
154        key: String,
155        salt: String,
156        personal: String,
157    }
158
159    #[test]
160    fn test_full() {
161        let test_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("fixtures/test.json");
162
163        let f = File::open(test_path).unwrap();
164        let reader = BufReader::new(f);
165        let tests: Vec<TestItem> = serde_json::from_reader(reader).unwrap();
166
167        for test in tests {
168            let mut hash = vec![0u8; test.outlen];
169            let mut blake2b = Blake2bBuilder::new(test.outlen)
170                .key(&unhex(test.key.as_bytes()))
171                .personal(&unhex(test.personal.as_bytes()))
172                .salt(&unhex(test.salt.as_bytes()))
173                .build();
174            blake2b.update(&unhex(test.input.as_bytes()));
175            blake2b.finalize(&mut hash);
176            assert_eq!(hex_string(&hash).unwrap(), test.out);
177        }
178    }
179
180    fn unhex(src: &[u8]) -> Vec<u8> {
181        let len = src.len() / 2;
182        let mut ret = vec![0u8; len];
183        if !src.is_empty() {
184            hex_decode(src, &mut ret).unwrap();
185        }
186        ret
187    }
188}