I'm having trouble finding some information. Does anyone know if the value returned from cipher.getAuthTag() (--> returns MAC) can be publicly visible?
TL;DR
Can a message authentication code be publicly visible, or does this need to be kept secret like a password?
Some background, I am trying to encrypt a file. I found this stackoverflow question and answer that helped me get started. https://stackoverflow.com/a/27345933/11070228
After doing some research in the nodejs documentation, I found that the answer uses a deprecated function. createCipher. The new function to use should be createCipheriv.
So, to use the new createCipheriv, I used the documentation to write a new encryption and decryption function, similar to the one in the post using the new createCipheriv function. After writing the decryption function, I got an error that was
Error: Unsupported state or unable to authenticate data
After googling that issue, it led me here to this github post. In a nutshell, it said that the authTag generated with the cipher is needed to decrypt the file.
I did not know what this authTag was, and neither did anyone I knew. So I started googling that and it let me to this blogpost. It states
The authTag is the message authentication code (MAC) calculated during the encryption.
And here is a wikipedia article on what a message authentication code is.
So. Here is my question. Can a message authentication code be publicly visible, or does this need to be kept secret like a password?
My code, not as relevant, but might help someone create the encryption and decryption using createCipheriv and createDecipheriv.
Encryption
const crypto = require('crypto');
const fs = require('fs');
// const iv = crypto.randomBytes(32).toString('hex');
// EDIT - based on @President James K. Polk. The initialization vector should be 12 bytes long
// const iv = crypto.randomBytes(6).toString('hex');
// EDIT - based on @dsprenkels. I misunderstood @President James K. Polk
const iv = crypto.randomBytes(12).toString('hex');
const privateKey = 'private key that is 32 byte long';
const cipher = crypto.createCipheriv('aes-256-gcm', privateKey, iv);
const filename = 'somefile.txt';
const encFilename = 'somefile.txt.enc';
const unencryptedInput = fs.createReadStream(filename);
const encryptedOutput = fs.createWriteStream(encFilename);
unencryptedInput.pipe(cipher).pipe(encryptedOutput);
encryptedOutput.on('finish', () => {
const authTagAsHex = cipher.getAuthTag().toString('hex'); // <-- can this be public
console.log(authTagAsHex);
});
Decryption
const crypto = require('crypto');
const fs = require('fs');
// const publicIV = 'same iv generated during encryption crypto.randomBytes(32).toString("hex")';
// EDIT - based on @President James K. Polk. The initialization vector should be 12 bytes long
// const publicIV = 'same iv generated during encryption crypto.randomBytes(6).toString("hex")';
// EDIT - based on @dsprenkels. I misunderstood @President James K. Polk
const publicIV = 'same iv generated during encryption crypto.randomBytes(12).toString("hex")';
const authTag = 'same authKey generated from cipher.getAuthTag().toString("hex")';
const privateKey = 'private key that is 32 byte long';
const decipher = crypto.createDecipheriv('aes-256-gcm', privateKey, publicIV);
decipher.setAuthTag(Buffer.from(authTag, 'hex'));
const filename = 'somefile.txt';
const encFilename = 'somefile.txt.enc';
const readStream = fs.createReadStream(encFilename);
const writeStream = fs.createWriteStream(filename);
readStream.pipe(decipher).pipe(writeStream);