1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
/*---
includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
flags: [async]
---*/
function has_usage(usage, x) {
for (let i = 0; i < usage.length; i++) {
if (x === usage[i]) {
return true;
}
}
return false;
}
async function test(params) {
let r;
let encoder = new TextEncoder();
let keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(params.pass),
params.algorithm.name,
false, [ "deriveBits", "deriveKey" ]);
if (params.derive === "key") {
let key = await crypto.subtle.deriveKey(params.algorithm, keyMaterial,
params.derivedAlgorithm,
true, params.usage);
if (has_usage(params.usage, "encrypt")) {
r = await crypto.subtle.encrypt(params.derivedAlgorithm, key,
encoder.encode(params.text));
} else if (has_usage(params.usage, "sign")) {
r = await crypto.subtle.sign(params.derivedAlgorithm, key,
encoder.encode(params.text));
}
} else {
r = await crypto.subtle.deriveBits(params.algorithm, keyMaterial, params.length);
}
r = Buffer.from(r).toString("hex");
if (params.expected != r) {
throw Error(`${params.algorithm.name} failed expected: "${params.expected}" vs "${r}"`);
}
return "SUCCESS";
}
function p(args, default_opts) {
let params = Object.assign({}, default_opts);
params = merge(params, args);
params.algorithm.salt = Buffer.from(params.algorithm.salt, "hex");
params.algorithm.info = Buffer.from(params.algorithm.info, "hex");
params.derivedAlgorithm.iv = Buffer.from(params.derivedAlgorithm.iv, "hex");
return params;
}
let derive_tsuite = {
name: "derive",
skip: () => (!has_buffer() || !has_webcrypto()),
T: test,
prepare_args: p,
opts: {
text: "secReT",
pass: "passW0rd",
derive: "key",
optional: false,
length: 256,
algorithm: {
name: "PBKDF2",
salt: "00112233001122330011223300112233",
hash: "SHA-256",
info: "deadbeef",
iterations: 100000
},
derivedAlgorithm: {
name: "AES-GCM",
length: 256,
iv: "55667788556677885566778855667788"
},
usage: [ "encrypt", "decrypt" ]
},
tests: [
{ expected: "e7b55c9f9fda69b87648585f76c58109174aaa400cfa" },
{ pass: "pass2", expected: "e87d1787f2807ea0e1f7e1cb265b23004c575cf2ad7e" },
{ algorithm: { iterations: 10000 }, expected: "5add0059931ed1db1ca24c26dbe4de5719c43ed18a54" },
{ algorithm: { hash: "SHA-512" }, expected: "544d64e5e246fdd2ba290ea932b2d80ef411c76139f4" },
{ algorithm: { salt: "aabbccddaabbccddaabbccddaabbccdd" }, expected: "5c1304bedf840b1f6f7d1aa804fe870a8f949d762c32" },
{ algorithm: { salt: "aabbccddaabbccddaabbccddaabb" },
exception: "TypeError: PBKDF2 algorithm.salt must be at least 16 bytes long" },
{ derivedAlgorithm: { length: 128 }, expected: "9e2d7bcc1f21f30ec3c32af9129b64507d086d129f2a" },
{ derivedAlgorithm: { length: 32 },
exception: "TypeError: deriveKey \"AES-GCM\" length must be 128 or 256" },
{ derivedAlgorithm: { name: "AES-CBC" }, expected: "3ad6523692d44b6a7a90be7c2721786f" },
{ derive: "bits", expected: "6458ed6e16b998d4e646422171087be8a1ee34bed463dfcb3dcd30842b1228fe" },
{ derive: "bits", pass: "pass2", expected: "ef8f75073fcadfd504d26610c743873e297ad90340c23ddc0e5f6bdb83cbabb2" },
{ derive: "bits", algorithm: { salt: "aabbccddaabbccddaabbccddaabbccdd" },
expected: "22ceb295aa25b59c6bc5b383a089bd6999006c03f273ce3614a4fa0d90bd29ae" },
{ derive: "bits", algorithm: { hash: "SHA-1" },
expected: "a2fc83498f7d07b4c8180c7ebfec2af0f3a7d6cb08bf8593d41d3c5c1e1c4d67" },
{ derive: "bits", algorithm: { hash: "SHA-1" }, length: 128,
expected: "a2fc83498f7d07b4c8180c7ebfec2af0" },
{ derive: "bits", algorithm: { hash: "SHA-1" }, length: 64,
expected: "a2fc83498f7d07b4" },
{ algorithm: { name: "HKDF" }, optional: true,
expected: "18ea069ee3317d2db02e02f4a228f50dc80d9a2396e6" },
{ algorithm: { name: "HKDF" },
derivedAlgorithm: { name: "HMAC", hash: "SHA-256", length: 256 },
usage: [ "sign", "verify" ], optional: true,
expected: "0b06bd37de54c08cedde2cbb649d6f26d066acfd51717d83b52091e2ae6829c2" },
{ derive: "bits", algorithm: { name: "HKDF" }, optional: true,
expected: "e089c7491711306c69e077aa19fae6bfd2d4a6d240b0d37317d50472d7291a3e" },
]};
run([derive_tsuite])
.then($DONE, $DONE);
|