import 'dart:typed_data'; import 'package:pointycastle/pointycastle.dart'; import 'package:pointycastle/src/registry/registry.dart'; class PKCS12ParametersGenerator implements PBEParametersGenerator { static final FactoryConfig factoryConfig = DynamicFactoryConfig.suffix( PBEParametersGenerator, '/PKCS12', (_, final Match match) => () { var mac = Digest(match.group(1)!); return PKCS12ParametersGenerator(mac); }); static const int KEY_MATERIAL = 1; static const int IV_MATERIAL = 2; static const int MAC_MATERIAL = 3; Digest digest; late int u; late int v; late Uint8List salt; late Uint8List password; late int iterationCount; PKCS12ParametersGenerator(this.digest) { u = digest.digestSize; v = digest.byteLength; } @override void init(Uint8List password, Uint8List salt, int iterationCount) { this.password = password; this.salt = salt; this.iterationCount = iterationCount; } /// /// Generates a derived key with the given [keySize] in bytes. /// @override KeyParameter generateDerivedParameters(int keySize) { var dKey = _generateDerivedKey(KEY_MATERIAL, keySize); return KeyParameter(dKey); } /// /// Generates a derived key with the given [keySize] in bytes and a derived IV with the given [ivSize]. /// @override ParametersWithIV generateDerivedParametersWithIV(int keySize, int ivSize) { var dKey = _generateDerivedKey(KEY_MATERIAL, keySize); var iv = _generateDerivedKey(IV_MATERIAL, ivSize); return ParametersWithIV(KeyParameter(dKey), iv); } /// /// Generates a derived key with the given [keySize] in bytes used for mac generating. /// @override KeyParameter generateDerivedMacParameters(int keySize) { var dKey = _generateDerivedKey(MAC_MATERIAL, keySize); return KeyParameter(dKey); } Uint8List _generateDerivedKey(int idByte, int n) { var D = Uint8List(v); var dKey = Uint8List(n); for (var i = 0; i != D.length; i++) { D[i] = idByte; } Uint8List S; if (salt.isNotEmpty) { S = Uint8List(v * (((salt.length + v) - 1) ~/ v)); for (var i = 0; i != S.length; i++) { S[i] = salt[i % salt.length]; } } else { S = Uint8List(0); } Uint8List P; if (password.isNotEmpty) { P = Uint8List(v * (((password.length + v) - 1) ~/ v)); for (var i = 0; i != P.length; i++) { P[i] = password[i % password.length]; } } else { P = Uint8List(0); } var I = Uint8List(S.length + P.length); _arrayCopy(S, 0, I, 0, S.length); _arrayCopy(P, 0, I, S.length, P.length); var B = Uint8List(v); var c = ((n + u) - 1) ~/ u; var A = Uint8List(u); for (var i = 1; i <= c; i++) { digest.update(D, 0, D.length); digest.update(I, 0, I.length); digest.doFinal(A, 0); for (var j = 1; j < iterationCount; j++) { digest.update(A, 0, A.length); digest.doFinal(A, 0); } for (var j = 0; j != B.length; j++) { B[j] = A[j % A.length]; } for (var j = 0; j != (I.length ~/ v); j++) { _adjust(I, j * v, B); } if (i == c) { _arrayCopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u)); } else { _arrayCopy(A, 0, dKey, (i - 1) * u, A.length); } } return dKey; } void _arrayCopy(Uint8List? sourceArr, int sourcePos, Uint8List? outArr, int outPos, int len) { for (var i = 0; i < len; i++) { outArr![outPos + i] = sourceArr![sourcePos + i]; } } void _adjust(Uint8List a, int aOff, Uint8List b) { var x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1; a[aOff + b.length - 1] = x; x >>>= 8; for (var i = b.length - 2; i >= 0; i--) { x += (b[i] & 0xff) + (a[aOff + i] & 0xff); a[aOff + i] = x; x >>>= 8; } } }