golang/go · critical
cipher: message authentication failed
Error message
cipher: message authentication failed
What it means
Returned by GCM.Open (errOpen) when authentication fails: the GCM tag computed over ciphertext+associated-data does not match the appended tag, or when the ciphertext is shorter than tagSize / exceeds the GCM maximum. This is the canonical AEAD authentication failure: either the key, nonce, ciphertext, or associated data differs from what was used to Seal.
Source
Thrown at src/crypto/internal/fips140/aes/gcm/gcm.go:91
panic("crypto/cipher: incorrect GCM nonce size")
}
if uint64(len(plaintext)) > uint64((1<<32)-2)*gcmBlockSize {
panic("crypto/cipher: message too large for GCM")
}
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
if alias.InexactOverlap(out, plaintext) {
panic("crypto/cipher: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, data) {
panic("crypto/cipher: invalid buffer overlap of output and additional data")
}
seal(out, g, nonce, plaintext, data)
return ret
}
var errOpen = errors.New("cipher: message authentication failed")
func (g *GCM) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize {
panic("crypto/cipher: incorrect nonce length given to GCM")
}
// Sanity check to prevent the authentication from always succeeding if an
// implementation leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize {
panic("crypto/cipher: incorrect GCM tag size")
}
if len(ciphertext) < g.tagSize {
return nil, errOpen
}
if uint64(len(ciphertext)) > uint64((1<<32)-2)*gcmBlockSize+uint64(g.tagSize) {
return nil, errOpen
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Verify the key, nonce, and additional data byte-for-byte match what Seal used; log nonce and AAD lengths to spot mismatches.
- Ensure the ciphertext includes the trailing tag and was not truncated in transit.
- If key rotation is the cause, try decryption against recent keys in order.
- Treat errOpen as unauthenticated and never disclose which field was wrong (constant-time).
Example fix
// before
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
if err != nil { panic(err) } // err == errOpen
// after
plaintext, err := aead.Open(nil, nonce, ciphertext, aad) // pass the SAME aad used in Seal
if err != nil {
return errors.New("decryption failed: authentication tag mismatch")
} Defensive patterns
Strategy: try-catch
Validate before calling
func looksAuthentic(ciphertext []byte, tagSize int) bool {
return len(ciphertext) >= tagSize
}
// stronger: verify lengths and AAD before calling Open, but the tag itself
// can only be verified by Open — there is no pre-check that substitutes for it. Type guard
// n/a
Try / catch
plaintext, err := aead.Open(nil, nonce, ciphertext, aad)
if err != nil {
// err is errOpen: treat as unauthenticated; do not partially use plaintext
return errors.New("decryption failed")
} Prevention
- Never reuse a nonce with the same key.
- Log nonce + AAD lengths (not values) to spot mismatches in audits.
- Use a key hierarchy (HKDF) and rotate keys.
- Treat errOpen as a security event, not a transient retry.
- Do not disclose which field failed authentication.
When it happens
Trigger: Calling aead.Open(dst, nonce, ciphertext, data) with the wrong key, wrong/rotated nonce, tampered ciphertext, reordered/truncated associated data, or ciphertext shorter than g.tagSize.
Common situations: Nonce reuse or rotation out of sync; key rotation where the decryptor still holds the old key; network truncation dropping the tag or trailing bytes; associated-data mismatch (e.g. AAD field changed between seal and open); ciphertext from a different AEAD/algorithm fed into GCM.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- cipher: incorrect tag size given to GCM
- cipher: the nonce can't have zero length
- cipher: NewGCM requires 128-bit block cipher
- crypto/cipher: incorrect nonce length given to SetNoncePrefi
- crypto/cipher: SetNoncePrefixAndMask called twice or after f
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/49def54f77eabcb8.
Report an issue: GitHub.