HMAC constructor

HMAC(
  1. HashFunc hash,
  2. List<int> key, [
  3. int? blockSize
])

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);
}