Search code examples
node.jsencryptioncryptographyaesnodejs-stream

Node.js pipe decipher file Error: Unsupported state or unable to authenticate data


I'm trying to encrypt/decrypt a file in stream with pipes. Encryption works, however when decrypting I get the error:

Error: Unsupported state or unable to authenticate data
at Decipheriv._flush (node:internal/crypto/cipher:160:29) at Decipheriv.final [as _final] (node:internal/streams/transform:112:25) at callFinal (node:internal/streams/writable:694:27) at prefinish (node:internal/streams/writable:719:7) at finishMaybe (node:internal/streams/writable:729:5) at Decipheriv.Writable.end (node:internal/streams/writable:631:5) at IOStream.onend (node:internal/streams/readable:693:10) at Object.onceWrapper (node:events:509:28) at IOStream.emit (node:events:402:35) at endReadableNT (node:internal/streams/readable:1343:12) Emitted 'error' event on Decipheriv instance at: at Decipheriv.onerror (node:internal/streams/readable:773:14) at Decipheriv.emit (node:events:390:28) at emitErrorNT (node:internal/streams/destroy:157:8) at emitErrorCloseNT (node:internal/streams/destroy:122:3) at processTicksAndRejections (node:internal/process/task_queues:83:21)

Code (last line produces the error):

const crypto = require('crypto');
const fs = require('fs');

const secret = crypto.randomBytes(32); 
const iv = crypto.randomBytes(16);

const cipher = crypto.createCipheriv('aes-256-gcm', secret, iv);
const decipher = crypto.createDecipheriv('aes-256-gcm', secret, iv);

fs.createReadStream('data.txt').pipe(cipher).
pipe(fs.createWriteStream('encrypted.txt'));

fs.createReadStream('encrypted.txt').pipe(decipher).
pipe(fs.createWriteStream('decrypted.txt'));

Solution

  • It works like this, waiting for it to finish reading/encryping before starting writing/encrypting.

    const crypto = require('crypto');
    const fs = require('fs');
    
    const secret = crypto.randomBytes(32);
    const iv = crypto.randomBytes(16);
    
    const cipher = crypto.createCipheriv('aes-256-gcm', secret, iv);
    const decipher = crypto.createDecipheriv('aes-256-gcm', secret, iv);
    
    fs.createReadStream('data.txt').pipe(cipher)
      .pipe(fs.createWriteStream('encrypted.txt'))
      .on('end', () => {
          fs.createReadStream('encrypted.txt')
            .pipe(decipher)
            .pipe(fs.createWriteStream('decrypted.txt'));
    });