HMAC constructor
Creates an HMAC instance with the specified hash function and secret key.
Example:
final key = List<int>.from([0x00, 0x01, 0x02]);
final hmac = HMAC(()=>SHA256(), key);
The hash
parameter should be a function that returns a hash instance, e.g., SHA1, SHA256, etc.
The key
is the secret key as a List<int>
.
The optional blockSize
parameter sets the block size for the HMAC.
If not provided, it defaults to the block size of the hash function.
Implementation
HMAC(HashFunc hash, List<int> key, [int? blockSize]) {
_blockSize = blockSize;
// Initialize inner and outer hashes.
_inner = hash();
_outer = hash();
// Pad temporary stores a key (or its hash) padded with zeroes.
final pad = List<int>.filled(getBlockSize, 0);
if (key.length > getBlockSize) {
// If key is bigger than hash block size, it must be
// hashed and this hash is used as a key instead.
_inner.update(key)
..finish(pad)
..clean();
} else {
// Otherwise, copy the key into pad.
pad.setAll(0, key);
}
// Now two different keys are derived from the padded key
// by XORing a different byte value to each.
// To make the inner hash key, XOR byte 0x36 into pad.
for (var i = 0; i < pad.length; i++) {
pad[i] ^= 0x36;
}
// Update inner hash with the result.
_inner.update(pad);
// To make the outer hash key, XOR byte 0x5c into pad.
// But since we already XORed 0x36 there, we must
// first undo this by XORing it again.
for (var i = 0; i < pad.length; i++) {
pad[i] ^= 0x36 ^ 0x5c;
}
// Update outer hash with the result.
_outer.update(pad);
// Save states of both hashes, so that we can quickly restore
// them later in reset() without the need to remember the actual
// key and perform this initialization again.
_innerKeyedState = _inner.saveState();
_outerKeyedState = _outer.saveState();
// Clean pad.
zero(pad);
}