HMAC<T extends HashState> constructor

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

Creates an HMAC instance with the specified hash function and secret key.

Implementation

HMAC(HashFunc<T> hash, List<int> key, [int? blockSize]) {
  _blockSize = blockSize;
  // Initialize inner and outer hashes.
  _inner = hash();
  _outer = hash();

  // SinsemillaPad 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.
  BinaryOps.zero(pad);
}