reactjsencryptionutf-8aes-gcmnode-forge

How to deal with the Error: "Authentication tag does not match tag length


I'm trying to implement encryption and decryption method on messages for a web based chat app. In this chat I'm encrypting the messages in my frontend and then storing these messages to my database. Now I need to fetch these encrypted messages from the database and decrypt them. But I'm Getting this error: Error decrypting data: Error: Authentication tag does not match tag length., This is the code I am using to encrypt and decrypt the data.

import forge from 'node-forge';

// Convert hex to ByteStringBuffer
const hexToBytes = (hex) => forge.util.createBuffer(forge.util.hexToBytes(hex));

// Function to encrypt data with a session key in hex format
export const encryptDataWithSessionKey = (data, sessionKeyHex) => {
  console.log('data during encryption: ', data);

  
  try {
    const sessionKey = hexToBytes(sessionKeyHex);
    
    // Generate a random IV (Initialization Vector)
    const iv = forge.random.getBytesSync(12); // 96 bits IV for GCM
    console.log('iv during encryption: ', iv);

    const dataBytes = forge.util.encodeUtf8(data);
    
    // Encrypt the data using the session key and IV
    const cipher = forge.cipher.createCipher('AES-GCM', sessionKey);
    console.log('cipher during encryption: ', cipher);
    cipher.start({ iv, tagLength: 128 });
    cipher.update(forge.util.createBuffer(dataBytes));
    cipher.finish();

    
    // Get the encrypted bytes along with the IV
    const encrypted = cipher.output.getBytes();
    console.log('encrypted during encryption: ', encrypted, encrypted.length);

    // Convert the encrypted bytes and IV to a Base64-encoded string
    const encryptedBase64 = forge.util.encode64(iv + encrypted);
    console.log('encryptedBase64 during encryption: ', encryptedBase64, encryptedBase64.length);
    
    return encryptedBase64;
  } catch (error) {
    console.error('Error encrypting data:', error);
    throw error;
  }
};

// Function to decrypt data with a session key in hex format
export const decryptDataWithSessionKey = (encryptedData, sessionKeyHex) => {
  console.log('encryptedData during decryption: ', encryptedData);

  try {
    const sessionKey = hexToBytes(sessionKeyHex);

    const encryptedBytesWithIV = forge.util.decode64(encryptedData);

    // Extract the IV and encrypted data
    const iv = encryptedBytesWithIV.slice(0, 12);
    console.log('iv during decryption: ', iv);

    const encryptedBytes = encryptedBytesWithIV.slice(12);
    console.log('encryptedBytes during decryption: ', encryptedBytes, encryptedBytes.length);
    
    // Decrypt the data using the session key and IV
    const decipher = forge.cipher.createDecipher('AES-GCM', sessionKey);
    console.log('decipher during decryption: ', decipher);

    console.log(1);
    decipher.start({ iv, tagLength: 128 });
    decipher.update(forge.util.createBuffer(encryptedBytes));
    console.log(2);
    decipher.finish();
    console.log(3);

    // Get the decrypted bytes
    const decrypted = decipher.output.getBytes();
    

    // Convert the decrypted bytes to a UTF-8 string
    const decryptedData = forge.util.decodeUtf8(decrypted);

    return decryptedData;
  } catch (error) {
    console.error('Error decrypting data:', error);
    throw error;
  }
};

I have checked all the values which are being passed in here like data, sessionKeyHex and encryptedData. I even have checked all the internal values like iv and cipherText and encrypted all are the same during encryption and decryption. Even I have defined tagLength on my own both times during encryption and decryption to make sure that tagLength does not change. I am just confirming that all the data is correctly passing in all manner.

Now the error I'm talking about is coming during this line decipher.start({ iv, tagLength: 128 });. In console I am getting output 1 but I am not getting the values after that line. Instead I am getting the error Error decrypting data: Error: Authentication tag does not match tag length..

I know that this authentication tag automatically added to encrypted message after running cipher.finish() but I don't think that in my code is attaching that's why I am getting the error.

So what am I performing wrong in this code due to which I am getting this error. Any helps pls


Solution

  • In your code, the authentication tag is not taken into account. To fix this, the following changes are required (s. also the GCM example in the documentation):

    const encryptedBase64 = forge.util.encode64(iv + encrypted + cipher.mode.tag.data); // Fix 1: append tag
    
    const encryptedBytesWithIVandTag = forge.util.decode64(encryptedData);
    const iv = encryptedBytesWithIVandTag.slice(0, 12);
    const encryptedBytes = encryptedBytesWithIVandTag.slice(12, -16); // Fix 2: consider tag
    const tag = encryptedBytesWithIVandTag.slice(-16); // Fix 3: separate tag
    ...
    decipher.start({ iv, tag: tag }); // Fix 4: specify tag