deriveKey method

  1. @override
Future<SecretKeyData> deriveKey({
  1. required SecretKey secretKey,
  2. List<int> nonce = const <int>[],
  3. List<int> info = const <int>[],
})
override

Generates a new secret key from a secret key and a nonce.

The nonce ("salt") should be some random sequence of bytes. Nonce does not need to be protected. If possible, you should have a different nonce for each key derivation.

Implementation

@override
Future<SecretKeyData> deriveKey({
  required SecretKey secretKey,
  List<int> nonce = const <int>[],
  List<int> info = const <int>[],
}) async {
  // Calculate a pseudorandom key
  final secretKeyBytes = await secretKey.extractBytes();
  final nonceAsSecretKey = SecretKey(nonce);
  final prkMac = await hmac.calculateMac(
    secretKeyBytes,
    secretKey: nonceAsSecretKey,
    nonce: nonce,
  );

  final prk = SecretKey(prkMac.bytes);

  // T(0)
  var bytes = const <int>[];

  // T(1), T(2), ...
  final hashLength = hmac.hashAlgorithm.hashLengthInBytes;
  final n = outputLength ~/ hashLength;
  final result = Uint8List(outputLength);
  for (var i = 0; i <= n; i++) {
    final sink = await hmac.newMacSink(secretKey: prk);
    sink.add(bytes);
    if (info.isNotEmpty) {
      sink.add(info);
    }
    final added = <int>[0xFF & (1 + i)];
    sink.add(added);
    sink.close();
    final mac = await sink.mac();
    bytes = mac.bytes;
    final offset = i * hashLength;
    if (offset + bytes.length <= result.length) {
      result.setAll(offset, bytes);
    } else {
      result.setAll(offset, bytes.take(result.length - offset));
    }
  }
  return SecretKeyData(result);
}