pbkdf2HmacSha1 function
PBKDF2-HMAC-SHA1, length bytes of key from password
Implementation
Uint8List pbkdf2HmacSha1(
Uint8List password, Uint8List salt, int iterations, int length) {
if (iterations < 1) {
throw ArgumentError.value(iterations, 'iterations', 'Must be positive');
}
final mac = HmacSha1(password);
final sha = mac._digest;
final w = sha._w;
final h = sha._state;
final pads = [mac._inner, mac._outer];
final out = Uint8List(length);
final index = Uint8List(4);
final first = Uint8List(20);
final u = Uint32List(5);
final t = Uint32List(5);
for (var block = 1, at = 0; at < length; block++, at += 20) {
index[0] = block >>> 24;
index[1] = (block >>> 16) & 0xff;
index[2] = (block >>> 8) & 0xff;
index[3] = block & 0xff;
mac
..update(salt, 0, salt.length)
..update(index, 0, 4)
..finish(first, 0);
for (var j = 0; j < 5; j++) {
final o = 4 * j;
u[j] = (first[o] << 24) |
(first[o + 1] << 16) |
(first[o + 2] << 8) |
first[o + 3];
t[j] = u[j];
}
// Each later message is the 20-byte MAC before it, so both hashes of an
// iteration are one block of words with 84 bytes as the length. Skipping
// update and finish took PBKDF2 from 1.71 to 1.32 ms on M4
for (var i = 1; i < iterations; i++) {
for (final pad in pads) {
w.setAll(0, u);
w[5] = 0x80000000;
w.fillRange(6, 15, 0);
w[15] = 84 * 8;
h.setAll(0, pad);
sha._compressBlock();
u.setAll(0, h);
}
for (var j = 0; j < 5; j++) {
t[j] ^= u[j];
}
}
sha._resume(mac._inner);
for (var j = 0; j < 20 && at + j < length; j++) {
out[at + j] = (t[j >>> 2] >>> (24 - 8 * (j & 3))) & 0xff;
}
}
return out;
}