11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci// Refs: https://github.com/nodejs/node/issues/31733 31cb0ef41Sopenharmony_ciconst common = require('../common'); 41cb0ef41Sopenharmony_ciif (!common.hasCrypto) 51cb0ef41Sopenharmony_ci common.skip('missing crypto'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst assert = require('assert'); 81cb0ef41Sopenharmony_ciconst crypto = require('crypto'); 91cb0ef41Sopenharmony_ciconst fs = require('fs'); 101cb0ef41Sopenharmony_ciconst path = require('path'); 111cb0ef41Sopenharmony_ciconst stream = require('stream'); 121cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir'); 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciclass Sink extends stream.Writable { 151cb0ef41Sopenharmony_ci constructor() { 161cb0ef41Sopenharmony_ci super(); 171cb0ef41Sopenharmony_ci this.chunks = []; 181cb0ef41Sopenharmony_ci } 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci _write(chunk, encoding, cb) { 211cb0ef41Sopenharmony_ci this.chunks.push(chunk); 221cb0ef41Sopenharmony_ci cb(); 231cb0ef41Sopenharmony_ci } 241cb0ef41Sopenharmony_ci} 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_cifunction direct(config) { 271cb0ef41Sopenharmony_ci const { cipher, key, iv, aad, authTagLength, plaintextLength } = config; 281cb0ef41Sopenharmony_ci const expected = Buffer.alloc(plaintextLength); 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci const c = crypto.createCipheriv(cipher, key, iv, { authTagLength }); 311cb0ef41Sopenharmony_ci c.setAAD(aad, { plaintextLength }); 321cb0ef41Sopenharmony_ci const ciphertext = Buffer.concat([c.update(expected), c.final()]); 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci const d = crypto.createDecipheriv(cipher, key, iv, { authTagLength }); 351cb0ef41Sopenharmony_ci d.setAAD(aad, { plaintextLength }); 361cb0ef41Sopenharmony_ci d.setAuthTag(c.getAuthTag()); 371cb0ef41Sopenharmony_ci const actual = Buffer.concat([d.update(ciphertext), d.final()]); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci assert.deepStrictEqual(expected, actual); 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_cifunction mstream(config) { 431cb0ef41Sopenharmony_ci const { cipher, key, iv, aad, authTagLength, plaintextLength } = config; 441cb0ef41Sopenharmony_ci const expected = Buffer.alloc(plaintextLength); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci const c = crypto.createCipheriv(cipher, key, iv, { authTagLength }); 471cb0ef41Sopenharmony_ci c.setAAD(aad, { plaintextLength }); 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci const plain = new stream.PassThrough(); 501cb0ef41Sopenharmony_ci const crypt = new Sink(); 511cb0ef41Sopenharmony_ci const chunks = crypt.chunks; 521cb0ef41Sopenharmony_ci plain.pipe(c).pipe(crypt); 531cb0ef41Sopenharmony_ci plain.end(expected); 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci crypt.on('close', common.mustCall(() => { 561cb0ef41Sopenharmony_ci const d = crypto.createDecipheriv(cipher, key, iv, { authTagLength }); 571cb0ef41Sopenharmony_ci d.setAAD(aad, { plaintextLength }); 581cb0ef41Sopenharmony_ci d.setAuthTag(c.getAuthTag()); 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci const crypt = new stream.PassThrough(); 611cb0ef41Sopenharmony_ci const plain = new Sink(); 621cb0ef41Sopenharmony_ci crypt.pipe(d).pipe(plain); 631cb0ef41Sopenharmony_ci for (const chunk of chunks) crypt.write(chunk); 641cb0ef41Sopenharmony_ci crypt.end(); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci plain.on('close', common.mustCall(() => { 671cb0ef41Sopenharmony_ci const actual = Buffer.concat(plain.chunks); 681cb0ef41Sopenharmony_ci assert.deepStrictEqual(expected, actual); 691cb0ef41Sopenharmony_ci })); 701cb0ef41Sopenharmony_ci })); 711cb0ef41Sopenharmony_ci} 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_cifunction fstream(config) { 741cb0ef41Sopenharmony_ci const count = fstream.count++; 751cb0ef41Sopenharmony_ci const filename = (name) => path.join(tmpdir.path, `${name}${count}`); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci const { cipher, key, iv, aad, authTagLength, plaintextLength } = config; 781cb0ef41Sopenharmony_ci const expected = Buffer.alloc(plaintextLength); 791cb0ef41Sopenharmony_ci fs.writeFileSync(filename('a'), expected); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci const c = crypto.createCipheriv(cipher, key, iv, { authTagLength }); 821cb0ef41Sopenharmony_ci c.setAAD(aad, { plaintextLength }); 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci const plain = fs.createReadStream(filename('a')); 851cb0ef41Sopenharmony_ci const crypt = fs.createWriteStream(filename('b')); 861cb0ef41Sopenharmony_ci plain.pipe(c).pipe(crypt); 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci // Observation: 'close' comes before 'end' on |c|, which definitely feels 891cb0ef41Sopenharmony_ci // wrong. Switching to `c.on('end', ...)` doesn't fix the test though. 901cb0ef41Sopenharmony_ci crypt.on('close', common.mustCall(() => { 911cb0ef41Sopenharmony_ci // Just to drive home the point that decryption does actually work: 921cb0ef41Sopenharmony_ci // reading the file synchronously, then decrypting it, works. 931cb0ef41Sopenharmony_ci { 941cb0ef41Sopenharmony_ci const ciphertext = fs.readFileSync(filename('b')); 951cb0ef41Sopenharmony_ci const d = crypto.createDecipheriv(cipher, key, iv, { authTagLength }); 961cb0ef41Sopenharmony_ci d.setAAD(aad, { plaintextLength }); 971cb0ef41Sopenharmony_ci d.setAuthTag(c.getAuthTag()); 981cb0ef41Sopenharmony_ci const actual = Buffer.concat([d.update(ciphertext), d.final()]); 991cb0ef41Sopenharmony_ci assert.deepStrictEqual(expected, actual); 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci const d = crypto.createDecipheriv(cipher, key, iv, { authTagLength }); 1031cb0ef41Sopenharmony_ci d.setAAD(aad, { plaintextLength }); 1041cb0ef41Sopenharmony_ci d.setAuthTag(c.getAuthTag()); 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci const crypt = fs.createReadStream(filename('b')); 1071cb0ef41Sopenharmony_ci const plain = fs.createWriteStream(filename('c')); 1081cb0ef41Sopenharmony_ci crypt.pipe(d).pipe(plain); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci plain.on('close', common.mustCall(() => { 1111cb0ef41Sopenharmony_ci const actual = fs.readFileSync(filename('c')); 1121cb0ef41Sopenharmony_ci assert.deepStrictEqual(expected, actual); 1131cb0ef41Sopenharmony_ci })); 1141cb0ef41Sopenharmony_ci })); 1151cb0ef41Sopenharmony_ci} 1161cb0ef41Sopenharmony_cifstream.count = 0; 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_cifunction test(config) { 1191cb0ef41Sopenharmony_ci direct(config); 1201cb0ef41Sopenharmony_ci mstream(config); 1211cb0ef41Sopenharmony_ci fstream(config); 1221cb0ef41Sopenharmony_ci} 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_citmpdir.refresh(); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_citest({ 1271cb0ef41Sopenharmony_ci cipher: 'aes-128-ccm', 1281cb0ef41Sopenharmony_ci aad: Buffer.alloc(1), 1291cb0ef41Sopenharmony_ci iv: Buffer.alloc(8), 1301cb0ef41Sopenharmony_ci key: Buffer.alloc(16), 1311cb0ef41Sopenharmony_ci authTagLength: 16, 1321cb0ef41Sopenharmony_ci plaintextLength: 32768, 1331cb0ef41Sopenharmony_ci}); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_citest({ 1361cb0ef41Sopenharmony_ci cipher: 'aes-128-ccm', 1371cb0ef41Sopenharmony_ci aad: Buffer.alloc(1), 1381cb0ef41Sopenharmony_ci iv: Buffer.alloc(8), 1391cb0ef41Sopenharmony_ci key: Buffer.alloc(16), 1401cb0ef41Sopenharmony_ci authTagLength: 16, 1411cb0ef41Sopenharmony_ci plaintextLength: 32769, 1421cb0ef41Sopenharmony_ci}); 143