CodeRigor

LESSON

Use authenticated encryption with managed nonces

Open AES-256-GCM records with Go’s random-nonce wrapper, bind associated data and return no plaintext when authentication fails.

When confidentiality is required, use an authenticated-encryption API rather than combining an arbitrary cipher with a checksum. This lesson uses AES-GCM through Go’s nonce-managing wrapper.

The API requires Go 1.24 or later. It generates and prepends the random nonce during Seal and extracts it during Open. The application does not accept a caller nonce, reducing a common misuse surface.

Managed nonce plus authenticated context
start / 3
The standard API generates the nonce and protects plaintext with a tag. Associated data is authenticated alongside the ciphertext but remains unencrypted.
Managed nonce plus authenticated context
The standard API generates the nonce and protects plaintext with a tag. Associated data is authenticated alongside the ciphertext but remains unencrypted.

For this particular wrapper, NonceSize is zero and callers pass nil as the nonce argument. The sealed result includes 12 nonce bytes and 16 tag bytes, so overhead is 28. This does not mean ordinary GCM can reuse a fixed zero nonce.

The exercise supplies key construction and Seal. Complete bounded Open, including AAD and error handling. A changed key, ciphertext, tag or AAD must fail without returning trusted plaintext.

Go
package main
import ("fmt";"crypto/aes";"crypto/cipher")
func main(){
block,_:=aes.NewCipher(make([]byte,32));aead,_:=cipher.NewGCMWithRandomNonce(block);sealed:=aead.Seal(nil,nil,[]byte("record"),[]byte("lab.notes"));plain,err:=aead.Open(nil,nil,sealed,[]byte("lab.notes"));fmt.Println(len(sealed),string(plain),err==nil)
}

The public tests include two published AES-256-GCM decryption vectors from BoringSSL’s test corpus. Their fixed all-zero key/nonce combinations are interoperability fixtures, not application secrets or a repeated encryption strategy.

Application encryption uses secure random key generation and the library’s random nonce. Go documents a per-key maximum of 2^32 messages for this wrapper; a real application must enforce a rotation/usage policy before reaching that bound. This small exercise does not claim to implement a key-management service.

A valid empty plaintext is distinct from authentication failure. Always inspect the error. The wrapper normalizes failed authentication to one error and returns no plaintext bytes.

Failure is not an empty success
start / 3
A valid empty plaintext has no error. A wrong context/tag/key has an error and no accepted plaintext. Never collapse those states.
Failure is not an empty success
A valid empty plaintext has no error. A wrong context/tag/key has an error and no accepted plaintext. Never collapse those states.
Go
package main
import ("fmt";"crypto/aes";"crypto/cipher")
func main(){
block,_:=aes.NewCipher(make([]byte,32));aead,_:=cipher.NewGCMWithRandomNonce(block);sealed:=aead.Seal(nil,nil,nil,nil);plain,err:=aead.Open(nil,nil,sealed,nil);fmt.Println(len(plain),err==nil)
}

Complete Open and test published vectors, empty/exact-limit plaintext, changed AAD, wrong key, a flipped tag and truncated input. Do not expose unauthenticated output.

Next we separate password-storage policy from these ordinary hash/MAC/encryption operations.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Optional expert discussion of how Go cryptography is engineered and tested. It supports the choice of maintained libraries; the course itself supplies the introductory explanations, vectors and complete lab.