• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const common = require('../common');
4
5if (!common.hasCrypto)
6  common.skip('missing crypto');
7
8const assert = require('assert');
9const { webcrypto } = require('crypto');
10const { subtle } = webcrypto;
11
12const kTests = [
13  {
14    name: 'X25519',
15    size: 32,
16    pkcs8: '302e020100300506032b656e04220420c8838e76d057dfb7d8c95a69e138160ad' +
17           'd6373fd71a4d276bb56e3a81b64ff61',
18    spki: '302a300506032b656e0321001cf2b1e6022ec537371ed7f53e54fa1154d83e98eb' +
19          '64ea51fae5b3307cfe9706',
20    result: '2768409dfab99ec23b8c89b93ff5880295f76176088f89e43dfebe7ea1950008'
21  },
22  {
23    name: 'X448',
24    size: 56,
25    pkcs8: '3046020100300506032b656f043a043858c7d29a3eb519b29d00cfb191bb64fc6' +
26           'd8a42d8f17176272b89f2272d1819295c6525c0829671b052ef0727530f188e31' +
27           'd0cc53bf26929e',
28    spki: '3042300506032b656f033900b604a1d1a5cd1d9426d561ef630a9eb16cbe69d5b9' +
29          'ca615edc53633efb52ea31e6e6a0a1dbacc6e76cbce6482d7e4ba3d55d9e802765' +
30          'ce6f',
31    result: 'f0f6c5f17f94f4291eab7178866d37ec8906dd6c514143dc85be7cf28deff39b'
32  },
33];
34
35async function prepareKeys() {
36  const keys = {};
37  await Promise.all(
38    kTests.map(async ({ name, size, pkcs8, spki, result }) => {
39      const [
40        privateKey,
41        publicKey,
42      ] = await Promise.all([
43        subtle.importKey(
44          'pkcs8',
45          Buffer.from(pkcs8, 'hex'),
46          { name },
47          true,
48          ['deriveKey', 'deriveBits']),
49        subtle.importKey(
50          'spki',
51          Buffer.from(spki, 'hex'),
52          { name },
53          true,
54          []),
55      ]);
56      keys[name] = {
57        privateKey,
58        publicKey,
59        size,
60        result,
61      };
62    }));
63  return keys;
64}
65
66(async function() {
67  const keys = await prepareKeys();
68  const otherArgs = [
69    { name: 'HMAC', hash: 'SHA-256', length: 256 },
70    true,
71    ['sign', 'verify']];
72
73  await Promise.all(
74    Object.keys(keys).map(async (name) => {
75      const { result, privateKey, publicKey } = keys[name];
76
77      {
78        // Good parameters
79        const key = await subtle.deriveKey({
80          name,
81          public: publicKey
82        }, privateKey, ...otherArgs);
83
84        const raw = await subtle.exportKey('raw', key);
85
86        assert.strictEqual(Buffer.from(raw).toString('hex'), result);
87      }
88
89      {
90        // Case insensitivity
91        const key = await subtle.deriveKey({
92          name: name.toLowerCase(),
93          public: publicKey
94        }, privateKey, {
95          name: 'HmAc',
96          hash: 'SHA-256',
97          length: 256
98        }, true, ['sign', 'verify']);
99
100        const raw = await subtle.exportKey('raw', key);
101
102        assert.strictEqual(Buffer.from(raw).toString('hex'), result);
103      }
104    }));
105
106  // Error tests
107  {
108    // Missing public property
109    await assert.rejects(
110      subtle.deriveKey(
111        { name: 'X448' },
112        keys.X448.privateKey,
113        ...otherArgs),
114      { code: 'ERR_MISSING_OPTION' });
115  }
116
117  {
118    // The public property is not a CryptoKey
119    await assert.rejects(
120      subtle.deriveKey(
121        {
122          name: 'X448',
123          public: { message: 'Not a CryptoKey' }
124        },
125        keys.X448.privateKey,
126        ...otherArgs),
127      { code: 'ERR_INVALID_ARG_TYPE' });
128  }
129
130  {
131    // Mismatched named curves
132    await assert.rejects(
133      subtle.deriveKey(
134        {
135          name: 'X448',
136          public: keys.X25519.publicKey
137        },
138        keys.X448.privateKey,
139        ...otherArgs),
140      { message: 'The public and private keys must be of the same type' });
141  }
142
143  {
144    // Base key is not a private key
145    await assert.rejects(
146      subtle.deriveKey(
147        {
148          name: 'X448',
149          public: keys.X448.publicKey
150        },
151        keys.X448.publicKey,
152        ...otherArgs),
153      { name: 'InvalidAccessError' });
154  }
155
156  {
157    // Public is not a public key
158    await assert.rejects(
159      subtle.deriveKey(
160        {
161          name: 'X448',
162          public: keys.X448.privateKey
163        },
164        keys.X448.privateKey,
165        ...otherArgs),
166      { name: 'InvalidAccessError' });
167  }
168
169  {
170    // Public is a secret key
171    const keyData = webcrypto.getRandomValues(new Uint8Array(32));
172    const key = await subtle.importKey(
173      'raw',
174      keyData,
175      { name: 'AES-CBC', length: 256 },
176      false, ['encrypt']);
177
178    await assert.rejects(
179      subtle.deriveKey(
180        {
181          name: 'X448',
182          public: key
183        },
184        keys.X448.publicKey,
185        ...otherArgs),
186      { name: 'InvalidAccessError' });
187  }
188})().then(common.mustCall());
189