I'm confused about something that makes AES GCM great. It uses MAC to sign data it encrypts. I also uses nonce.

But lets say I encrypt data in software A. Software A produces a ciphertext and a tag as shown here : https://pycryptodome.readthedocs.io/en/latest/src/cipher/aes.html

But when I want to decrypt the ciphertext in software B, it fails because software B does not know the nonce not the MAC code.

So how does software like TLS and such work ?

  • $\begingroup$ All correct implementations of GCM (for any cipher) use the nonce and tag, which are sometimes called IV and MAC respectively. The Java API, and possibly others, puts the ciphertext and tag in the same buffer but they still both exist,; you just read the documentation to use them, and people working on 'TLS and such' do read the documentation and don't use incorrect implementations. $\endgroup$ Commented Oct 12, 2023 at 3:00
  • $\begingroup$ Usually, the nonce is prepended and the tag is appended to the ciphertext ($nonce\|ciphertext\|tag$) and send as this (after format conversion), this is necessary and meaningful since nonce required at the beginning and tag checked at the end. This is almost same in all libraries, however, the output encoding may differ and may require your care. We don't send binary since it can cause problems on some protocols, usually, base64 is preferred since better byte representation than hex. $\endgroup$
    – kelalaka
    Commented Oct 12, 2023 at 7:09
  • 1
    $\begingroup$ @kelalaka+ I don't know about 'usually'. XMLenc does, but IMLE that isn't much used and XML is instead wrapped or transport-encrypted. TLS1.2 puts only part of the nonce (for GCM and CCM) before the ciphertext (and tag); TLS1.3 puts none of it, using instead the implicit sequence number xored with some key material from the handshake. SSH similarly uses the sequence number for nonce, but appends the tag. CMS/SMIME puts the nonce in the parameters in the AlgorithmIdentifier, and the tag as a separate field in AuthEnvelopedData, neither of them adjacent to the ciphertext. ... $\endgroup$ Commented Oct 13, 2023 at 1:12
  • $\begingroup$ ... TLS and SSH always send binary; CMS can be either binary or PEM, and SMIME similarly either 8bit or base64. $\endgroup$ Commented Oct 13, 2023 at 1:13
  • $\begingroup$ @dave_thompson_085 thanks for sharing you expertise on these. Well, to be honest, my comment was mostly the libraries other then the TLS. $\endgroup$
    – kelalaka
    Commented Oct 13, 2023 at 7:00

1 Answer 1


It usually works because the treatment of the nonce (sometimes just called the IV) and the authentication tag is contained in the protocol description, see for instance this Q/A for TLS 1.2. The configuration options for a scheme are normally defined and the protocol needs to describe how they are fulfilled.

Sometimes there are defaults, hopefully explicitly defined for the scheme. If not then the wrinkles need to be removed by compatibility testing. It can also be the case that the configuration settings and placement of e.g. the authentication tag are hidden somewhere in a referenced RFC such as RFC 5116. Obviously the data to be authenticated and/or encrypted does need to be defined.

Quite a lot of proprietary implementations forget to define a protocol, and in that case it may be very tricky to find out how the scheme is used. This problem often occurs on StackOverflow where countless hours are spent trying to get code replicated in different languages. This is particularly tricky for encryption as a single wrong bit will lead to decryption errors.

Note that GCM is described in NIST SP 38D and the test vectors are available (CAVP) and generally the GCM implementations themselves can be configured for any protocol, although NIST has indicated that support for nonces other than 12 bytes may be missing. It might be that some shorter authentication tag sizes are also not supported for verification but this is less likely.

Note that there are a few ways of creating a GCM API which may also make it harder to make compatible code:

  • single shot API's where all parameters such as nonce, associated & plaintext / ciphertext & authentication tag need to be supplied at once
  • update / final API's where the (associated) text can be supplied piecemeal
  • streaming API's where the data is usually provided by some kind of input stream or source and/or supplied to an output stream or sink

And then there are the ways of handling the authentication tag: as part of the ciphertext or separately. The nonce is generally part of initialization and the handling is up to the user.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.