// See file LICENSE for more information. library impl.key_derivator.pbkdf2; import 'dart:typed_data'; import 'package:pointycastle/api.dart'; import 'package:pointycastle/key_derivators/api.dart'; import 'package:pointycastle/src/registry/registry.dart'; import 'package:pointycastle/src/impl/base_key_derivator.dart'; /// Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2. This generator uses a SHA-1 HMac as the /// calculation function. The document this implementation is based on can be found at: /// /// * [http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html] /// class PBKDF2KeyDerivator extends BaseKeyDerivator { /// Intended for internal use. static final FactoryConfig factoryConfig = DynamicFactoryConfig.suffix( KeyDerivator, '/PBKDF2', (_, final Match match) => () { var mac = Mac(match.group(1)!); return PBKDF2KeyDerivator(mac); }); late Pbkdf2Parameters _params; final Mac _mac; late Uint8List _state; PBKDF2KeyDerivator(this._mac) { _state = Uint8List(_mac.macSize); } @override String get algorithmName => '${_mac.algorithmName}/PBKDF2'; @override int get keySize => _params.desiredKeyLength; void reset() { _mac.reset(); _state.fillRange(0, _state.length, 0); } @override void init(covariant Pbkdf2Parameters params) { _params = params; } @override int deriveKey(Uint8List inp, int inpOff, Uint8List out, int outOff) { var dkLen = _params.desiredKeyLength; var hLen = _mac.macSize; var l = (dkLen + hLen - 1) ~/ hLen; var iBuf = Uint8List(4); var outBytes = Uint8List(l * hLen); var outPos = 0; CipherParameters param = KeyParameter(inp.sublist(inpOff)); _mac.init(param); for (var i = 1; i <= l; i++) { // Increment the value in 'iBuf' for (var pos = 3;; pos--) { iBuf[pos]++; if (iBuf[pos] != 0) break; } _f(_params.salt, _params.iterationCount, iBuf, outBytes, outPos); outPos += hLen; } out.setRange(outOff, outOff + dkLen, outBytes); return keySize; } void _f(Uint8List? S, int c, Uint8List iBuf, Uint8List out, int outOff) { if (c <= 0) { throw ArgumentError('Iteration count must be at least 1.'); } if (S != null) { _mac.update(S, 0, S.length); } _mac.update(iBuf, 0, iBuf.length); _mac.doFinal(_state, 0); out.setRange(outOff, outOff + _state.length, _state); for (var count = 1; count < c; count++) { _mac.update(_state, 0, _state.length); _mac.doFinal(_state, 0); for (var j = 0; j != _state.length; j++) { out[outOff + j] ^= _state[j]; } } } }