1'use strict'; 2const common = require('../common'); 3if (!common.hasCrypto) 4 common.skip('missing crypto'); 5 6const assert = require('assert'); 7const crypto = require('crypto'); 8 9function testCipher1(key, iv) { 10 // Test encryption and decryption with explicit key and iv 11 const plaintext = 12 '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' + 13 'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' + 14 'jAfaFg**'; 15 const cipher = crypto.createCipheriv('des-ede3-cbc', key, iv); 16 let ciph = cipher.update(plaintext, 'utf8', 'hex'); 17 ciph += cipher.final('hex'); 18 19 const decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv); 20 let txt = decipher.update(ciph, 'hex', 'utf8'); 21 txt += decipher.final('utf8'); 22 23 assert.strictEqual(txt, plaintext, 24 `encryption/decryption with key ${key} and iv ${iv}`); 25 26 // Streaming cipher interface 27 // NB: In real life, it's not guaranteed that you can get all of it 28 // in a single read() like this. But in this case, we know it's 29 // quite small, so there's no harm. 30 const cStream = crypto.createCipheriv('des-ede3-cbc', key, iv); 31 cStream.end(plaintext); 32 ciph = cStream.read(); 33 34 const dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv); 35 dStream.end(ciph); 36 txt = dStream.read().toString('utf8'); 37 38 assert.strictEqual(txt, plaintext, 39 `streaming cipher with key ${key} and iv ${iv}`); 40} 41 42 43function testCipher2(key, iv) { 44 // Test encryption and decryption with explicit key and iv 45 const plaintext = 46 '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' + 47 'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' + 48 'jAfaFg**'; 49 const cipher = crypto.createCipheriv('des-ede3-cbc', key, iv); 50 let ciph = cipher.update(plaintext, 'utf8', 'buffer'); 51 ciph = Buffer.concat([ciph, cipher.final('buffer')]); 52 53 const decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv); 54 let txt = decipher.update(ciph, 'buffer', 'utf8'); 55 txt += decipher.final('utf8'); 56 57 assert.strictEqual(txt, plaintext, 58 `encryption/decryption with key ${key} and iv ${iv}`); 59} 60 61 62function testCipher3(key, iv) { 63 // Test encryption and decryption with explicit key and iv. 64 // AES Key Wrap test vector comes from RFC3394 65 const plaintext = Buffer.from('00112233445566778899AABBCCDDEEFF', 'hex'); 66 67 const cipher = crypto.createCipheriv('id-aes128-wrap', key, iv); 68 let ciph = cipher.update(plaintext, 'utf8', 'buffer'); 69 ciph = Buffer.concat([ciph, cipher.final('buffer')]); 70 const ciph2 = Buffer.from('1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5', 71 'hex'); 72 assert(ciph.equals(ciph2)); 73 const decipher = crypto.createDecipheriv('id-aes128-wrap', key, iv); 74 let deciph = decipher.update(ciph, 'buffer'); 75 deciph = Buffer.concat([deciph, decipher.final()]); 76 77 assert(deciph.equals(plaintext), 78 `encryption/decryption with key ${key} and iv ${iv}`); 79} 80 81{ 82 const Cipheriv = crypto.Cipheriv; 83 const key = '123456789012345678901234'; 84 const iv = '12345678'; 85 86 const instance = Cipheriv('des-ede3-cbc', key, iv); 87 assert(instance instanceof Cipheriv, 'Cipheriv is expected to return a new ' + 88 'instance when called without `new`'); 89 90 assert.throws( 91 () => crypto.createCipheriv(null), 92 { 93 code: 'ERR_INVALID_ARG_TYPE', 94 name: 'TypeError', 95 message: 'The "cipher" argument must be of type string. ' + 96 'Received null' 97 }); 98 99 assert.throws( 100 () => crypto.createCipheriv('des-ede3-cbc', null), 101 { 102 code: 'ERR_INVALID_ARG_TYPE', 103 name: 'TypeError', 104 }); 105 106 assert.throws( 107 () => crypto.createCipheriv('des-ede3-cbc', key, 10), 108 { 109 code: 'ERR_INVALID_ARG_TYPE', 110 name: 'TypeError', 111 }); 112} 113 114{ 115 const Decipheriv = crypto.Decipheriv; 116 const key = '123456789012345678901234'; 117 const iv = '12345678'; 118 119 const instance = Decipheriv('des-ede3-cbc', key, iv); 120 assert(instance instanceof Decipheriv, 'Decipheriv expected to return a new' + 121 ' instance when called without `new`'); 122 123 assert.throws( 124 () => crypto.createDecipheriv(null), 125 { 126 code: 'ERR_INVALID_ARG_TYPE', 127 name: 'TypeError', 128 message: 'The "cipher" argument must be of type string. ' + 129 'Received null' 130 }); 131 132 assert.throws( 133 () => crypto.createDecipheriv('des-ede3-cbc', null), 134 { 135 code: 'ERR_INVALID_ARG_TYPE', 136 name: 'TypeError', 137 }); 138 139 assert.throws( 140 () => crypto.createDecipheriv('des-ede3-cbc', key, 10), 141 { 142 code: 'ERR_INVALID_ARG_TYPE', 143 name: 'TypeError', 144 }); 145} 146 147testCipher1('0123456789abcd0123456789', '12345678'); 148testCipher1('0123456789abcd0123456789', Buffer.from('12345678')); 149testCipher1(Buffer.from('0123456789abcd0123456789'), '12345678'); 150testCipher1(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678')); 151testCipher2(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678')); 152 153if (!common.hasFipsCrypto) { 154 testCipher3(Buffer.from('000102030405060708090A0B0C0D0E0F', 'hex'), 155 Buffer.from('A6A6A6A6A6A6A6A6', 'hex')); 156} 157 158// Zero-sized IV or null should be accepted in ECB mode. 159crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), Buffer.alloc(0)); 160crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), null); 161 162const errMessage = /Invalid initialization vector/; 163 164// But non-empty IVs should be rejected. 165for (let n = 1; n < 256; n += 1) { 166 assert.throws( 167 () => crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), 168 Buffer.alloc(n)), 169 errMessage); 170} 171 172// Correctly sized IV should be accepted in CBC mode. 173crypto.createCipheriv('aes-128-cbc', Buffer.alloc(16), Buffer.alloc(16)); 174 175// But all other IV lengths should be rejected. 176for (let n = 0; n < 256; n += 1) { 177 if (n === 16) continue; 178 assert.throws( 179 () => crypto.createCipheriv('aes-128-cbc', Buffer.alloc(16), 180 Buffer.alloc(n)), 181 errMessage); 182} 183 184// And so should null be. 185assert.throws(() => { 186 crypto.createCipheriv('aes-128-cbc', Buffer.alloc(16), null); 187}, /Invalid initialization vector/); 188 189// Zero-sized IV should be rejected in GCM mode. 190assert.throws( 191 () => crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16), 192 Buffer.alloc(0)), 193 errMessage); 194 195// But all other IV lengths should be accepted. 196const minIvLength = common.hasOpenSSL3 ? 8 : 1; 197const maxIvLength = common.hasOpenSSL3 ? 64 : 256; 198for (let n = minIvLength; n < maxIvLength; n += 1) { 199 if (common.hasFipsCrypto && n < 12) continue; 200 crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16), Buffer.alloc(n)); 201} 202 203{ 204 // Passing an invalid cipher name should throw. 205 assert.throws( 206 () => crypto.createCipheriv('aes-127', Buffer.alloc(16), null), 207 { 208 name: 'Error', 209 code: 'ERR_CRYPTO_UNKNOWN_CIPHER', 210 message: 'Unknown cipher' 211 }); 212 213 // Passing a key with an invalid length should throw. 214 assert.throws( 215 () => crypto.createCipheriv('aes-128-ecb', Buffer.alloc(17), null), 216 /Invalid key length/); 217} 218 219{ 220 // https://github.com/nodejs/node/issues/45757 221 // eslint-disable-next-line no-restricted-syntax 222 assert.throws(() => 223 crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16), Buffer.alloc(12)) 224 .update(Buffer.allocUnsafeSlow(2 ** 31 - 1))); 225} 226