gofiber/fiber · error

failed to decrypt ciphertext

Error message

failed to decrypt ciphertext: %w

What it means

Returned by DecryptCookie when gcm.Open fails — the GCM authentication tag did not verify. This is the canonical 'wrong key, wrong cookie name, or tampered ciphertext' signal. The wrapped error is crypto/cipher's 'cipher: message authentication failed'.

Solutions

  1. Confirm the same key that encrypted the cookie is being used to decrypt.
  2. Confirm the cookie name passed to DecryptCookie matches the one passed to EncryptCookie (it is GCM additional data).
  3. Ensure both sides use cipher.NewGCMWithRandomNonce (this middleware's nonce layout prepends the random nonce).
  4. On key rotation, invalidate old cookies and force re-issue rather than attempting decrypt.

Example fix

// before: name mismatch breaks AAD
plaintext, _ := encryptcookie.DecryptCookie("session", value, key)
// after
plaintext, err := encryptcookie.DecryptCookie("sess", value, key)
if err != nil {
    c.ClearCookie("sess")
    return c.Redirect("/login")
}
Defensive patterns

Strategy: try-catch

Try / catch

plain, err := encryptcookie.DecryptCookie(name, value, key)
if err != nil {
    // GCM auth failed: wrong key, wrong name, or tampered value
    c.ClearCookie(name)
    return c.Redirect("/login")
}

Prevention

When it happens

Trigger: DecryptCookie(name, value, key) where the AES-GCM tag fails to verify: the key differs from the one used to encrypt, the cookie name (used as additional data) changed, the ciphertext/nonce bytes were modified, or the value was produced by a different GCM variant (NewGCM with explicit nonce vs NewGCMWithRandomNonce).

Common situations: Rotating the encryption key without invalidating sessions, renaming the cookie (the name is bound into the AAD), swapping EncryptCookie for a different GCM implementation, clients tampering with cookies, or copying a cookie value between environments with different keys.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/fb6b8c50b2cd5e54. Report an issue: GitHub.

Appendix: source

Thrown at middleware/encryptcookie/utils.go:89

	}

	block, err := aes.NewCipher(keyDecoded)
	if err != nil {
		return "", fmt.Errorf("failed to create AES cipher: %w", err)
	}

	gcm, err := cipher.NewGCMWithRandomNonce(block)
	if err != nil {
		return "", fmt.Errorf("failed to create GCM mode: %w", err)
	}

	if len(enc) < gcm.NonceSize()+gcm.Overhead() {
		return "", ErrInvalidEncryptedValue
	}

	plaintext, err := gcm.Open(nil, nil, enc, []byte(name))
	if err != nil {
		return "", fmt.Errorf("failed to decrypt ciphertext: %w", err)
	}

	return string(plaintext), nil
}

// GenerateKey returns a random string of 16, 24, or 32 bytes.
// The length of the key determines the AES encryption algorithm used:
// 16 bytes for AES-128, 24 bytes for AES-192, and 32 bytes for AES-256-GCM.
func GenerateKey(length int) string {
	if length != 16 && length != 24 && length != 32 {
		panic(ErrInvalidKeyLength)
	}

	key := make([]byte, length)

	if _, err := rand.Read(key); err != nil {
		panic(err)
	}

View on GitHub (pinned to a105acad6c)