1'use strict'; 2 3const common = require('../common'); 4 5if (!common.hasCrypto) 6 common.skip('missing crypto'); 7 8const assert = require('assert'); 9const { subtle } = require('crypto').webcrypto; 10 11const { 12 passing 13} = require('../fixtures/crypto/rsa')(); 14 15async function importVectorKey( 16 publicKeyBuffer, 17 privateKeyBuffer, 18 name, 19 hash, 20 publicUsages, 21 privateUsages) { 22 const [publicKey, privateKey] = await Promise.all([ 23 subtle.importKey( 24 'spki', publicKeyBuffer, { name, hash }, false, publicUsages), 25 subtle.importKey( 26 'pkcs8', privateKeyBuffer, { name, hash }, false, privateUsages), 27 ]); 28 29 return { publicKey, privateKey }; 30} 31 32async function testDecryption({ ciphertext, 33 algorithm, 34 plaintext, 35 hash, 36 publicKeyBuffer, 37 privateKeyBuffer }) { 38 if (ciphertext === undefined) 39 return; 40 41 const { 42 privateKey 43 } = await importVectorKey( 44 publicKeyBuffer, 45 privateKeyBuffer, 46 algorithm.name, 47 hash, 48 ['encrypt'], 49 ['decrypt']); 50 51 const encodedPlaintext = Buffer.from(plaintext).toString('hex'); 52 const result = await subtle.decrypt(algorithm, privateKey, ciphertext); 53 54 assert.strictEqual( 55 Buffer.from(result).toString('hex'), 56 encodedPlaintext); 57 58 const ciphercopy = Buffer.from(ciphertext); 59 60 // Modifying the ciphercopy after calling decrypt should just work 61 const result2 = await subtle.decrypt(algorithm, privateKey, ciphercopy); 62 ciphercopy[0] = 255 - ciphercopy[0]; 63 64 assert.strictEqual( 65 Buffer.from(result2).toString('hex'), 66 encodedPlaintext); 67} 68 69async function testEncryption( 70 { 71 ciphertext, 72 algorithm, 73 plaintext, 74 hash, 75 publicKeyBuffer, 76 privateKeyBuffer 77 }, 78 modify = false) { 79 const { 80 publicKey, 81 privateKey 82 } = await importVectorKey( 83 publicKeyBuffer, 84 privateKeyBuffer, 85 algorithm.name, 86 hash, 87 ['encrypt'], 88 ['decrypt']); 89 90 if (modify) 91 plaintext = Buffer.from(plaintext); // make a copy 92 93 const encodedPlaintext = Buffer.from(plaintext).toString('hex'); 94 95 const result = await subtle.encrypt(algorithm, publicKey, plaintext); 96 if (modify) 97 plaintext[0] = 255 - plaintext[0]; 98 99 assert.strictEqual( 100 result.byteLength * 8, 101 privateKey.algorithm.modulusLength); 102 103 const out = await subtle.decrypt(algorithm, privateKey, result); 104 105 assert.strictEqual( 106 Buffer.from(out).toString('hex'), 107 encodedPlaintext); 108} 109 110async function testEncryptionLongPlaintext({ algorithm, 111 plaintext, 112 hash, 113 publicKeyBuffer, 114 privateKeyBuffer }) { 115 const { 116 publicKey, 117 } = await importVectorKey( 118 publicKeyBuffer, 119 privateKeyBuffer, 120 algorithm.name, 121 hash, 122 ['encrypt'], 123 ['decrypt']); 124 const newplaintext = new Uint8Array(plaintext.byteLength + 1); 125 newplaintext.set(plaintext, 0); 126 newplaintext[plaintext.byteLength] = 32; 127 128 return assert.rejects( 129 subtle.encrypt(algorithm, publicKey, newplaintext), { 130 name: 'OperationError' 131 }); 132} 133 134async function testEncryptionWrongKey({ algorithm, 135 plaintext, 136 hash, 137 publicKeyBuffer, 138 privateKeyBuffer }) { 139 const { 140 privateKey, 141 } = await importVectorKey( 142 publicKeyBuffer, 143 privateKeyBuffer, 144 algorithm.name, 145 hash, 146 ['encrypt'], 147 ['decrypt']); 148 return assert.rejects( 149 subtle.encrypt(algorithm, privateKey, plaintext), { 150 message: /The requested operation is not valid/ 151 }); 152} 153 154async function testEncryptionBadUsage({ algorithm, 155 plaintext, 156 hash, 157 publicKeyBuffer, 158 privateKeyBuffer }) { 159 const { 160 publicKey, 161 } = await importVectorKey( 162 publicKeyBuffer, 163 privateKeyBuffer, 164 algorithm.name, 165 hash, 166 ['wrapKey'], 167 ['decrypt']); 168 return assert.rejects( 169 subtle.encrypt(algorithm, publicKey, plaintext), { 170 message: /The requested operation is not valid/ 171 }); 172} 173 174async function testDecryptionWrongKey({ ciphertext, 175 algorithm, 176 hash, 177 publicKeyBuffer, 178 privateKeyBuffer }) { 179 if (ciphertext === undefined) 180 return; 181 182 const { 183 publicKey 184 } = await importVectorKey( 185 publicKeyBuffer, 186 privateKeyBuffer, 187 algorithm.name, 188 hash, 189 ['encrypt'], 190 ['decrypt']); 191 192 return assert.rejects( 193 subtle.decrypt(algorithm, publicKey, ciphertext), { 194 message: /The requested operation is not valid/ 195 }); 196} 197 198async function testDecryptionBadUsage({ ciphertext, 199 algorithm, 200 hash, 201 publicKeyBuffer, 202 privateKeyBuffer }) { 203 if (ciphertext === undefined) 204 return; 205 206 const { 207 publicKey 208 } = await importVectorKey( 209 publicKeyBuffer, 210 privateKeyBuffer, 211 algorithm.name, 212 hash, 213 ['encrypt'], 214 ['unwrapKey']); 215 216 return assert.rejects( 217 subtle.decrypt(algorithm, publicKey, ciphertext), { 218 message: /The requested operation is not valid/ 219 }); 220} 221 222(async function() { 223 const variations = []; 224 225 // Test decryption 226 passing.forEach(async (vector) => { 227 variations.push(testDecryption(vector)); 228 variations.push(testDecryptionWrongKey(vector)); 229 variations.push(testDecryptionBadUsage(vector)); 230 variations.push(testEncryption(vector)); 231 variations.push(testEncryption(vector, true)); 232 variations.push(testEncryptionLongPlaintext(vector)); 233 variations.push(testEncryptionWrongKey(vector)); 234 variations.push(testEncryptionBadUsage(vector)); 235 }); 236 237 await Promise.all(variations); 238})().then(common.mustCall()); 239