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 12async function testEncrypt({ keyBuffer, algorithm, plaintext, result }) { 13 // Using a copy of plaintext to prevent tampering of the original 14 plaintext = Buffer.from(plaintext); 15 16 const key = await subtle.importKey( 17 'raw', 18 keyBuffer, 19 { name: algorithm.name }, 20 false, 21 ['encrypt', 'decrypt']); 22 23 const output = await subtle.encrypt(algorithm, key, plaintext); 24 plaintext[0] = 255 - plaintext[0]; 25 26 assert.strictEqual( 27 Buffer.from(output).toString('hex'), 28 Buffer.from(result).toString('hex')); 29 30 // Converting the returned ArrayBuffer into a Buffer right away, 31 // so that the next line works 32 const check = Buffer.from(await subtle.decrypt(algorithm, key, output)); 33 check[0] = 255 - check[0]; 34 35 assert.strictEqual( 36 Buffer.from(check).toString('hex'), 37 Buffer.from(plaintext).toString('hex')); 38} 39 40async function testEncryptNoEncrypt({ keyBuffer, algorithm, plaintext }) { 41 const key = await subtle.importKey( 42 'raw', 43 keyBuffer, 44 { name: algorithm.name }, 45 false, 46 ['decrypt']); 47 48 return assert.rejects(subtle.encrypt(algorithm, key, plaintext), { 49 message: /The requested operation is not valid for the provided key/ 50 }); 51} 52 53async function testEncryptNoDecrypt({ keyBuffer, algorithm, plaintext }) { 54 const key = await subtle.importKey( 55 'raw', 56 keyBuffer, 57 { name: algorithm.name }, 58 false, 59 ['encrypt']); 60 61 const output = await subtle.encrypt(algorithm, key, plaintext); 62 63 return assert.rejects(subtle.decrypt(algorithm, key, output), { 64 message: /The requested operation is not valid for the provided key/ 65 }); 66} 67 68async function testEncryptWrongAlg({ keyBuffer, algorithm, plaintext }, alg) { 69 assert.notStrictEqual(algorithm.name, alg); 70 const key = await subtle.importKey( 71 'raw', 72 keyBuffer, 73 { name: alg }, 74 false, 75 ['encrypt']); 76 77 return assert.rejects(subtle.encrypt(algorithm, key, plaintext), { 78 message: /The requested operation is not valid for the provided key/ 79 }); 80} 81 82async function testDecrypt({ keyBuffer, algorithm, result }) { 83 const key = await subtle.importKey( 84 'raw', 85 keyBuffer, 86 { name: algorithm.name }, 87 false, 88 ['encrypt', 'decrypt']); 89 90 await subtle.decrypt(algorithm, key, result); 91} 92 93// Test aes-cbc vectors 94{ 95 const { 96 passing, 97 failing, 98 decryptionFailing 99 } = require('../fixtures/crypto/aes_cbc')(); 100 101 (async function() { 102 const variations = []; 103 104 passing.forEach((vector) => { 105 variations.push(testEncrypt(vector)); 106 variations.push(testEncryptNoEncrypt(vector)); 107 variations.push(testEncryptNoDecrypt(vector)); 108 variations.push(testEncryptWrongAlg(vector, 'AES-CTR')); 109 }); 110 111 failing.forEach((vector) => { 112 variations.push(assert.rejects(testEncrypt(vector), { 113 message: /algorithm\.iv must contain exactly 16 bytes/ 114 })); 115 variations.push(assert.rejects(testDecrypt(vector), { 116 message: /algorithm\.iv must contain exactly 16 bytes/ 117 })); 118 }); 119 120 decryptionFailing.forEach((vector) => { 121 variations.push(assert.rejects(testDecrypt(vector), { 122 name: 'OperationError' 123 })); 124 }); 125 126 await Promise.all(variations); 127 })().then(common.mustCall()); 128} 129 130// Test aes-ctr vectors 131{ 132 const { 133 passing, 134 failing, 135 decryptionFailing 136 } = require('../fixtures/crypto/aes_ctr')(); 137 138 (async function() { 139 const variations = []; 140 141 passing.forEach((vector) => { 142 variations.push(testEncrypt(vector)); 143 variations.push(testEncryptNoEncrypt(vector)); 144 variations.push(testEncryptNoDecrypt(vector)); 145 variations.push(testEncryptWrongAlg(vector, 'AES-CBC')); 146 }); 147 148 // TODO(@jasnell): These fail for different reasons. Need to 149 // make them consistent 150 failing.forEach((vector) => { 151 variations.push(assert.rejects(testEncrypt(vector), { 152 message: /.*/ 153 })); 154 variations.push(assert.rejects(testDecrypt(vector), { 155 message: /.*/ 156 })); 157 }); 158 159 decryptionFailing.forEach((vector) => { 160 variations.push(assert.rejects(testDecrypt(vector), { 161 name: 'OperationError' 162 })); 163 }); 164 165 await Promise.all(variations); 166 })().then(common.mustCall()); 167} 168 169// Test aes-gcm vectors 170{ 171 const { 172 passing, 173 failing, 174 decryptionFailing 175 } = require('../fixtures/crypto/aes_gcm')(); 176 177 (async function() { 178 const variations = []; 179 180 passing.forEach((vector) => { 181 variations.push(testEncrypt(vector)); 182 variations.push(testEncryptNoEncrypt(vector)); 183 variations.push(testEncryptNoDecrypt(vector)); 184 variations.push(testEncryptWrongAlg(vector, 'AES-CBC')); 185 }); 186 187 failing.forEach((vector) => { 188 variations.push(assert.rejects(testEncrypt(vector), { 189 message: /is not a valid AES-GCM tag length/ 190 })); 191 variations.push(assert.rejects(testDecrypt(vector), { 192 message: /is not a valid AES-GCM tag length/ 193 })); 194 }); 195 196 decryptionFailing.forEach((vector) => { 197 variations.push(assert.rejects(testDecrypt(vector), { 198 name: 'OperationError' 199 })); 200 }); 201 202 await Promise.all(variations); 203 })().then(common.mustCall()); 204} 205 206{ 207 (async function() { 208 const secretKey = await subtle.generateKey( 209 { 210 name: 'AES-GCM', 211 length: 256, 212 }, 213 false, 214 ['encrypt', 'decrypt'], 215 ); 216 217 const iv = webcrypto.getRandomValues(new Uint8Array(12)); 218 const aad = webcrypto.getRandomValues(new Uint8Array(32)); 219 220 const encrypted = await subtle.encrypt( 221 { 222 name: 'AES-GCM', 223 iv, 224 additionalData: aad, 225 tagLength: 128 226 }, 227 secretKey, 228 webcrypto.getRandomValues(new Uint8Array(32)) 229 ); 230 231 await subtle.decrypt( 232 { 233 name: 'AES-GCM', 234 iv, 235 additionalData: aad, 236 tagLength: 128, 237 }, 238 secretKey, 239 new Uint8Array(encrypted), 240 ); 241 })().then(common.mustCall()); 242} 243