102 lines
2.6 KiB
Dart
102 lines
2.6 KiB
Dart
// 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];
|
|
}
|
|
}
|
|
}
|
|
}
|