PBKDF: implement argon2id
This commit is contained in:
1 parent
1fcf38db41
commit
b30b5d0add
13 files changed
+1291
-148
No files matched your search
@@ -0,0 +1,134 @@
|
||||
/// One Argon2 memory block is 1024 bytes = 128 × u64.
|
||||
pub(super) const BLOCK_WORDS: usize = 128;
|
||||
|
||||
/// One Argon2 memory block is 1024 bytes.
|
||||
pub(super) const BLOCK_SIZE: usize = 1024;
|
||||
|
||||
/// A single 1024-byte Argon2 memory block.
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct Block(pub(super) [u64; BLOCK_WORDS]);
|
||||
|
||||
impl Block {
|
||||
pub(super) const ZERO: Self = Self([0u64; BLOCK_WORDS]);
|
||||
}
|
||||
|
||||
/// Argon2 compression function G.
|
||||
///
|
||||
/// R = X XOR Y
|
||||
/// Z = P(R)
|
||||
/// output = Z XOR R
|
||||
///
|
||||
/// On passes after the first, the old contents of the destination block are also XORed into the result.
|
||||
pub(super) fn compress_block(previous: &Block, reference: &Block, old: Option<&Block>) -> Block {
|
||||
let mut r = [0u64; BLOCK_WORDS];
|
||||
|
||||
for (dst, (&a, &b)) in r.iter_mut().zip(previous.0.iter().zip(reference.0.iter())) {
|
||||
*dst = a ^ b;
|
||||
}
|
||||
|
||||
/*
|
||||
* P(R), first over rows and then over columns.
|
||||
*/
|
||||
let mut z = r;
|
||||
|
||||
/*
|
||||
* Row-wise permutation.
|
||||
*/
|
||||
for row in 0..8 {
|
||||
let start = row * 16;
|
||||
|
||||
let mut words = [0u64; 16];
|
||||
|
||||
words.copy_from_slice(&z[start..start + 16]);
|
||||
|
||||
round(&mut words);
|
||||
|
||||
z[start..start + 16].copy_from_slice(&words);
|
||||
}
|
||||
|
||||
/*
|
||||
* Column-wise permutation.
|
||||
*
|
||||
* Each permutation operates on two adjacent 64-bit
|
||||
* columns from each of the eight rows.
|
||||
*/
|
||||
for column_pair in 0..8 {
|
||||
let mut words = [0u64; 16];
|
||||
|
||||
for row in 0..8 {
|
||||
let source = row * 16 + column_pair * 2;
|
||||
|
||||
words[row * 2] = z[source];
|
||||
|
||||
words[row * 2 + 1] = z[source + 1];
|
||||
}
|
||||
|
||||
round(&mut words);
|
||||
|
||||
for row in 0..8 {
|
||||
let destination = row * 16 + column_pair * 2;
|
||||
|
||||
z[destination] = words[row * 2];
|
||||
|
||||
z[destination + 1] = words[row * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = [0u64; BLOCK_WORDS];
|
||||
|
||||
for i in 0..BLOCK_WORDS {
|
||||
output[i] = z[i] ^ r[i] ^ old.map_or(0, |block| block.0[i]);
|
||||
}
|
||||
|
||||
Block(output)
|
||||
}
|
||||
|
||||
/// The Argon2/BLAKE2b quarter-round.
|
||||
///
|
||||
/// This is the BlaMka operation used by Argon2.
|
||||
#[inline(always)]
|
||||
fn g(v: &mut [u64; 16], a: usize, b: usize, c: usize, d: usize) {
|
||||
v[a] = blamka(v[a], v[b]);
|
||||
|
||||
v[d] = (v[d] ^ v[a]).rotate_right(32);
|
||||
|
||||
v[c] = blamka(v[c], v[d]);
|
||||
|
||||
v[b] = (v[b] ^ v[c]).rotate_right(24);
|
||||
|
||||
v[a] = blamka(v[a], v[b]);
|
||||
|
||||
v[d] = (v[d] ^ v[a]).rotate_right(16);
|
||||
|
||||
v[c] = blamka(v[c], v[d]);
|
||||
|
||||
v[b] = (v[b] ^ v[c]).rotate_right(63);
|
||||
}
|
||||
|
||||
/// BlaMka addition:
|
||||
///
|
||||
/// a + b + 2 * low32(a) * low32(b) mod 2^64.
|
||||
#[inline(always)]
|
||||
fn blamka(a: u64, b: u64) -> u64 {
|
||||
let product = 2u64
|
||||
.wrapping_mul(a & 0xffff_ffff)
|
||||
.wrapping_mul(b & 0xffff_ffff);
|
||||
|
||||
a.wrapping_add(b).wrapping_add(product)
|
||||
}
|
||||
|
||||
/// One BLAKE2b style 16 word round used by Argon2.
|
||||
#[inline(always)]
|
||||
fn round(v: &mut [u64; 16]) {
|
||||
// Column step.
|
||||
g(v, 0, 4, 8, 12);
|
||||
g(v, 1, 5, 9, 13);
|
||||
g(v, 2, 6, 10, 14);
|
||||
g(v, 3, 7, 11, 15);
|
||||
|
||||
// Diagonal step.
|
||||
g(v, 0, 5, 10, 15);
|
||||
g(v, 1, 6, 11, 12);
|
||||
g(v, 2, 7, 8, 13);
|
||||
g(v, 3, 4, 9, 14);
|
||||
}
|
||||
Reference in new issue
Block a user