1#[cfg(not(feature = "std"))]
12use alloc::vec::Vec;
13
14#[cfg(not(feature = "std"))]
15use core::{cmp::min, convert::TryInto};
16#[cfg(feature = "std")]
17use std::{cmp::min, convert::TryInto};
18
19use zeroize::Zeroize;
20
21use crate::error::{validate, Error, Result};
22use crate::hash::{HashAlgorithm, HashFunction};
23use crate::types::Digest;
24use dcrypt_common::security::{EphemeralSecret, SecretBuffer, SecureZeroingType};
25
26const BLAKE2B_BLOCK_SIZE: usize = 128;
30const BLAKE2B_MAX_OUTPUT_SIZE: usize = 64;
31const BLAKE2B_ROUNDS: usize = 12;
32const BLAKE2B_KEY_SIZE: usize = 64; pub(crate) const BLAKE2B_IV: [u64; 8] = [
36 0x6A09_E667_F3BC_C908,
37 0xBB67_AE85_84CA_A73B,
38 0x3C6E_F372_FE94_F82B,
39 0xA54F_F53A_5F1D_36F1,
40 0x510E_527F_ADE6_82D1,
41 0x9B05_688C_2B3E_6C1F,
42 0x1F83_D9AB_FB41_BD6B,
43 0x5BE0_CD19_137E_2179,
44];
45
46const BLAKE2B_SIGMA: [[usize; 16]; BLAKE2B_ROUNDS] = [
48 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
49 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
50 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
51 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
52 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
53 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
54 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
55 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
56 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
57 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
58 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
59 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
60];
61
62#[allow(missing_docs)]
66pub enum Blake2bAlgorithm {}
67impl HashAlgorithm for Blake2bAlgorithm {
68 const OUTPUT_SIZE: usize = BLAKE2B_MAX_OUTPUT_SIZE;
69 const BLOCK_SIZE: usize = BLAKE2B_BLOCK_SIZE;
70 const ALGORITHM_ID: &'static str = "BLAKE2b";
71}
72
73#[allow(missing_docs)]
77#[derive(Clone, Zeroize)]
78pub struct Blake2b {
79 pub(crate) h: [u64; 8],
80 pub(crate) t: [u64; 2],
81 pub(crate) f: [u64; 2],
82 pub(crate) buf: [u8; BLAKE2B_BLOCK_SIZE],
83 pub(crate) buf_len: usize,
84 pub(crate) out_len: usize,
85 pub(crate) key: Option<SecretBuffer<BLAKE2B_KEY_SIZE>>, pub(crate) is_keyed: bool,
87}
88impl Drop for Blake2b {
89 fn drop(&mut self) {
90 self.zeroize();
91 }
92}
93
94impl Blake2b {
98 pub fn with_output_size(out_len: usize) -> Self {
100 if !(1..=BLAKE2B_MAX_OUTPUT_SIZE).contains(&out_len) {
101 panic!("Blake2b output size must be between 1 and 64 bytes");
102 }
103 let mut h = BLAKE2B_IV;
104 h[0] ^= 0x0101_0000u64 | out_len as u64; Self {
106 h,
107 t: [0; 2],
108 f: [0; 2],
109 buf: [0; BLAKE2B_BLOCK_SIZE],
110 buf_len: 0,
111 out_len,
112 key: None,
113 is_keyed: false,
114 }
115 }
116
117 pub fn with_parameter_block(param: [u8; 64], out_len: usize) -> Self {
126 if !(1..=BLAKE2B_MAX_OUTPUT_SIZE).contains(&out_len) {
127 panic!("Blake2b output size must be between 1 and 64 bytes");
128 }
129
130 let mut h = BLAKE2B_IV;
131 for (i, chunk) in param.chunks_exact(8).enumerate() {
132 h[i] ^= u64::from_le_bytes(chunk.try_into().unwrap());
133 }
134
135 Self {
136 h,
137 t: [0; 2],
138 f: [0; 2],
139 buf: [0; BLAKE2B_BLOCK_SIZE],
140 buf_len: 0,
141 out_len,
142 key: None,
143 is_keyed: false,
144 }
145 }
146
147 pub fn with_key(key: &[u8], out_len: usize) -> Result<Self> {
154 if key.is_empty() || key.len() > BLAKE2B_KEY_SIZE {
155 return Err(Error::param(
156 "key",
157 "Key length must be between 1 and 64 bytes",
158 ));
159 }
160
161 let mut key_secret_buf_content = [0u8; BLAKE2B_KEY_SIZE];
163 key_secret_buf_content[..key.len()].copy_from_slice(key);
164
165 let mut h = BLAKE2B_IV;
166 let param0 = (out_len as u64) | ((key.len() as u64) << 8) | (1u64 << 16) | (1u64 << 24); h[0] ^= param0;
171
172 let mut blake2b = Blake2b {
173 h,
174 t: [0; 2],
175 f: [0; 2],
176 buf: [0; BLAKE2B_BLOCK_SIZE],
177 buf_len: 0,
178 out_len,
179 key: Some(SecretBuffer::new(key_secret_buf_content)),
180 is_keyed: true,
181 };
182
183 let mut key_block_padded = [0u8; BLAKE2B_BLOCK_SIZE];
185 key_block_padded[..key.len()].copy_from_slice(key);
186 blake2b.update_internal(&key_block_padded)?;
187
188 Ok(blake2b)
189 }
190
191 #[inline(always)]
196 fn blake2b_g(v: &mut [u64; 16], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
197 v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
198 v[d] = (v[d] ^ v[a]).rotate_right(32);
199 v[c] = v[c].wrapping_add(v[d]);
200 v[b] = (v[b] ^ v[c]).rotate_right(24);
201 v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
202 v[d] = (v[d] ^ v[a]).rotate_right(16);
203 v[c] = v[c].wrapping_add(v[d]);
204 v[b] = (v[b] ^ v[c]).rotate_right(63);
205 }
206
207 fn compress(&mut self, last: bool) -> Result<()> {
208 let mut v = [0u64; 16];
209 v[..8].copy_from_slice(&self.h);
210 v[8..].copy_from_slice(&BLAKE2B_IV);
211 v[12] ^= self.t[0];
212 v[13] ^= self.t[1];
213 if last {
214 v[14] ^= 0xFFFF_FFFF_FFFF_FFFF;
215 } let mut m = [0u64; 16];
218 for (i, elem) in m.iter_mut().enumerate().take(16) {
219 let idx = i * 8;
220 validate::max_length("BLAKE2b buffer slice", idx + 8, self.buf.len())?;
221 *elem = u64::from_le_bytes(self.buf[idx..idx + 8].try_into().map_err(|_| {
222 Error::Processing {
223 operation: "BLAKE2b compression",
224 details: "Failed to convert bytes to u64",
225 }
226 })?);
227 }
228 let m_ephemeral = EphemeralSecret::new(m);
229 for s in BLAKE2B_SIGMA.iter().take(BLAKE2B_ROUNDS) {
230 Self::blake2b_g(&mut v, 0, 4, 8, 12, m_ephemeral[s[0]], m_ephemeral[s[1]]);
231 Self::blake2b_g(&mut v, 1, 5, 9, 13, m_ephemeral[s[2]], m_ephemeral[s[3]]);
232 Self::blake2b_g(&mut v, 2, 6, 10, 14, m_ephemeral[s[4]], m_ephemeral[s[5]]);
233 Self::blake2b_g(&mut v, 3, 7, 11, 15, m_ephemeral[s[6]], m_ephemeral[s[7]]);
234 Self::blake2b_g(&mut v, 0, 5, 10, 15, m_ephemeral[s[8]], m_ephemeral[s[9]]);
235 Self::blake2b_g(&mut v, 1, 6, 11, 12, m_ephemeral[s[10]], m_ephemeral[s[11]]);
236 Self::blake2b_g(&mut v, 2, 7, 8, 13, m_ephemeral[s[12]], m_ephemeral[s[13]]);
237 Self::blake2b_g(&mut v, 3, 4, 9, 14, m_ephemeral[s[14]], m_ephemeral[s[15]]);
238 }
239 for i in 0..8 {
240 self.h[i] ^= v[i] ^ v[i + 8];
241 }
242 Ok(())
243 }
244
245 fn update_internal(&mut self, mut input: &[u8]) -> Result<()> {
246 while !input.is_empty() {
247 let fill = min(input.len(), BLAKE2B_BLOCK_SIZE - self.buf_len);
248 self.buf[self.buf_len..self.buf_len + fill].copy_from_slice(&input[..fill]);
249 self.buf_len += fill;
250 input = &input[fill..];
251
252 if self.buf_len == BLAKE2B_BLOCK_SIZE {
253 if input.is_empty() {
254 break;
256 }
257 let inc = BLAKE2B_BLOCK_SIZE as u64;
259 self.t[0] = self.t[0].wrapping_add(inc);
260 if self.t[0] < inc {
261 self.t[1] = self.t[1].wrapping_add(1);
262 }
263 self.compress(false)?;
264 self.buf_len = 0;
265 }
266 }
267 Ok(())
268 }
269
270 fn finalize_internal(&mut self) -> Result<Vec<u8>> {
271 let inc = self.buf_len as u64;
273 self.t[0] = self.t[0].wrapping_add(inc);
274 if self.t[0] < inc {
275 self.t[1] = self.t[1].wrapping_add(1);
276 }
277
278 for b in &mut self.buf[self.buf_len..] {
280 *b = 0;
281 }
282 self.compress(true)?;
283
284 let mut out = Vec::with_capacity(self.out_len);
286 for &w in &self.h {
287 out.extend_from_slice(&w.to_le_bytes());
288 }
289 out.truncate(self.out_len);
290 Ok(out)
291 }
292}
293
294impl HashFunction for Blake2b {
295 type Algorithm = Blake2bAlgorithm;
296 type Output = Digest<BLAKE2B_MAX_OUTPUT_SIZE>;
297
298 fn new() -> Self {
299 Blake2b::with_output_size(BLAKE2B_MAX_OUTPUT_SIZE)
300 }
301
302 fn update(&mut self, input: &[u8]) -> Result<&mut Self> {
303 self.update_internal(input)?;
304 Ok(self)
305 }
306
307 fn finalize(&mut self) -> Result<Self::Output> {
308 let hash = self.finalize_internal()?;
309 let mut digest = [0u8; BLAKE2B_MAX_OUTPUT_SIZE];
310 digest[..hash.len()].copy_from_slice(&hash);
311 Ok(Digest::with_len(digest, self.out_len))
312 }
313
314 fn output_size() -> usize {
315 Self::Algorithm::OUTPUT_SIZE
316 }
317 fn block_size() -> usize {
318 Self::Algorithm::BLOCK_SIZE
319 }
320 fn name() -> String {
321 Self::Algorithm::ALGORITHM_ID.to_string()
322 }
323}
324
325const BLAKE2S_BLOCK_SIZE: usize = 64;
327const BLAKE2S_MAX_OUTPUT_SIZE: usize = 32;
328const BLAKE2S_ROUNDS: usize = 10;
329const BLAKE2S_KEY_SIZE: usize = 32; const BLAKE2S_IV: [u32; 8] = [
331 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
332];
333const BLAKE2S_SIGMA: [[usize; 16]; BLAKE2S_ROUNDS] = [
334 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
335 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
336 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
337 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
338 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
339 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
340 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
341 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
342 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
343 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
344];
345
346pub enum Blake2sAlgorithm {}
348
349impl HashAlgorithm for Blake2sAlgorithm {
351 const OUTPUT_SIZE: usize = BLAKE2S_MAX_OUTPUT_SIZE;
352 const BLOCK_SIZE: usize = BLAKE2S_BLOCK_SIZE;
353 const ALGORITHM_ID: &'static str = "BLAKE2s";
354}
355
356#[derive(Clone, Zeroize)]
358pub struct Blake2s {
359 h: [u32; 8],
360 t: [u32; 2],
361 f: [u32; 2],
362 buf: [u8; BLAKE2S_BLOCK_SIZE],
363 buf_len: usize,
364 out_len: usize,
365 key: Option<SecretBuffer<BLAKE2S_KEY_SIZE>>, is_keyed: bool,
367}
368
369impl Drop for Blake2s {
371 fn drop(&mut self) {
372 self.zeroize();
373 }
374}
375
376impl Blake2s {
377 pub fn with_output_size(out_len: usize) -> Self {
387 if out_len == 0 || out_len > BLAKE2S_MAX_OUTPUT_SIZE {
388 panic!("Blake2s output size must be between 1 and 32 bytes");
389 }
390 let mut h = BLAKE2S_IV;
391 let param0 = (out_len as u32) | (1u32 << 16) | (1u32 << 24); h[0] ^= param0;
394 Blake2s {
395 h,
396 t: [0; 2],
397 f: [0; 2],
398 buf: [0; BLAKE2S_BLOCK_SIZE],
399 buf_len: 0,
400 out_len,
401 key: None,
402 is_keyed: false,
403 }
404 }
405
406 pub fn with_key(key: &[u8], out_len: usize) -> Result<Self> {
413 if key.is_empty() || key.len() > BLAKE2S_KEY_SIZE {
414 return Err(Error::param(
415 "key",
416 "Key length must be between 1 and 32 bytes",
417 ));
418 }
419
420 let mut key_secret_buf_content = [0u8; BLAKE2S_KEY_SIZE];
422 key_secret_buf_content[..key.len()].copy_from_slice(key);
423
424 let mut h = BLAKE2S_IV;
425 let param0 = (out_len as u32) | ((key.len() as u32) << 8) | (1u32 << 16) | (1u32 << 24); h[0] ^= param0;
431
432 let mut blake2s = Blake2s {
433 h,
434 t: [0; 2],
435 f: [0; 2],
436 buf: [0; BLAKE2S_BLOCK_SIZE],
437 buf_len: 0,
438 out_len,
439 key: Some(SecretBuffer::new(key_secret_buf_content)),
440 is_keyed: true,
441 };
442
443 let mut key_block_padded = [0u8; BLAKE2S_BLOCK_SIZE];
446 key_block_padded[..key.len()].copy_from_slice(key);
447
448 blake2s.update_internal(&key_block_padded)?;
449
450 Ok(blake2s)
451 }
452
453 fn g(v: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize, x: u32, y: u32) {
454 v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
455 v[d] = (v[d] ^ v[a]).rotate_right(16);
456 v[c] = v[c].wrapping_add(v[d]);
457 v[b] = (v[b] ^ v[c]).rotate_right(12);
458 v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
459 v[d] = (v[d] ^ v[a]).rotate_right(8);
460 v[c] = v[c].wrapping_add(v[d]);
461 v[b] = (v[b] ^ v[c]).rotate_right(7);
462 }
463
464 fn compress(&mut self, last: bool) -> Result<()> {
465 let mut v = [0u32; 16];
466 v[..8].copy_from_slice(&self.h);
467 v[8..].copy_from_slice(&BLAKE2S_IV);
468 v[12] ^= self.t[0];
469 v[13] ^= self.t[1];
470 if last {
471 v[14] = !v[14];
472 }
473
474 let mut m = [0u32; 16];
475 for (i, elem) in m.iter_mut().enumerate().take(16) {
476 let idx = i * 4;
477 validate::max_length("BLAKE2s buffer slice", idx + 4, self.buf.len())?;
479
480 *elem = u32::from_le_bytes(self.buf[idx..idx + 4].try_into().map_err(|_| {
482 Error::Processing {
483 operation: "BLAKE2s compression",
484 details: "Failed to convert bytes to u32",
485 }
486 })?);
487 }
488
489 let m_ephemeral = EphemeralSecret::new(m);
491
492 for s in BLAKE2S_SIGMA.iter().take(BLAKE2S_ROUNDS) {
493 Self::g(&mut v, 0, 4, 8, 12, m_ephemeral[s[0]], m_ephemeral[s[1]]);
494 Self::g(&mut v, 1, 5, 9, 13, m_ephemeral[s[2]], m_ephemeral[s[3]]);
495 Self::g(&mut v, 2, 6, 10, 14, m_ephemeral[s[4]], m_ephemeral[s[5]]);
496 Self::g(&mut v, 3, 7, 11, 15, m_ephemeral[s[6]], m_ephemeral[s[7]]);
497 Self::g(&mut v, 0, 5, 10, 15, m_ephemeral[s[8]], m_ephemeral[s[9]]);
498 Self::g(&mut v, 1, 6, 11, 12, m_ephemeral[s[10]], m_ephemeral[s[11]]);
499 Self::g(&mut v, 2, 7, 8, 13, m_ephemeral[s[12]], m_ephemeral[s[13]]);
500 Self::g(&mut v, 3, 4, 9, 14, m_ephemeral[s[14]], m_ephemeral[s[15]]);
501 }
502
503 for i in 0..8 {
504 self.h[i] ^= v[i] ^ v[i + 8];
505 }
506
507 Ok(())
508 }
509
510 fn update_internal(&mut self, mut input: &[u8]) -> Result<()> {
511 while !input.is_empty() {
512 let fill = min(input.len(), BLAKE2S_BLOCK_SIZE - self.buf_len);
513 self.buf[self.buf_len..self.buf_len + fill].copy_from_slice(&input[..fill]);
514 self.buf_len += fill;
515 input = &input[fill..];
516
517 if self.buf_len == BLAKE2S_BLOCK_SIZE {
518 if input.is_empty() {
519 break;
521 }
522 let inc = BLAKE2S_BLOCK_SIZE as u32;
524 self.t[0] = self.t[0].wrapping_add(inc);
525 if self.t[0] < inc {
526 self.t[1] = self.t[1].wrapping_add(1);
527 }
528 self.compress(false)?;
529 self.buf_len = 0;
530 }
531 }
532 Ok(())
533 }
534
535 fn finalize_internal(&mut self) -> Result<Vec<u8>> {
536 let inc = self.buf_len as u32;
538 self.t[0] = self.t[0].wrapping_add(inc);
539 if self.t[0] < inc {
540 self.t[1] = self.t[1].wrapping_add(1);
541 }
542
543 for b in &mut self.buf[self.buf_len..] {
545 *b = 0;
546 }
547 self.compress(true)?;
548
549 let mut out = Vec::with_capacity(self.out_len);
551 for &w in &self.h {
552 out.extend_from_slice(&w.to_le_bytes());
553 }
554 out.truncate(self.out_len);
555 Ok(out)
556 }
557}
558
559impl HashFunction for Blake2s {
560 type Algorithm = Blake2sAlgorithm;
561 type Output = Digest<BLAKE2S_MAX_OUTPUT_SIZE>;
562
563 fn new() -> Self {
564 Blake2s::with_output_size(BLAKE2S_MAX_OUTPUT_SIZE)
565 }
566
567 fn update(&mut self, input: &[u8]) -> Result<&mut Self> {
568 self.update_internal(input)?;
569 Ok(self)
570 }
571
572 fn finalize(&mut self) -> Result<Self::Output> {
573 let hash = self.finalize_internal()?;
574 let mut digest = [0u8; BLAKE2S_MAX_OUTPUT_SIZE];
575 digest[..hash.len()].copy_from_slice(&hash);
576 Ok(Digest::with_len(digest, self.out_len))
578 }
579
580 fn output_size() -> usize {
581 Self::Algorithm::OUTPUT_SIZE
582 }
583
584 fn block_size() -> usize {
585 Self::Algorithm::BLOCK_SIZE
586 }
587
588 fn name() -> String {
589 Self::Algorithm::ALGORITHM_ID.to_string()
590 }
591}
592
593impl SecureZeroingType for Blake2b {
595 fn zeroed() -> Self {
596 Blake2b::with_output_size(BLAKE2B_MAX_OUTPUT_SIZE)
597 }
598
599 fn secure_clone(&self) -> Self {
600 self.clone()
601 }
602}
603
604impl SecureZeroingType for Blake2s {
605 fn zeroed() -> Self {
606 Blake2s::with_output_size(BLAKE2S_MAX_OUTPUT_SIZE)
607 }
608
609 fn secure_clone(&self) -> Self {
610 self.clone()
611 }
612}
613
614#[cfg(test)]
615mod tests;