Skip to content

Commit 8c71562

Browse files
committed
[WebCrypto] Test digesting async iterable objects
1 parent 5ae9376 commit 8c71562

File tree

1 file changed

+317
-0
lines changed

1 file changed

+317
-0
lines changed
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
// META: title=WebCryptoAPI: digest() with async iterables
2+
// META: timeout=long
3+
4+
const subtle = crypto.subtle; // Change to test prefixed implementations
5+
6+
const sourceData = {
7+
empty: [],
8+
short: [new Uint8Array([21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255])],
9+
medium: [new Uint8Array([182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, 171, 172, 161, 147])]
10+
};
11+
12+
sourceData.long = [];
13+
for (let i=0; i<1024; i++) {
14+
sourceData.long.push(sourceData.medium[0]);
15+
}
16+
17+
const digestedData = {
18+
"sha-1": {
19+
empty: new Uint8Array([218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]),
20+
short: new Uint8Array([201, 19, 24, 205, 242, 57, 106, 1, 94, 63, 78, 106, 134, 160, 186, 101, 184, 99, 89, 68]),
21+
medium: new Uint8Array([229, 65, 6, 8, 112, 235, 22, 191, 51, 182, 142, 81, 245, 19, 82, 104, 147, 152, 103, 41]),
22+
long: new Uint8Array([48, 152, 181, 0, 55, 236, 208, 46, 189, 101, 118, 83, 178, 191, 160, 30, 238, 39, 162, 234])
23+
},
24+
"sha-256": {
25+
empty: new Uint8Array([227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85]),
26+
short: new Uint8Array([162, 131, 17, 134, 152, 71, 146, 199, 211, 45, 89, 200, 151, 64, 104, 127, 25, 173, 220, 27, 149, 158, 113, 161, 204, 83, 138, 59, 126, 216, 67, 242]),
27+
medium: new Uint8Array([83, 83, 103, 135, 126, 240, 20, 215, 252, 113, 126, 92, 183, 132, 62, 89, 182, 26, 238, 98, 199, 2, 156, 236, 126, 198, 193, 47, 217, 36, 224, 228]),
28+
long: new Uint8Array([20, 205, 234, 157, 199, 95, 90, 98, 116, 217, 252, 30, 100, 0, 153, 18, 241, 220, 211, 6, 180, 143, 232, 233, 207, 18, 45, 230, 113, 87, 23, 129])
29+
},
30+
"sha-384": {
31+
empty: new Uint8Array([56, 176, 96, 167, 81, 172, 150, 56, 76, 217, 50, 126, 177, 177, 227, 106, 33, 253, 183, 17, 20, 190, 7, 67, 76, 12, 199, 191, 99, 246, 225, 218, 39, 78, 222, 191, 231, 111, 101, 251, 213, 26, 210, 241, 72, 152, 185, 91]),
32+
short: new Uint8Array([107, 245, 234, 101, 36, 209, 205, 220, 67, 247, 207, 59, 86, 238, 5, 146, 39, 64, 74, 47, 83, 143, 2, 42, 61, 183, 68, 122, 120, 44, 6, 193, 237, 5, 232, 171, 79, 94, 220, 23, 243, 113, 20, 64, 223, 233, 119, 49]),
33+
medium: new Uint8Array([203, 194, 197, 136, 254, 91, 37, 249, 22, 218, 40, 180, 228, 122, 72, 74, 230, 252, 31, 228, 144, 45, 213, 201, 147, 154, 107, 253, 3, 74, 179, 180, 139, 57, 8, 116, 54, 1, 31, 106, 153, 135, 157, 39, 149, 64, 233, 119]),
34+
long: new Uint8Array([73, 244, 253, 179, 152, 25, 104, 249, 125, 87, 55, 15, 133, 52, 80, 103, 205, 82, 150, 169, 125, 209, 161, 142, 6, 145, 30, 117, 110, 150, 8, 73, 37, 41, 135, 14, 26, 209, 48, 153, 141, 87, 203, 251, 183, 193, 208, 158])
35+
},
36+
"sha-512": {
37+
empty: new Uint8Array([207, 131, 225, 53, 126, 239, 184, 189, 241, 84, 40, 80, 214, 109, 128, 7, 214, 32, 228, 5, 11, 87, 21, 220, 131, 244, 169, 33, 211, 108, 233, 206, 71, 208, 209, 60, 93, 133, 242, 176, 255, 131, 24, 210, 135, 126, 236, 47, 99, 185, 49, 189, 71, 65, 122, 129, 165, 56, 50, 122, 249, 39, 218, 62]),
38+
short: new Uint8Array([55, 82, 72, 190, 95, 243, 75, 231, 76, 171, 79, 241, 195, 188, 141, 198, 139, 213, 248, 223, 244, 2, 62, 152, 248, 123, 134, 92, 255, 44, 114, 66, 146, 223, 24, 148, 67, 166, 79, 244, 19, 74, 101, 205, 70, 53, 185, 212, 245, 220, 13, 63, 182, 117, 40, 0, 42, 99, 172, 242, 108, 157, 165, 117]),
39+
medium: new Uint8Array([185, 16, 159, 131, 158, 142, 164, 60, 137, 15, 41, 60, 225, 29, 198, 226, 121, 141, 30, 36, 49, 241, 228, 185, 25, 227, 178, 12, 79, 54, 48, 59, 163, 156, 145, 109, 179, 6, 196, 90, 59, 101, 118, 31, 245, 190, 133, 50, 142, 234, 244, 44, 56, 48, 241, 217, 94, 122, 65, 22, 91, 125, 45, 54]),
40+
long: new Uint8Array([75, 2, 202, 246, 80, 39, 96, 48, 234, 86, 23, 229, 151, 197, 213, 63, 217, 218, 166, 139, 120, 191, 230, 11, 34, 170, 184, 211, 106, 76, 42, 58, 255, 219, 113, 35, 79, 73, 39, 103, 55, 197, 117, 221, 247, 77, 20, 5, 76, 189, 111, 219, 152, 253, 13, 220, 188, 180, 111, 145, 173, 118, 182, 238])
41+
},
42+
};
43+
44+
// Try every combination of hash with source data size.
45+
// Each combination is tested with an array, a `ReadableStream` created from an array,
46+
// and a manually created `async iterable` object.
47+
Object.keys(sourceData).forEach(function(size) {
48+
Object.keys(digestedData).forEach(function(alg) {
49+
promise_test(function() {
50+
const data = sourceData[size];
51+
const promise = subtle.digest(alg, data)
52+
.then(function(result) {
53+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
54+
}, function(err) {
55+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
56+
});
57+
58+
return promise;
59+
}, alg + " with " + size + " source data - array");
60+
61+
promise_test(function() {
62+
const data = sourceData[size];
63+
const promise = subtle.digest(alg, ReadableStream.from(data))
64+
.then(function(result) {
65+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
66+
}, function(err) {
67+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
68+
});
69+
70+
return promise;
71+
}, alg + " with " + size + " source data - stream from array");
72+
73+
promise_test(function() {
74+
const data = sourceData[size];
75+
let i = 0;
76+
const stream = new ReadableStream({
77+
async pull(controller) {
78+
await new Promise(resolve => setTimeout(resolve));
79+
if (i === data.length) {
80+
controller.close();
81+
} else {
82+
controller.enqueue(data[i++]);
83+
}
84+
}
85+
});
86+
const promise = subtle.digest(alg, stream)
87+
.then(function(result) {
88+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
89+
}, function(err) {
90+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
91+
});
92+
93+
return promise;
94+
}, alg + " with " + size + " source data - manually constructed stream");
95+
96+
promise_test(function() {
97+
const data = sourceData[size];
98+
const asyncIterable = {
99+
[Symbol.asyncIterator]() {
100+
let i = 0;
101+
return {
102+
async next() {
103+
await new Promise(resolve => setTimeout(resolve));
104+
if (i === data.length) {
105+
return { done: true };
106+
}
107+
return { value: data[i++] };
108+
}
109+
};
110+
}
111+
};
112+
const promise = subtle.digest(alg, asyncIterable)
113+
.then(function(result) {
114+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
115+
}, function(err) {
116+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
117+
});
118+
119+
return promise;
120+
}, alg + " with " + size + " source data - manually constructed async iterable object");
121+
122+
promise_test(function() {
123+
const data = [...sourceData[size], new Uint8Array()];
124+
const promise = subtle.digest(alg, data)
125+
.then(function(result) {
126+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
127+
}, function(err) {
128+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
129+
});
130+
131+
return promise;
132+
}, alg + " with " + size + " source data - array with empty chunk");
133+
134+
promise_test(function() {
135+
const data = [...sourceData[size], new Uint8Array()];
136+
const promise = subtle.digest(alg, ReadableStream.from(data))
137+
.then(function(result) {
138+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
139+
}, function(err) {
140+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
141+
});
142+
143+
return promise;
144+
}, alg + " with " + size + " source data - stream from array with empty chunk");
145+
146+
promise_test(function() {
147+
const data = [...sourceData[size], new Uint8Array()];
148+
let i = 0;
149+
const stream = new ReadableStream({
150+
async pull(controller) {
151+
await new Promise(resolve => setTimeout(resolve));
152+
if (i === data.length) {
153+
controller.close();
154+
} else {
155+
controller.enqueue(data[i++]);
156+
}
157+
}
158+
});
159+
const promise = subtle.digest(alg, stream)
160+
.then(function(result) {
161+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
162+
}, function(err) {
163+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
164+
});
165+
166+
return promise;
167+
}, alg + " with " + size + " source data - manually constructed stream with empty chunk");
168+
169+
promise_test(function() {
170+
const data = [...sourceData[size], new Uint8Array()];
171+
const asyncIterable = {
172+
[Symbol.asyncIterator]() {
173+
let i = 0;
174+
return {
175+
async next() {
176+
await new Promise(resolve => setTimeout(resolve));
177+
if (i === data.length) {
178+
return { done: true };
179+
}
180+
return { value: data[i++] };
181+
}
182+
};
183+
}
184+
};
185+
const promise = subtle.digest(alg, asyncIterable)
186+
.then(function(result) {
187+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
188+
}, function(err) {
189+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
190+
});
191+
192+
return promise;
193+
}, alg + " with " + size + " source data - manually constructed async iterable object with empty chunk");
194+
195+
promise_test(function() {
196+
const data = [...sourceData[size], 'test'];
197+
const promise = subtle.digest(alg, data)
198+
.then(function() {
199+
assert_unreached("digest() should throw for non-BufferSource chunks");
200+
}, function(err) {
201+
assert_equals(err.name, "TypeError", "Non-BufferSource chunk should cause TypeError");
202+
});
203+
204+
return promise;
205+
}, alg + " with " + size + " source data - array with invalid chunk");
206+
207+
promise_test(function() {
208+
const data = [...sourceData[size], 'test'];
209+
const promise = subtle.digest(alg, ReadableStream.from(data))
210+
.then(function() {
211+
assert_unreached("digest() should throw for non-BufferSource chunks");
212+
}, function(err) {
213+
assert_equals(err.name, "TypeError", "Non-BufferSource chunk should cause TypeError");
214+
});
215+
216+
return promise;
217+
}, alg + " with " + size + " source data - stream from array with invalid chunk");
218+
219+
promise_test(function() {
220+
const data = [...sourceData[size], 'test'];
221+
let i = 0;
222+
const stream = new ReadableStream({
223+
async pull(controller) {
224+
await new Promise(resolve => setTimeout(resolve));
225+
if (i === data.length) {
226+
controller.close();
227+
} else {
228+
controller.enqueue(data[i++]);
229+
}
230+
}
231+
});
232+
const promise = subtle.digest(alg, stream)
233+
.then(function() {
234+
assert_unreached("digest() should throw for non-BufferSource chunks");
235+
}, function(err) {
236+
assert_equals(err.name, "TypeError", "Non-BufferSource chunk should cause TypeError");
237+
});
238+
239+
return promise;
240+
}, alg + " with " + size + " source data - manually constructed stream with invalid chunk");
241+
242+
promise_test(function() {
243+
const data = [...sourceData[size], 'test'];
244+
const asyncIterable = {
245+
[Symbol.asyncIterator]() {
246+
let i = 0;
247+
return {
248+
async next() {
249+
await new Promise(resolve => setTimeout(resolve));
250+
if (i === data.length) {
251+
return { done: true };
252+
}
253+
return { value: data[i++] };
254+
}
255+
};
256+
}
257+
};
258+
const promise = subtle.digest(alg, asyncIterable)
259+
.then(function() {
260+
assert_unreached("digest() should throw for non-BufferSource chunks");
261+
}, function(err) {
262+
assert_equals(err.name, "TypeError", "Non-BufferSource chunk should cause TypeError");
263+
});
264+
265+
return promise;
266+
}, alg + " with " + size + " source data - manually constructed async iterable object with invalid chunk");
267+
268+
if (size === "empty") {
269+
promise_test(function() {
270+
const data = "";
271+
const promise = subtle.digest(alg, data)
272+
.then(function(result) {
273+
assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size);
274+
}, function(err) {
275+
assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);
276+
});
277+
278+
return promise;
279+
}, alg + " - empty string works");
280+
}
281+
282+
if (size === "short") {
283+
promise_test(function() {
284+
const data = "test";
285+
const promise = subtle.digest(alg, data)
286+
.then(function() {
287+
assert_unreached("digest() should throw for non-BufferSource chunks");
288+
}, function(err) {
289+
assert_equals(err.name, "TypeError", "Non-BufferSource chunk should cause TypeError");
290+
});
291+
292+
return promise;
293+
}, alg + " - non-empty string doesn't work");
294+
}
295+
});
296+
});
297+
298+
299+
done();
300+
301+
302+
function equalBuffers(a, b) {
303+
if (a.byteLength !== b.byteLength) {
304+
return false;
305+
}
306+
307+
const aBytes = new Uint8Array(a);
308+
const bBytes = new Uint8Array(b);
309+
310+
for (let i=0; i<a.byteLength; i++) {
311+
if (aBytes[i] !== bBytes[i]) {
312+
return false;
313+
}
314+
}
315+
316+
return true;
317+
}

0 commit comments

Comments
 (0)