import 'dart:typed_data'; import 'package:pointycastle/api.dart'; import 'package:pointycastle/key_derivators/api.dart'; import 'package:pointycastle/src/impl/base_key_derivator.dart'; import 'package:pointycastle/src/registry/registry.dart'; class ConcatKDFDerivator extends BaseKeyDerivator { /// Intended for internal use. static final FactoryConfig factoryConfig = DynamicFactoryConfig.suffix(KeyDerivator, '/ConcatKDF', (_, Match match) { final digestName = match.group(1); final digest = Digest(digestName!); return () { return ConcatKDFDerivator(digest); }; }); final Digest _digest; late final HkdfParameters _parameters; ConcatKDFDerivator(this._digest); @override String get algorithmName => '${_digest.algorithmName}/ConcatKDF'; @override int deriveKey(Uint8List inp, int inpOff, Uint8List out, int outOff) { _digest.reset(); var reps = _getReps(_parameters.desiredKeyLength, _digest.digestSize * 8); var output = Uint8List(reps * _digest.digestSize); var counter = Uint8List(4); for (var i = 1; i <= reps; i++) { var counterInt = i.toUnsigned(32); counter[0] = (counterInt >> 24) & 255; counter[1] = (counterInt >> 16) & 255; counter[2] = (counterInt >> 8) & 255; counter[3] = counterInt & 255; _digest.update(counter, 0, 4); _digest.update(_parameters.ikm, 0, _parameters.ikm.length); _digest.update(_parameters.salt ?? inp.sublist(inpOff), 0, _parameters.salt?.length ?? inp.sublist(inpOff).length); _digest.doFinal(output, (i - 1) * _digest.digestSize); } out.setAll(outOff, output.getRange(0, keySize)); return keySize; } int _getReps(int keydatalen, int messagedigestlen) { return (keydatalen / messagedigestlen).ceil(); } @override void init(covariant HkdfParameters params) { _parameters = params; } @override int get keySize => (_parameters.desiredKeyLength / 8).ceil(); }