digitalbazaar / forge

A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps

Home Page:https://digitalbazaar.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

node-forge AES-GCM fails to decrypt from .NET core 5.0

RobertBRenfro opened this issue · comments

Greetings,
I'm currently developing a POC where an encrypted message from .net core 5.0 is sent to angular where node-forge is used to decrypt the message. node-forge always fails to decrypt the message. I've placed breakpoints in the node-forge and angular code to gather some data, which is shown below. I'm also including the relevant angular and .net code. Any help or insight you can provide will be greatly appreciated.

.net sends
iv: a8vtZQXrB7ahkpCO
tag: 9aWu5mYiVpOK6oNHrV9+LQ==
payload: ykUd/Xc=

angular receives
iv: a8vtZQXrB7ahkpCO
tag: 9aWu5mYiVpOK6oNHrV9+LQ==
payload: ykUd/Xc=

node-forge decodes (forge.util.decode64)
iv: kËíe\u0005ë\u0007¶¡�
tag: õ¥®æf"V��ê�G­_~-
payload: ÊE\u001dýw

node-forge (start decipher)
iv: kËíe\u0005ë\u0007¶¡��
tag: õ¥®æf"V��ê�G­_~- (this._tag)
this._j0: [1808526693,99289014,-1584230258,1,]

node-forge (finish) computed tag does not match. payload is not decrypted.
this.tag.bytes(): 5w]!\u00070�º·TE°¬G£ð
this.tag: õ¥®æf"V��ê�G­~-

angular code

    decryptUsingAES256(decString) {
        var data = decString.split("|");
        var iv = forge.util.decode64(data[0]);
        var tag = forge.util.decode64(data[1]);
        var decodedData = forge.util.decode64(data[2]);
        decodedData = forge.util.createBuffer(decodedData);
    
        var decipher = forge.cipher.createDecipher("AES-GCM", forge.util.createBuffer(this.key));
        decipher.start({
          iv: iv,
          tagLength: 128, 
          tag: tag
        });
        decipher.update(decodedData);
        const result = decipher.finish(); 
        var response = decipher.output.data;
        if(result){
            response = decipher.output.data;
        }
        return response;
    }

.net code

       private static string EncryptStream(IConfiguration configuration, string originalBody)
        {
            string outPutText = originalBody;
            try
            {
                // Get bytes of plaintext string
                byte[] plainBytes = Encoding.UTF8.GetBytes(outPutText);

                // Get parameter sizes
                int nonceSize = AesGcm.NonceByteSizes.MaxSize;
                int tagSize = AesGcm.TagByteSizes.MaxSize;
                int cipherSize = plainBytes.Length;

                // We write everything into one big array for easier encoding
                int encryptedDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
                Span<byte> encryptedData = encryptedDataLength < 1024
                                         ? stackalloc byte[encryptedDataLength]
                                         : new byte[encryptedDataLength].AsSpan();

                // Copy parameters
                BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(0, 4), nonceSize);
                BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
                var iv = encryptedData.Slice(4, nonceSize);
                var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
                var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);

                // Generate secure nonce
                RandomNumberGenerator.Fill(iv);

                // Encrypt
                using var aes = new AesGcm(Encoding.UTF8.GetBytes(configuration.GetSection("HPSSettings:AESEncryptKey").Value));
                aes.Encrypt(iv, plainBytes.AsSpan(), cipherBytes, tag);

                // Encode for transmission
                outPutText = $@"{Convert.ToBase64String(iv)}|{Convert.ToBase64String(tag)}|{Convert.ToBase64String(cipherBytes)}";
            }
            catch (CryptographicException e)
            {
                Serilog.Log.Error("A Cryptographic error occurred: {0}", e.Message);
            }

            return outPutText;
        }
    }

I found the issue! AES-GCM is now working end to end. The issue was that .net was injecting the key in the wrong format (ut8). the correct format is iso-8859-1.