3
votes

I'm using BouncyCastle to encrypt data in C#, using the AES256 GCM algorithm. For this I'm using the implementation provided by James Tuley. Below is a snippet of this code:

public byte[] SimpleEncrypt(byte[] secretMessage, byte[] key, byte[] nonSecretPayload = null)
{
    if (key == null || key.Length != KeyBitSize / 8)
        throw new ArgumentException($"Key needs to be {KeyBitSize} bit!", nameof(key));

    if (secretMessage == null || secretMessage.Length == 0)
        throw new ArgumentException("Secret Message Required!", nameof(secretMessage));

    nonSecretPayload = nonSecretPayload ?? new byte[] { };
        
    byte[] nonce = _csprng.RandomBytes(NonceBitSize / 8);

    var cipher = new GcmBlockCipher(new AesFastEngine());
    var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
    cipher.Init(true, parameters);
        
    var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
    int len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
    cipher.DoFinal(cipherText, len);
        
    using (var combinedStream = new MemoryStream())
    {
        using (var binaryWriter = new BinaryWriter(combinedStream))
        {
            binaryWriter.Write(nonSecretPayload);
            binaryWriter.Write(nonce);
            binaryWriter.Write(cipherText);
        }

        return combinedStream.ToArray();
    }
}

I need to get the authentication tag (mentioned in RFC 5084). It mentions that the authentication tag is part of the output:

AES-GCM generates two outputs: a ciphertext and message authentication code (also called an authentication tag).

I don't understand though how to get the authentication tag from this code? Can anyone help me out?

1
At the end of this function, three parts are combined into a byte array (which becomes the return value). Since the nonSecretPayload is a pass-through parameter, and cipherText is one of the outputs according to standards, that leaves us with the nonce. Could it be that in the standard, they're referring to the nonce as an "authentication tag"? - Cee McSharpface
@dlatikay I don't think so: "AES-GCM has four inputs: an AES key, an initialization vector (IV), a plaintext content, and optional additional authenticated data (AAD). AES-GCM generates two outputs: a ciphertext and message authentication code (also called an authentication tag). To have a common set of terms for AES-CCM and AES-GCM, the AES-GCM IV is referred to as a nonce in the remainder of this document.". Thus the IV is an input, the security tag is not an input but an output (or part of it). - Leon Cullens
this hints that the authentication tag might already be a part of the cipherText, which would lead to the question at which offset would it start. If it is not, then an additional cryptographic hash function needs to be called to generate the tag from the ciphertext here Either way let's look into the source code of that BC library. - Cee McSharpface
@LeonCullens As far as I understand, the message authentication code is simply appended to the end of the ciphertext and not intended to be treated differently. You may want to read blog.heckel.xyz/2014/03/01/… - Leonard Brünings

1 Answers

3
votes

Call the GetMac() function of the cipher object to obtain the authentication tag:

...
cipher.DoFinal(cipherText, len);
var auth_tag =  cipher.GetMac();
...

Source: http://www.bouncycastle.org/docs/docs1.5on/org/bouncycastle/crypto/modes/GCMBlockCipher.html "Return the value of the MAC associated with the last stream processed" MAC = "Message Authentication Code"

The documentation of the DoFinal() function states "Finish the operation either appending or verifying the MAC at the end of the data", which seems to confirm the earlier hypothesis that the cipherText will already contain the MAC, too. Using GetMacSize(), you should be able to determine its offset from the end of the cipherText.