269 lines
7.4 KiB
Dart
269 lines
7.4 KiB
Dart
@OnPlatform({
|
|
'chrome': Skip('Skip due to potential absence of file loading'),
|
|
'node': Skip('Skip due to potential absence of file loading')
|
|
})
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:pointycastle/pointycastle.dart';
|
|
import 'package:pointycastle/src/utils.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../test/src/helpers.dart';
|
|
|
|
dynamic loadJson(String path) {
|
|
var file = File(path);
|
|
return jsonDecode(file.readAsStringSync());
|
|
}
|
|
|
|
Uint8List nullSafeBytes(dynamic src) {
|
|
if (src == null) {
|
|
return Uint8List(0);
|
|
}
|
|
return createUint8ListFromHexString(src.toString());
|
|
}
|
|
|
|
void main() {
|
|
var acvpToDart = {};
|
|
acvpToDart['SHA2-224'] = 'SHA-224';
|
|
acvpToDart['SHA2-256'] = 'SHA-256';
|
|
acvpToDart['SHA2-384'] = 'SHA-384';
|
|
acvpToDart['SHA2-512'] = 'SHA-512';
|
|
acvpToDart['SHA2-512/224'] = 'SHA-512/224';
|
|
acvpToDart['SHA2-512/256'] = 'SHA-512/256';
|
|
acvpToDart['SHA3-224'] = 'SHA3-224';
|
|
acvpToDart['SHA3-256'] = 'SHA3-256';
|
|
acvpToDart['SHA3-384'] = 'SHA3-384';
|
|
acvpToDart['SHA3-512'] = 'SHA3-512';
|
|
|
|
group('KDA OneStep Concat Sp800-56Cr2', () {
|
|
test('run vectors', () {
|
|
//
|
|
// These vectors were generated by NIST's ACVP system.
|
|
// The correct answers were generated by the Bouncy Castle FIPS (Java) Lib
|
|
// and verified by submission to ACVP.
|
|
// "req" files contain the request.
|
|
// "rsp" files contain the response.
|
|
// There are two types of tests, AFT where the IUT is responsible for
|
|
// calculating the DKM and VAL where the IUT is responsible to calculating
|
|
// a DKM that may or may not match the supplied DKM in the request.
|
|
//
|
|
|
|
var req = loadJson('test/test_resources/kdf-56c/KDA.req.json');
|
|
var rsp = loadJson('test/test_resources/kdf-56c/KDA.rsp.json');
|
|
|
|
//
|
|
// Form a maps of known correct results.
|
|
//
|
|
|
|
var validDKMAFT = <String, Uint8List>{};
|
|
var validVALResult = <String, bool>{};
|
|
|
|
rsp[1]['testGroups'].forEach((group) {
|
|
group['tests'].forEach((test) {
|
|
if (test['dkm'] != null) {
|
|
validDKMAFT['${group['tgId']}:${test['tcId']}'] =
|
|
createUint8ListFromHexString(test['dkm']);
|
|
} else {
|
|
validVALResult['${group['tgId']}:${test['tcId']}'] =
|
|
test['testPassed'];
|
|
}
|
|
});
|
|
});
|
|
|
|
var groups = req[1]['testGroups'];
|
|
groups.forEach((group) {
|
|
var kdfConfig = group['kdfConfiguration'];
|
|
group['tests'].forEach((test) {
|
|
var kdfParams = test['kdfParameter'];
|
|
var t = kdfParams['t'];
|
|
var fpU = test['fixedInfoPartyU'];
|
|
var fpV = test['fixedInfoPartyV'];
|
|
var l = kdfParams['l'];
|
|
var algId = nullSafeBytes(kdfParams['algorithmId']);
|
|
|
|
var otherInfo = BytesBuilder();
|
|
otherInfo.add(algId);
|
|
otherInfo.add(nullSafeBytes(fpU['partyId']));
|
|
otherInfo.add(nullSafeBytes(fpU['ephemeralData']));
|
|
otherInfo.add(nullSafeBytes(fpV['partyId']));
|
|
otherInfo.add(nullSafeBytes(fpV['ephemeralData']));
|
|
otherInfo.add(createUint8ListFromHexString(t));
|
|
|
|
var Z = createUint8ListFromHexString(kdfParams['z']);
|
|
|
|
var c = kdfParams['salt'] != null
|
|
? HkdfParameters(
|
|
Z, l, createUint8ListFromHexString(kdfParams['salt']))
|
|
: HkdfParameters(Z, l);
|
|
|
|
var concatKdf =
|
|
KeyDerivator(acvpToDart[kdfConfig['auxFunction']] + '/ConcatKDF')
|
|
..init(c);
|
|
var key = concatKdf.process(otherInfo.toBytes());
|
|
|
|
if (group['testType'] == 'AFT') {
|
|
//
|
|
// AFT test, IUT must generate a DKM that must match what NIST
|
|
// is expecting.
|
|
//
|
|
var knownDKM = validDKMAFT['${group['tgId']}:${test['tcId']}'];
|
|
expect(key, equals(knownDKM));
|
|
} else {
|
|
// VAL test
|
|
// DKM is supplied in request, the IUT must generate a DKM that may
|
|
// or may not equal the supplied DKM in the request.
|
|
//
|
|
|
|
var dkm = createUint8ListFromHexString(test['dkm']);
|
|
var tp = constantTimeAreEqual(dkm, key);
|
|
expect(
|
|
validVALResult['${group['tgId']}:${test['tcId']}'], equals(tp));
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
group('RFC7518', () {
|
|
test('Test concatKDF from RFC 7518 Appendix C', () {
|
|
var kdf = KeyDerivator('SHA-256/ConcatKDF');
|
|
var Z = Uint8List.fromList([
|
|
158,
|
|
86,
|
|
217,
|
|
29,
|
|
129,
|
|
113,
|
|
53,
|
|
211,
|
|
114,
|
|
131,
|
|
66,
|
|
131,
|
|
191,
|
|
132,
|
|
38,
|
|
156,
|
|
251,
|
|
49,
|
|
110,
|
|
163,
|
|
218,
|
|
128,
|
|
106,
|
|
72,
|
|
246,
|
|
218,
|
|
167,
|
|
121,
|
|
140,
|
|
254,
|
|
144,
|
|
196
|
|
]);
|
|
var otherData = Uint8List.fromList([
|
|
0,
|
|
0,
|
|
0,
|
|
7,
|
|
65,
|
|
49,
|
|
50,
|
|
56,
|
|
71,
|
|
67,
|
|
77,
|
|
0,
|
|
0,
|
|
0,
|
|
5,
|
|
65,
|
|
108,
|
|
105,
|
|
99,
|
|
101,
|
|
0,
|
|
0,
|
|
0,
|
|
3,
|
|
66,
|
|
111,
|
|
98,
|
|
0,
|
|
0,
|
|
0,
|
|
128
|
|
]);
|
|
var params = HkdfParameters(Z, 128);
|
|
kdf.init(params);
|
|
|
|
var key = kdf.process(otherData);
|
|
expect(
|
|
key,
|
|
Uint8List.fromList([
|
|
86,
|
|
170,
|
|
141,
|
|
234,
|
|
248,
|
|
35,
|
|
109,
|
|
32,
|
|
92,
|
|
34,
|
|
40,
|
|
205,
|
|
113,
|
|
167,
|
|
16,
|
|
26
|
|
]));
|
|
});
|
|
|
|
test('Test concatKdf A1 derived from jose4j', () {
|
|
var z = base64Url.decode('Sq8rGLm4rEtzScmnSsY5r1n-AqBl_iBU8FxN80Uc0S0=');
|
|
var alg = 'A256CBC-HS512';
|
|
var otherInfo = computerOtherInfo(alg, 512);
|
|
var c = HkdfParameters(z, 512);
|
|
var concatKdf = KeyDerivator('SHA-256/ConcatKDF')..init(c);
|
|
var key = concatKdf.process(otherInfo);
|
|
var keyencoded = base64UrlEncode(key);
|
|
expect(
|
|
'pgs50IOZ6BxfqvTSie4t9OjWxGr4whiHo1v9Dti93CRiJE2PP60FojLatVVrcjg3BxpuFjnlQxL97GOwAfcwLA==',
|
|
keyencoded);
|
|
});
|
|
|
|
test('Test concatKdf A2 derived from jose4j', () {
|
|
var z = base64Url.decode('LfkHot2nGTVlmfxbgxQfMg==');
|
|
var alg = 'A128CBC-HS256';
|
|
var otherInfo = computerOtherInfo(alg, 256);
|
|
var c = HkdfParameters(z, 256);
|
|
var concatKdf = KeyDerivator('SHA-256/ConcatKDF')..init(c);
|
|
var key = concatKdf.process(otherInfo);
|
|
var keyencoded = base64UrlEncode(key);
|
|
expect('vphyobtvExGXF7TaOvAkx6CCjHQNYamP2ET8xkhTu-0=', keyencoded);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Helpers for ECDH-ES
|
|
Uint8List computerOtherInfo(String encryptionAlgorithmName, int keybitLength) {
|
|
var l = encryptionAlgorithmName.codeUnits.length.toUnsigned(32);
|
|
var ll = _convertToBigEndian(l);
|
|
var a = Uint8List.fromList(encryptionAlgorithmName.codeUnits);
|
|
//TODO: add apu, apv, fixed to empty for now
|
|
var zero = _convertToBigEndian(0);
|
|
var k = _convertToBigEndian(keybitLength);
|
|
return Uint8List.fromList([...ll, ...a, ...zero, ...zero, ...k]);
|
|
}
|
|
|
|
Uint8List _convertToBigEndian(int l) {
|
|
var ll = Uint8List(4);
|
|
ll[0] = (l >> 24) & 255;
|
|
ll[1] = (l >> 16) & 255;
|
|
ll[2] = (l >> 8) & 255;
|
|
ll[3] = l & 255;
|
|
return ll;
|
|
}
|