mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 21:19:50 +01:00
d65b17082b
PR-URL: https://github.com/nodejs/node/pull/53601 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
223 lines
5.4 KiB
JavaScript
223 lines
5.4 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const assert = require('assert');
|
|
const { subtle } = globalThis.crypto;
|
|
|
|
const kTests = [
|
|
{
|
|
name: 'X25519',
|
|
size: 32,
|
|
pkcs8: '302e020100300506032b656e04220420c8838e76d057dfb7d8c95a69e138160ad' +
|
|
'd6373fd71a4d276bb56e3a81b64ff61',
|
|
spki: '302a300506032b656e0321001cf2b1e6022ec537371ed7f53e54fa1154d83e98eb' +
|
|
'64ea51fae5b3307cfe9706',
|
|
result: '2768409dfab99ec23b8c89b93ff5880295f76176088f89e43dfebe7ea1950008'
|
|
},
|
|
{
|
|
name: 'X448',
|
|
size: 56,
|
|
pkcs8: '3046020100300506032b656f043a043858c7d29a3eb519b29d00cfb191bb64fc6' +
|
|
'd8a42d8f17176272b89f2272d1819295c6525c0829671b052ef0727530f188e31' +
|
|
'd0cc53bf26929e',
|
|
spki: '3042300506032b656f033900b604a1d1a5cd1d9426d561ef630a9eb16cbe69d5b9' +
|
|
'ca615edc53633efb52ea31e6e6a0a1dbacc6e76cbce6482d7e4ba3d55d9e802765' +
|
|
'ce6f',
|
|
result: 'f0f6c5f17f94f4291eab7178866d37ec8906dd6c514143dc85be7cf28deff39b' +
|
|
'726e0f6dcf810eb594dca97b4882bd44c43ea7dc67f49a4e',
|
|
},
|
|
];
|
|
|
|
async function prepareKeys() {
|
|
const keys = {};
|
|
await Promise.all(
|
|
kTests.map(async ({ name, size, pkcs8, spki, result }) => {
|
|
const [
|
|
privateKey,
|
|
publicKey,
|
|
] = await Promise.all([
|
|
subtle.importKey(
|
|
'pkcs8',
|
|
Buffer.from(pkcs8, 'hex'),
|
|
{ name },
|
|
true,
|
|
['deriveKey', 'deriveBits']),
|
|
subtle.importKey(
|
|
'spki',
|
|
Buffer.from(spki, 'hex'),
|
|
{ name },
|
|
true,
|
|
[]),
|
|
]);
|
|
keys[name] = {
|
|
privateKey,
|
|
publicKey,
|
|
size,
|
|
result,
|
|
};
|
|
}));
|
|
return keys;
|
|
}
|
|
|
|
(async function() {
|
|
const keys = await prepareKeys();
|
|
|
|
await Promise.all(
|
|
Object.keys(keys).map(async (name) => {
|
|
const { size, result, privateKey, publicKey } = keys[name];
|
|
|
|
{
|
|
// Good parameters
|
|
const bits = await subtle.deriveBits({
|
|
name,
|
|
public: publicKey
|
|
}, privateKey, 8 * size);
|
|
|
|
assert(bits instanceof ArrayBuffer);
|
|
assert.strictEqual(Buffer.from(bits).toString('hex'), result);
|
|
}
|
|
|
|
{
|
|
// Case insensitivity
|
|
const bits = await subtle.deriveBits({
|
|
name: name.toLowerCase(),
|
|
public: publicKey
|
|
}, privateKey, 8 * size);
|
|
|
|
assert.strictEqual(Buffer.from(bits).toString('hex'), result);
|
|
}
|
|
|
|
{
|
|
// Null length
|
|
const bits = await subtle.deriveBits({
|
|
name,
|
|
public: publicKey
|
|
}, privateKey, null);
|
|
|
|
assert.strictEqual(Buffer.from(bits).toString('hex'), result);
|
|
}
|
|
|
|
{
|
|
// Default length
|
|
const bits = await subtle.deriveBits({
|
|
name,
|
|
public: publicKey
|
|
}, privateKey);
|
|
|
|
assert.strictEqual(Buffer.from(bits).toString('hex'), result);
|
|
}
|
|
|
|
{
|
|
// Short Result
|
|
const bits = await subtle.deriveBits({
|
|
name,
|
|
public: publicKey
|
|
}, privateKey, 8 * size - 32);
|
|
|
|
assert.strictEqual(
|
|
Buffer.from(bits).toString('hex'),
|
|
result.slice(0, -8));
|
|
}
|
|
|
|
{
|
|
// Too long result
|
|
await assert.rejects(subtle.deriveBits({
|
|
name,
|
|
public: publicKey
|
|
}, privateKey, 8 * size + 8), {
|
|
message: /derived bit length is too small/
|
|
});
|
|
}
|
|
|
|
{
|
|
// Non-multiple of 8
|
|
const bits = await subtle.deriveBits({
|
|
name,
|
|
public: publicKey
|
|
}, privateKey, 8 * size - 11);
|
|
|
|
assert.strictEqual(
|
|
Buffer.from(bits).toString('hex'),
|
|
result.slice(0, -2));
|
|
}
|
|
}));
|
|
|
|
// Error tests
|
|
{
|
|
// Missing public property
|
|
await assert.rejects(
|
|
subtle.deriveBits(
|
|
{ name: 'X448' },
|
|
keys.X448.privateKey,
|
|
8 * keys.X448.size),
|
|
{ code: 'ERR_MISSING_OPTION' });
|
|
}
|
|
|
|
{
|
|
// The public property is not a CryptoKey
|
|
await assert.rejects(
|
|
subtle.deriveBits(
|
|
{
|
|
name: 'X448',
|
|
public: { message: 'Not a CryptoKey' }
|
|
},
|
|
keys.X448.privateKey,
|
|
8 * keys.X448.size),
|
|
{ code: 'ERR_INVALID_ARG_TYPE' });
|
|
}
|
|
|
|
{
|
|
// Mismatched types
|
|
await assert.rejects(
|
|
subtle.deriveBits(
|
|
{
|
|
name: 'X448',
|
|
public: keys.X25519.publicKey
|
|
},
|
|
keys.X448.privateKey,
|
|
8 * keys.X448.size),
|
|
{ message: 'The public and private keys must be of the same type' });
|
|
}
|
|
|
|
{
|
|
// Base key is not a private key
|
|
await assert.rejects(subtle.deriveBits({
|
|
name: 'X448',
|
|
public: keys.X448.publicKey
|
|
}, keys.X448.publicKey, null), {
|
|
name: 'InvalidAccessError'
|
|
});
|
|
}
|
|
|
|
{
|
|
// Base key is not a private key
|
|
await assert.rejects(subtle.deriveBits({
|
|
name: 'X448',
|
|
public: keys.X448.privateKey
|
|
}, keys.X448.publicKey, null), {
|
|
name: 'InvalidAccessError'
|
|
});
|
|
}
|
|
|
|
{
|
|
// Public is a secret key
|
|
const keyData = globalThis.crypto.getRandomValues(new Uint8Array(32));
|
|
const key = await subtle.importKey(
|
|
'raw',
|
|
keyData,
|
|
{ name: 'AES-CBC', length: 256 },
|
|
false, ['encrypt']);
|
|
|
|
await assert.rejects(subtle.deriveBits({
|
|
name: 'X448',
|
|
public: key
|
|
}, keys.X448.publicKey, null), {
|
|
name: 'InvalidAccessError'
|
|
});
|
|
}
|
|
})().then(common.mustCall());
|