1

I'm using the BountyCastle.NetCore NuGet library to decrypt an already prepared encrypted message from our servers. I was able to utilize both the Java cryptography libraries (native) and Python (pycrptodome) implementation with success. In general, our servers are preparing the message as this:

enter image description here

The decrypt strategy is:

  • Prepare the AES-256 secret key by base64 decoding the cryptographyKey.

  • Prepare the cipher text bytes by base64 decoding the message body.

  • Remove Tag from the cipher text.
  • Prepare AAD by copying the first 16 bytes from cipher text.
  • Prepare NONCE (IV) by copying bytes 4 – 16 from AAD.
  • Then decrypt with AES – GCM, tag length = 16 bytes; with the input
    from 1, 3, 4, 5.

Applying the general algorithm based on this example, my implementation looks like this:

Note: I didn't apply the Tag within the code below because it is more of a verification step and I couldn't get past decrypting the message.

public string Decrypt(string cryptoKey, string cypherText)
{
    string sR = string.Empty;
    try
    {
        // Prepare the AES-256 secret key by decoding the cryptographyKey
        var keyBytes = Convert.FromBase64String(cryptoKey);

        // Prepare the Cypher bytes by decoding the cypher text
        var cypherBytes = Convert.FromBase64String(cypherText);

        // <------AAD----->
        // [---][--NONCE--][-----Encrypted Message-----][---TAG---]
        // <-------------------CypherText------------------------->

        // Prepare the AAD - first AAD_LENGTH from cypher
        var aad = new Byte[AAD_LENGTH];
        Array.Copy(cypherBytes, 0, aad, 0, AAD_LENGTH);

        // Prepare NONCE - bytes 4-16 from AAD
        var nonce = new Byte[NONCE_LENGTH];
        Array.Copy(aad, AAD_LENGTH - NONCE_LENGTH, nonce, 0, NONCE_LENGTH);

        // Extract the encrypted message within the body - between AAD and TAG section
        var encryptedMsgSize = cypherBytes.Length - TAG_LENGTH - AAD_LENGTH;
        var encryptedMsg = new Byte[encryptedMsgSize];
        Array.Copy(cypherBytes, AAD_LENGTH, encryptedMsg, 0, encryptedMsgSize);

        GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());
        AeadParameters parameters = new AeadParameters(new KeyParameter(keyBytes), 128, nonce);

        cipher.Init(false, parameters);
        cipher.ProcessAadBytes(cypherBytes, 0, AAD_LENGTH);

        byte[] plainBytes = new byte[cipher.GetOutputSize(encryptedMsg.Length)];
        Int32 retLen = cipher.ProcessBytes(encryptedMsg, 0, encryptedMsg.Length, plainBytes, 0);
        cipher.DoFinal(plainBytes, retLen);

        sR = Encoding.UTF8.GetString(plainBytes).TrimEnd("\r\n\0".ToCharArray());
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Console.WriteLine(ex.StackTrace);
    }

    return sR;
}

Despite trying many different combinations, setting different parameters etc, it always throws an exception on the line:

cipher.DoFinal(plainBytes, retLen);

with "mac check in GCM failed".

Any other suggestions would be welcomed :-)

zinc1oxide
  • 490
  • 3
  • 15

0 Answers0