mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
183 lines
5.9 KiB
JavaScript
183 lines
5.9 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const common = require('../common');
|
||
|
if (!common.hasCrypto)
|
||
|
common.skip('missing crypto');
|
||
|
|
||
|
const assert = require('assert');
|
||
|
const {
|
||
|
createSecretKey,
|
||
|
KeyObject,
|
||
|
randomBytes,
|
||
|
generateKeyPairSync,
|
||
|
} = require('crypto');
|
||
|
|
||
|
function assertCryptoKey(cryptoKey, keyObject, algorithm, extractable, usages) {
|
||
|
assert.strictEqual(cryptoKey instanceof CryptoKey, true);
|
||
|
assert.strictEqual(cryptoKey.type, keyObject.type);
|
||
|
assert.strictEqual(cryptoKey.algorithm.name, algorithm);
|
||
|
assert.strictEqual(cryptoKey.extractable, extractable);
|
||
|
assert.deepStrictEqual(cryptoKey.usages, usages);
|
||
|
assert.strictEqual(keyObject.equals(KeyObject.from(cryptoKey)), true);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
for (const length of [128, 192, 256]) {
|
||
|
const aes = createSecretKey(randomBytes(length >> 3));
|
||
|
for (const algorithm of ['AES-CTR', 'AES-CBC', 'AES-GCM', 'AES-KW']) {
|
||
|
const usages = algorithm === 'AES-KW' ? ['wrapKey', 'unwrapKey'] : ['encrypt', 'decrypt'];
|
||
|
for (const extractable of [true, false]) {
|
||
|
const cryptoKey = aes.toCryptoKey(algorithm, extractable, usages);
|
||
|
assertCryptoKey(cryptoKey, aes, algorithm, extractable, usages);
|
||
|
assert.strictEqual(cryptoKey.algorithm.length, length);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
const pbkdf2 = createSecretKey(randomBytes(16));
|
||
|
const algorithm = 'PBKDF2';
|
||
|
const usages = ['deriveBits'];
|
||
|
assert.throws(() => pbkdf2.toCryptoKey(algorithm, true, usages), {
|
||
|
name: 'SyntaxError',
|
||
|
message: 'PBKDF2 keys are not extractable'
|
||
|
});
|
||
|
assert.throws(() => pbkdf2.toCryptoKey(algorithm, false, ['wrapKey']), {
|
||
|
name: 'SyntaxError',
|
||
|
message: 'Unsupported key usage for a PBKDF2 key'
|
||
|
});
|
||
|
const cryptoKey = pbkdf2.toCryptoKey(algorithm, false, usages);
|
||
|
assertCryptoKey(cryptoKey, pbkdf2, algorithm, false, usages);
|
||
|
assert.strictEqual(cryptoKey.algorithm.length, undefined);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
for (const length of [128, 192, 256]) {
|
||
|
const hmac = createSecretKey(randomBytes(length >> 3));
|
||
|
const algorithm = 'HMAC';
|
||
|
const usages = ['sign', 'verify'];
|
||
|
|
||
|
assert.throws(() => {
|
||
|
createSecretKey(Buffer.alloc(0)).toCryptoKey({ name: algorithm, hash: 'SHA-256' }, true, usages);
|
||
|
}, {
|
||
|
name: 'DataError',
|
||
|
message: 'Zero-length key is not supported',
|
||
|
});
|
||
|
|
||
|
assert.throws(() => {
|
||
|
hmac.toCryptoKey({
|
||
|
name: algorithm,
|
||
|
hash: 'SHA-256',
|
||
|
}, true, []);
|
||
|
}, {
|
||
|
name: 'SyntaxError',
|
||
|
message: 'Usages cannot be empty when importing a secret key.'
|
||
|
});
|
||
|
|
||
|
for (const hash of ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']) {
|
||
|
for (const extractable of [true, false]) {
|
||
|
assert.throws(() => {
|
||
|
hmac.toCryptoKey({ name: algorithm, hash: 'SHA-256', length: 0 }, true, usages);
|
||
|
}, {
|
||
|
name: 'DataError',
|
||
|
message: 'Zero-length key is not supported',
|
||
|
});
|
||
|
const cryptoKey = hmac.toCryptoKey({ name: algorithm, hash }, extractable, usages);
|
||
|
assertCryptoKey(cryptoKey, hmac, algorithm, extractable, usages);
|
||
|
assert.strictEqual(cryptoKey.algorithm.length, length);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
for (const algorithm of ['Ed25519', 'Ed448', 'X25519', 'X448']) {
|
||
|
const { publicKey, privateKey } = generateKeyPairSync(algorithm.toLowerCase());
|
||
|
assert.throws(() => {
|
||
|
publicKey.toCryptoKey(algorithm === 'Ed25519' ? 'X25519' : 'Ed25519', true, []);
|
||
|
}, {
|
||
|
name: 'DataError',
|
||
|
message: 'Invalid key type'
|
||
|
});
|
||
|
for (const key of [publicKey, privateKey]) {
|
||
|
let usages;
|
||
|
if (algorithm.startsWith('E')) {
|
||
|
usages = key.type === 'public' ? ['verify'] : ['sign'];
|
||
|
} else {
|
||
|
usages = key.type === 'public' ? [] : ['deriveBits'];
|
||
|
}
|
||
|
for (const extractable of [true, false]) {
|
||
|
const cryptoKey = key.toCryptoKey(algorithm, extractable, usages);
|
||
|
assertCryptoKey(cryptoKey, key, algorithm, extractable, usages);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
const { publicKey, privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
||
|
for (const key of [publicKey, privateKey]) {
|
||
|
for (const algorithm of ['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP']) {
|
||
|
let usages;
|
||
|
if (algorithm === 'RSA-OAEP') {
|
||
|
usages = key.type === 'public' ? ['encrypt', 'wrapKey'] : ['decrypt', 'unwrapKey'];
|
||
|
} else {
|
||
|
usages = key.type === 'public' ? ['verify'] : ['sign'];
|
||
|
}
|
||
|
for (const extractable of [true, false]) {
|
||
|
for (const hash of ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']) {
|
||
|
const cryptoKey = key.toCryptoKey({
|
||
|
name: algorithm,
|
||
|
hash
|
||
|
}, extractable, usages);
|
||
|
assertCryptoKey(cryptoKey, key, algorithm, extractable, usages);
|
||
|
assert.strictEqual(cryptoKey.algorithm.hash.name, hash);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
for (const namedCurve of ['P-256', 'P-384', 'P-521']) {
|
||
|
const { publicKey, privateKey } = generateKeyPairSync('ec', { namedCurve });
|
||
|
assert.throws(() => {
|
||
|
privateKey.toCryptoKey({
|
||
|
name: 'ECDH',
|
||
|
namedCurve,
|
||
|
}, true, []);
|
||
|
}, {
|
||
|
name: 'SyntaxError',
|
||
|
message: 'Usages cannot be empty when importing a private key.'
|
||
|
});
|
||
|
assert.throws(() => {
|
||
|
publicKey.toCryptoKey({
|
||
|
name: 'ECDH',
|
||
|
namedCurve: namedCurve === 'P-256' ? 'P-384' : 'P-256'
|
||
|
}, true, []);
|
||
|
}, {
|
||
|
name: 'DataError',
|
||
|
message: 'Named curve mismatch'
|
||
|
});
|
||
|
for (const key of [publicKey, privateKey]) {
|
||
|
for (const algorithm of ['ECDH', 'ECDSA']) {
|
||
|
let usages;
|
||
|
if (algorithm === 'ECDH') {
|
||
|
usages = key.type === 'public' ? [] : ['deriveBits'];
|
||
|
} else {
|
||
|
usages = key.type === 'public' ? ['verify'] : ['sign'];
|
||
|
}
|
||
|
for (const extractable of [true, false]) {
|
||
|
const cryptoKey = key.toCryptoKey({
|
||
|
name: algorithm,
|
||
|
namedCurve
|
||
|
}, extractable, usages);
|
||
|
assertCryptoKey(cryptoKey, key, algorithm, extractable, usages);
|
||
|
assert.strictEqual(cryptoKey.algorithm.namedCurve, namedCurve);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|