'use strict'; const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); const { webcrypto } = require('crypto'); const { subtle } = webcrypto; 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' }, ]; 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, ['deriveKey', 'deriveBits']), ]); keys[name] = { privateKey, publicKey, size, result, }; })); return keys; } (async function() { const keys = await prepareKeys(); const otherArgs = [ { name: 'HMAC', hash: 'SHA-256', length: 256 }, true, ['sign', 'verify']]; await Promise.all( Object.keys(keys).map(async (name) => { const { result, privateKey, publicKey } = keys[name]; { // Good parameters const key = await subtle.deriveKey({ name, public: publicKey }, privateKey, ...otherArgs); const raw = await subtle.exportKey('raw', key); assert.strictEqual(Buffer.from(raw).toString('hex'), result); } { // Case insensitivity const key = await subtle.deriveKey({ name: name.toLowerCase(), public: publicKey }, privateKey, { name: 'HmAc', hash: 'SHA-256', length: 256 }, true, ['sign', 'verify']); const raw = await subtle.exportKey('raw', key); assert.strictEqual(Buffer.from(raw).toString('hex'), result); } })); // Error tests { // Missing public property await assert.rejects( subtle.deriveKey( { name: 'X448' }, keys.X448.privateKey, ...otherArgs), { code: 'ERR_INVALID_ARG_TYPE' }); } { // The public property is not a CryptoKey await assert.rejects( subtle.deriveKey( { name: 'X448', public: { message: 'Not a CryptoKey' } }, keys.X448.privateKey, ...otherArgs), { code: 'ERR_INVALID_ARG_TYPE' }); } { // Mismatched named curves await assert.rejects( subtle.deriveKey( { name: 'X448', public: keys.X25519.publicKey }, keys.X448.privateKey, ...otherArgs), { message: 'The public and private keys must be of the same type' }); } { // Base key is not a private key await assert.rejects( subtle.deriveKey( { name: 'X448', public: keys.X448.publicKey }, keys.X448.publicKey, ...otherArgs), { message: /baseKey must be a private key/ }); } { // Base key is not a private key await assert.rejects( subtle.deriveKey( { name: 'X448', public: keys.X448.privateKey }, keys.X448.publicKey, ...otherArgs), { message: /algorithm\.public must be a public key/ }); } { // Public is a secret key const keyData = webcrypto.getRandomValues(new Uint8Array(32)); const key = await subtle.importKey( 'raw', keyData, { name: 'AES-CBC', length: 256 }, false, ['encrypt']); await assert.rejects( subtle.deriveKey( { name: 'X448', public: key }, keys.X448.publicKey, ...otherArgs), { message: /algorithm\.public must be a public key/ }); } })().then(common.mustCall());