11cb0ef41Sopenharmony_ci// Flags: --expose-internals --no-warnings 21cb0ef41Sopenharmony_ci'use strict'; 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciconst common = require('../common'); 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ciif (!common.hasCrypto) 71cb0ef41Sopenharmony_ci common.skip('missing crypto'); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst assert = require('assert'); 101cb0ef41Sopenharmony_ciconst { webcrypto: { subtle }, KeyObject } = require('crypto'); 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci// This is only a partial test. The WebCrypto Web Platform Tests 131cb0ef41Sopenharmony_ci// will provide much greater coverage. 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci// Test ECDH key derivation 161cb0ef41Sopenharmony_ci{ 171cb0ef41Sopenharmony_ci async function test(namedCurve) { 181cb0ef41Sopenharmony_ci const [alice, bob] = await Promise.all([ 191cb0ef41Sopenharmony_ci subtle.generateKey({ name: 'ECDH', namedCurve }, true, ['deriveKey']), 201cb0ef41Sopenharmony_ci subtle.generateKey({ name: 'ECDH', namedCurve }, true, ['deriveKey']), 211cb0ef41Sopenharmony_ci ]); 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci const [secret1, secret2] = await Promise.all([ 241cb0ef41Sopenharmony_ci subtle.deriveKey({ 251cb0ef41Sopenharmony_ci name: 'ECDH', namedCurve, public: alice.publicKey 261cb0ef41Sopenharmony_ci }, bob.privateKey, { 271cb0ef41Sopenharmony_ci name: 'AES-CBC', 281cb0ef41Sopenharmony_ci length: 256 291cb0ef41Sopenharmony_ci }, true, ['encrypt']), 301cb0ef41Sopenharmony_ci subtle.deriveKey({ 311cb0ef41Sopenharmony_ci name: 'ECDH', namedCurve, public: bob.publicKey 321cb0ef41Sopenharmony_ci }, alice.privateKey, { 331cb0ef41Sopenharmony_ci name: 'AES-CBC', 341cb0ef41Sopenharmony_ci length: 256 351cb0ef41Sopenharmony_ci }, true, ['encrypt']), 361cb0ef41Sopenharmony_ci ]); 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci const [raw1, raw2] = await Promise.all([ 391cb0ef41Sopenharmony_ci subtle.exportKey('raw', secret1), 401cb0ef41Sopenharmony_ci subtle.exportKey('raw', secret2), 411cb0ef41Sopenharmony_ci ]); 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci assert.deepStrictEqual(raw1, raw2); 441cb0ef41Sopenharmony_ci } 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci test('P-521').then(common.mustCall()); 471cb0ef41Sopenharmony_ci} 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci// Test HKDF key derivation 501cb0ef41Sopenharmony_ci{ 511cb0ef41Sopenharmony_ci async function test(pass, info, salt, hash, expected) { 521cb0ef41Sopenharmony_ci const ec = new TextEncoder(); 531cb0ef41Sopenharmony_ci const key = await subtle.importKey( 541cb0ef41Sopenharmony_ci 'raw', 551cb0ef41Sopenharmony_ci ec.encode(pass), 561cb0ef41Sopenharmony_ci { name: 'HKDF', hash }, 571cb0ef41Sopenharmony_ci false, ['deriveKey']); 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci const secret = await subtle.deriveKey({ 601cb0ef41Sopenharmony_ci name: 'HKDF', 611cb0ef41Sopenharmony_ci hash, 621cb0ef41Sopenharmony_ci salt: ec.encode(salt), 631cb0ef41Sopenharmony_ci info: ec.encode(info) 641cb0ef41Sopenharmony_ci }, key, { 651cb0ef41Sopenharmony_ci name: 'AES-CTR', 661cb0ef41Sopenharmony_ci length: 256 671cb0ef41Sopenharmony_ci }, true, ['encrypt']); 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci const raw = await subtle.exportKey('raw', secret); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci assert.strictEqual(Buffer.from(raw).toString('hex'), expected); 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci const kTests = [ 751cb0ef41Sopenharmony_ci ['hello', 'there', 'my friend', 'SHA-256', 761cb0ef41Sopenharmony_ci '14d93b0ccd99d4f2cbd9fbfe9c830b5b8a43e3e45e32941ef21bdeb0fa87b6b6'], 771cb0ef41Sopenharmony_ci ['hello', 'there', 'my friend', 'SHA-384', 781cb0ef41Sopenharmony_ci 'e36cf2cf943d8f3a88adb80f478745c336ac811b1a86d03a7d10eb0b6b52295c'], 791cb0ef41Sopenharmony_ci ]; 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci const tests = Promise.all(kTests.map((args) => test(...args))); 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci tests.then(common.mustCall()); 841cb0ef41Sopenharmony_ci} 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci// Test PBKDF2 key derivation 871cb0ef41Sopenharmony_ci{ 881cb0ef41Sopenharmony_ci async function test(pass, salt, iterations, hash, expected) { 891cb0ef41Sopenharmony_ci const ec = new TextEncoder(); 901cb0ef41Sopenharmony_ci const key = await subtle.importKey( 911cb0ef41Sopenharmony_ci 'raw', 921cb0ef41Sopenharmony_ci ec.encode(pass), 931cb0ef41Sopenharmony_ci { name: 'PBKDF2', hash }, 941cb0ef41Sopenharmony_ci false, ['deriveKey']); 951cb0ef41Sopenharmony_ci const secret = await subtle.deriveKey({ 961cb0ef41Sopenharmony_ci name: 'PBKDF2', 971cb0ef41Sopenharmony_ci hash, 981cb0ef41Sopenharmony_ci salt: ec.encode(salt), 991cb0ef41Sopenharmony_ci iterations, 1001cb0ef41Sopenharmony_ci }, key, { 1011cb0ef41Sopenharmony_ci name: 'AES-CTR', 1021cb0ef41Sopenharmony_ci length: 256 1031cb0ef41Sopenharmony_ci }, true, ['encrypt']); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci const raw = await subtle.exportKey('raw', secret); 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci assert.strictEqual(Buffer.from(raw).toString('hex'), expected); 1081cb0ef41Sopenharmony_ci } 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci const kTests = [ 1111cb0ef41Sopenharmony_ci ['hello', 'there', 10, 'SHA-256', 1121cb0ef41Sopenharmony_ci 'f72d1cf4853fffbd16a42751765d11f8dc7939498ee7b7ce7678b4cb16fad880'], 1131cb0ef41Sopenharmony_ci ['hello', 'there', 5, 'SHA-384', 1141cb0ef41Sopenharmony_ci '201509b012c9cd2fbe7ea938f0c509b36ecb140f38bf9130e96923f55f46756d'], 1151cb0ef41Sopenharmony_ci ]; 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci const tests = Promise.all(kTests.map((args) => test(...args))); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci tests.then(common.mustCall()); 1201cb0ef41Sopenharmony_ci} 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci// Test default key lengths 1231cb0ef41Sopenharmony_ci{ 1241cb0ef41Sopenharmony_ci const vectors = [ 1251cb0ef41Sopenharmony_ci ['PBKDF2', 'deriveKey', 528], 1261cb0ef41Sopenharmony_ci ['HKDF', 'deriveKey', 528], 1271cb0ef41Sopenharmony_ci [{ name: 'HMAC', hash: 'SHA-1' }, 'sign', 512], 1281cb0ef41Sopenharmony_ci [{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 512], 1291cb0ef41Sopenharmony_ci // Not long enough secret generated by ECDH 1301cb0ef41Sopenharmony_ci // [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024], 1311cb0ef41Sopenharmony_ci // [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024], 1321cb0ef41Sopenharmony_ci ]; 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci (async () => { 1351cb0ef41Sopenharmony_ci const keyPair = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-521' }, false, ['deriveKey']); 1361cb0ef41Sopenharmony_ci for (const [derivedKeyAlgorithm, usage, expected] of vectors) { 1371cb0ef41Sopenharmony_ci const derived = await subtle.deriveKey( 1381cb0ef41Sopenharmony_ci { name: 'ECDH', public: keyPair.publicKey }, 1391cb0ef41Sopenharmony_ci keyPair.privateKey, 1401cb0ef41Sopenharmony_ci derivedKeyAlgorithm, 1411cb0ef41Sopenharmony_ci false, 1421cb0ef41Sopenharmony_ci [usage]); 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci if (derived.algorithm.name === 'HMAC') { 1451cb0ef41Sopenharmony_ci assert.strictEqual(derived.algorithm.length, expected); 1461cb0ef41Sopenharmony_ci } else { 1471cb0ef41Sopenharmony_ci // KDFs cannot be exportable and do not indicate their length 1481cb0ef41Sopenharmony_ci const secretKey = KeyObject.from(derived); 1491cb0ef41Sopenharmony_ci assert.strictEqual(secretKey.symmetricKeySize, expected / 8); 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci })().then(common.mustCall()); 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci{ 1561cb0ef41Sopenharmony_ci const vectors = [ 1571cb0ef41Sopenharmony_ci [{ name: 'HMAC', hash: 'SHA-1' }, 'sign', 512], 1581cb0ef41Sopenharmony_ci [{ name: 'HMAC', hash: 'SHA-256' }, 'sign', 512], 1591cb0ef41Sopenharmony_ci [{ name: 'HMAC', hash: 'SHA-384' }, 'sign', 1024], 1601cb0ef41Sopenharmony_ci [{ name: 'HMAC', hash: 'SHA-512' }, 'sign', 1024], 1611cb0ef41Sopenharmony_ci ]; 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci (async () => { 1641cb0ef41Sopenharmony_ci for (const [derivedKeyAlgorithm, usage, expected] of vectors) { 1651cb0ef41Sopenharmony_ci const derived = await subtle.deriveKey( 1661cb0ef41Sopenharmony_ci { name: 'PBKDF2', salt: new Uint8Array([]), hash: 'SHA-256', iterations: 20 }, 1671cb0ef41Sopenharmony_ci await subtle.importKey('raw', new Uint8Array([]), { name: 'PBKDF2' }, false, ['deriveKey']), 1681cb0ef41Sopenharmony_ci derivedKeyAlgorithm, 1691cb0ef41Sopenharmony_ci false, 1701cb0ef41Sopenharmony_ci [usage]); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci assert.strictEqual(derived.algorithm.length, expected); 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci })().then(common.mustCall()); 1751cb0ef41Sopenharmony_ci} 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci// Test X25519 and X448 key derivation 1781cb0ef41Sopenharmony_ci{ 1791cb0ef41Sopenharmony_ci async function test(name) { 1801cb0ef41Sopenharmony_ci const [alice, bob] = await Promise.all([ 1811cb0ef41Sopenharmony_ci subtle.generateKey({ name }, true, ['deriveKey']), 1821cb0ef41Sopenharmony_ci subtle.generateKey({ name }, true, ['deriveKey']), 1831cb0ef41Sopenharmony_ci ]); 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci const [secret1, secret2] = await Promise.all([ 1861cb0ef41Sopenharmony_ci subtle.deriveKey({ 1871cb0ef41Sopenharmony_ci name, public: alice.publicKey 1881cb0ef41Sopenharmony_ci }, bob.privateKey, { 1891cb0ef41Sopenharmony_ci name: 'AES-CBC', 1901cb0ef41Sopenharmony_ci length: 256 1911cb0ef41Sopenharmony_ci }, true, ['encrypt']), 1921cb0ef41Sopenharmony_ci subtle.deriveKey({ 1931cb0ef41Sopenharmony_ci name, public: bob.publicKey 1941cb0ef41Sopenharmony_ci }, alice.privateKey, { 1951cb0ef41Sopenharmony_ci name: 'AES-CBC', 1961cb0ef41Sopenharmony_ci length: 256 1971cb0ef41Sopenharmony_ci }, true, ['encrypt']), 1981cb0ef41Sopenharmony_ci ]); 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci const [raw1, raw2] = await Promise.all([ 2011cb0ef41Sopenharmony_ci subtle.exportKey('raw', secret1), 2021cb0ef41Sopenharmony_ci subtle.exportKey('raw', secret2), 2031cb0ef41Sopenharmony_ci ]); 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci assert.deepStrictEqual(raw1, raw2); 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci test('X25519').then(common.mustCall()); 2091cb0ef41Sopenharmony_ci test('X448').then(common.mustCall()); 2101cb0ef41Sopenharmony_ci} 211