node/test/parallel/test-webcrypto-derivebits-cfrg.js
Filip Skokan d65b17082b
crypto: make deriveBits length parameter optional and nullable
PR-URL: https://github.com/nodejs/node/pull/53601
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
2024-06-28 22:21:29 +00:00

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());