golang/go · critical

cipher: message authentication failed

Error message

cipher: message authentication failed

What it means

errOpen is the sentinel returned by gcmFallback.Open (GCM decryption) when authentication fails. In the shown region it fires when the ciphertext is shorter than the configured tag size; the same error is returned later when the recomputed GCM authentication tag does not match the tag embedded in the ciphertext, which signals tampering or a key/nonce/additional-data mismatch.

Source

Thrown at src/crypto/cipher/gcm.go:269

	if alias.AnyOverlap(out, additionalData) {
		panic("crypto/cipher: invalid buffer overlap of output and additional data")
	}

	var H, counter, tagMask [gcmBlockSize]byte
	g.cipher.Encrypt(H[:], H[:])
	deriveCounter(&H, &counter, nonce)
	gcmCounterCryptGeneric(g.cipher, tagMask[:], tagMask[:], &counter)

	gcmCounterCryptGeneric(g.cipher, out, plaintext, &counter)

	var tag [gcmTagSize]byte
	gcmAuth(tag[:], &H, &tagMask, out[:len(plaintext)], additionalData)
	copy(out[len(plaintext):], tag[:])

	return ret
}

var errOpen = errors.New("cipher: message authentication failed")

func (g *gcmFallback) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
	if len(nonce) != g.nonceSize {
		panic("crypto/cipher: incorrect nonce length given to GCM")
	}
	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
	}

	ret, out := sliceForAppend(dst, len(ciphertext)-g.tagSize)
	if alias.InexactOverlap(out, ciphertext) {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Verify the full ciphertext including the trailing tag is passed unmodified to Open.
  2. Ensure encrypt and decrypt sides use the exact same key, nonce, and additionalData.
  3. Never reuse a nonce with the same key; generate a fresh random 12-byte nonce per message.
  4. Treat this error as a security event (possible forgery); do not silently retry or strip the tag.
Defensive patterns

Strategy: try-catch

Try / catch

plaintext, err := gcm.Open(nil, nonce, ciphertext, aad)
if err != nil {
    if errors.Is(err, cipher.ErrAuth) /* or the package's auth sentinel */ {
        // Authentication failure: treat as tampering/forgery. Do NOT retry
        // with truncated tags or fall back; log and reject the message.
        return ErrCiphertextRejected
    }
    return err
}

Prevention

When it happens

Trigger: Calling gcm.Open(...) with len(ciphertext) < g.tagSize; or with ciphertext whose trailing tag bytes do not match the tag recomputed from the plaintext, nonce, key, or additionalData.

Common situations: Truncated ciphertext in transit; bit-flips or corruption on the wire; nonce reuse across messages under the same key; decrypting with the wrong key; passing different additionalData than was used at encryption time.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/2a69c5283a3a9c67. Report an issue: GitHub.