1'use strict'; 2const common = require('../common'); 3 4if (!common.hasCrypto) 5 common.skip('missing crypto'); 6 7if (common.hasFipsCrypto) 8 common.skip('not supported in FIPS mode'); 9 10const crypto = require('crypto'); 11const assert = require('assert'); 12 13common.expectWarning({ 14 Warning: [ 15 ['Use Cipheriv for counter mode of aes-256-gcm'], 16 ], 17 DeprecationWarning: [ 18 ['crypto.createCipher is deprecated.', 'DEP0106'], 19 ] 20}); 21 22function testCipher1(key) { 23 // Test encryption and decryption 24 const plaintext = 'Keep this a secret? No! Tell everyone about node.js!'; 25 const cipher = crypto.createCipher('aes192', key); 26 27 // Encrypt plaintext which is in utf8 format 28 // to a ciphertext which will be in hex 29 let ciph = cipher.update(plaintext, 'utf8', 'hex'); 30 // Only use binary or hex, not base64. 31 ciph += cipher.final('hex'); 32 33 const decipher = crypto.createDecipher('aes192', key); 34 let txt = decipher.update(ciph, 'hex', 'utf8'); 35 txt += decipher.final('utf8'); 36 37 assert.strictEqual(txt, plaintext); 38 39 // Streaming cipher interface 40 // NB: In real life, it's not guaranteed that you can get all of it 41 // in a single read() like this. But in this case, we know it's 42 // quite small, so there's no harm. 43 const cStream = crypto.createCipher('aes192', key); 44 cStream.end(plaintext); 45 ciph = cStream.read(); 46 47 const dStream = crypto.createDecipher('aes192', key); 48 dStream.end(ciph); 49 txt = dStream.read().toString('utf8'); 50 51 assert.strictEqual(txt, plaintext); 52} 53 54 55function testCipher2(key) { 56 // Encryption and decryption with Base64. 57 // Reported in https://github.com/joyent/node/issues/738 58 const plaintext = 59 '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' + 60 'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' + 61 'jAfaFg**'; 62 const cipher = crypto.createCipher('aes256', key); 63 64 // Encrypt plaintext which is in utf8 format to a ciphertext which will be in 65 // Base64. 66 let ciph = cipher.update(plaintext, 'utf8', 'base64'); 67 ciph += cipher.final('base64'); 68 69 const decipher = crypto.createDecipher('aes256', key); 70 let txt = decipher.update(ciph, 'base64', 'utf8'); 71 txt += decipher.final('utf8'); 72 73 assert.strictEqual(txt, plaintext); 74} 75 76testCipher1('MySecretKey123'); 77testCipher1(Buffer.from('MySecretKey123')); 78 79testCipher2('0123456789abcdef'); 80testCipher2(Buffer.from('0123456789abcdef')); 81 82{ 83 const Cipher = crypto.Cipher; 84 const instance = crypto.Cipher('aes-256-cbc', 'secret'); 85 assert(instance instanceof Cipher, 'Cipher is expected to return a new ' + 86 'instance when called without `new`'); 87 88 assert.throws( 89 () => crypto.createCipher(null), 90 { 91 code: 'ERR_INVALID_ARG_TYPE', 92 name: 'TypeError', 93 message: 'The "cipher" argument must be of type string. ' + 94 'Received null' 95 }); 96 97 assert.throws( 98 () => crypto.createCipher('aes-256-cbc', null), 99 { 100 code: 'ERR_INVALID_ARG_TYPE', 101 name: 'TypeError' 102 }); 103 104 assert.throws( 105 () => crypto.createCipher('aes-256-cbc', 'secret').update(null), 106 { 107 code: 'ERR_INVALID_ARG_TYPE', 108 name: 'TypeError', 109 }); 110 111 assert.throws( 112 () => crypto.createCipher('aes-256-cbc', 'secret').setAAD(null), 113 { 114 code: 'ERR_INVALID_ARG_TYPE', 115 name: 'TypeError', 116 }); 117} 118 119{ 120 const Decipher = crypto.Decipher; 121 const instance = crypto.Decipher('aes-256-cbc', 'secret'); 122 assert(instance instanceof Decipher, 'Decipher is expected to return a new ' + 123 'instance when called without `new`'); 124 125 assert.throws( 126 () => crypto.createDecipher(null), 127 { 128 code: 'ERR_INVALID_ARG_TYPE', 129 name: 'TypeError', 130 message: 'The "cipher" argument must be of type string. ' + 131 'Received null' 132 }); 133 134 assert.throws( 135 () => crypto.createDecipher('aes-256-cbc', 'secret').setAuthTag(null), 136 { 137 code: 'ERR_INVALID_ARG_TYPE', 138 name: 'TypeError', 139 }); 140 141 assert.throws( 142 () => crypto.createDecipher('aes-256-cbc', null), 143 { 144 code: 'ERR_INVALID_ARG_TYPE', 145 name: 'TypeError', 146 }); 147} 148 149// Base64 padding regression test, see 150// https://github.com/nodejs/node-v0.x-archive/issues/4837. 151{ 152 const c = crypto.createCipher('aes-256-cbc', 'secret'); 153 const s = c.update('test', 'utf8', 'base64') + c.final('base64'); 154 assert.strictEqual(s, '375oxUQCIocvxmC5At+rvA=='); 155} 156 157// Calling Cipher.final() or Decipher.final() twice should error but 158// not assert. See https://github.com/nodejs/node-v0.x-archive/issues/4886. 159{ 160 const c = crypto.createCipher('aes-256-cbc', 'secret'); 161 try { c.final('xxx'); } catch { /* Ignore. */ } 162 try { c.final('xxx'); } catch { /* Ignore. */ } 163 try { c.final('xxx'); } catch { /* Ignore. */ } 164 const d = crypto.createDecipher('aes-256-cbc', 'secret'); 165 try { d.final('xxx'); } catch { /* Ignore. */ } 166 try { d.final('xxx'); } catch { /* Ignore. */ } 167 try { d.final('xxx'); } catch { /* Ignore. */ } 168} 169 170// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/5482: 171// string to Cipher#update() should not assert. 172{ 173 const c = crypto.createCipher('aes192', '0123456789abcdef'); 174 c.update('update'); 175 c.final(); 176} 177 178// https://github.com/nodejs/node-v0.x-archive/issues/5655 regression tests, 179// 'utf-8' and 'utf8' are identical. 180{ 181 let c = crypto.createCipher('aes192', '0123456789abcdef'); 182 c.update('update', ''); // Defaults to "utf8". 183 c.final('utf-8'); // Should not throw. 184 185 c = crypto.createCipher('aes192', '0123456789abcdef'); 186 c.update('update', 'utf8'); 187 c.final('utf-8'); // Should not throw. 188 189 c = crypto.createCipher('aes192', '0123456789abcdef'); 190 c.update('update', 'utf-8'); 191 c.final('utf8'); // Should not throw. 192} 193 194// Regression tests for https://github.com/nodejs/node/issues/8236. 195{ 196 const key = '0123456789abcdef'; 197 const plaintext = 'Top secret!!!'; 198 const c = crypto.createCipher('aes192', key); 199 let ciph = c.update(plaintext, 'utf16le', 'base64'); 200 ciph += c.final('base64'); 201 202 let decipher = crypto.createDecipher('aes192', key); 203 204 let txt; 205 txt = decipher.update(ciph, 'base64', 'ucs2'); 206 txt += decipher.final('ucs2'); 207 assert.strictEqual(txt, plaintext); 208 209 decipher = crypto.createDecipher('aes192', key); 210 txt = decipher.update(ciph, 'base64', 'ucs-2'); 211 txt += decipher.final('ucs-2'); 212 assert.strictEqual(txt, plaintext); 213 214 decipher = crypto.createDecipher('aes192', key); 215 txt = decipher.update(ciph, 'base64', 'utf-16le'); 216 txt += decipher.final('utf-16le'); 217 assert.strictEqual(txt, plaintext); 218} 219 220// setAutoPadding/setAuthTag/setAAD should return `this` 221{ 222 const key = '0123456789'; 223 const tagbuf = Buffer.from('auth_tag'); 224 const aadbuf = Buffer.from('aadbuf'); 225 const decipher = crypto.createDecipher('aes-256-gcm', key); 226 assert.strictEqual(decipher.setAutoPadding(), decipher); 227 assert.strictEqual(decipher.setAuthTag(tagbuf), decipher); 228 assert.strictEqual(decipher.setAAD(aadbuf), decipher); 229} 230 231// Error throwing in setAAD/setAuthTag/getAuthTag/setAutoPadding 232{ 233 const key = '0123456789'; 234 const aadbuf = Buffer.from('aadbuf'); 235 const data = Buffer.from('test-crypto-cipher-decipher'); 236 237 const cipher = crypto.createCipher('aes-256-gcm', key); 238 cipher.setAAD(aadbuf); 239 cipher.setAutoPadding(); 240 241 assert.throws( 242 () => cipher.getAuthTag(), 243 { 244 code: 'ERR_CRYPTO_INVALID_STATE', 245 name: 'Error', 246 message: 'Invalid state for operation getAuthTag' 247 } 248 ); 249 250 const encrypted = Buffer.concat([cipher.update(data), cipher.final()]); 251 252 const decipher = crypto.createDecipher('aes-256-gcm', key); 253 decipher.setAAD(aadbuf); 254 decipher.setAuthTag(cipher.getAuthTag()); 255 decipher.setAutoPadding(); 256 decipher.update(encrypted); 257 decipher.final(); 258 259 assert.throws( 260 () => decipher.setAAD(aadbuf), 261 { 262 code: 'ERR_CRYPTO_INVALID_STATE', 263 name: 'Error', 264 message: 'Invalid state for operation setAAD' 265 }); 266 267 assert.throws( 268 () => decipher.setAuthTag(cipher.getAuthTag()), 269 { 270 code: 'ERR_CRYPTO_INVALID_STATE', 271 name: 'Error', 272 message: 'Invalid state for operation setAuthTag' 273 }); 274 275 assert.throws( 276 () => decipher.setAutoPadding(), 277 { 278 code: 'ERR_CRYPTO_INVALID_STATE', 279 name: 'Error', 280 message: 'Invalid state for operation setAutoPadding' 281 } 282 ); 283} 284