{"record":{"id":"e73c0da5f185e9e9","repo":"golang/go","slug":"crypto-cipher-incorrect-nonce-length-given-to-set","errorCode":null,"errorMessage":"crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask","messagePattern":"crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/aes/gcm/gcm_nonces.go","lineNumber":231,"sourceCode":"\tg      GCM\n\tready  bool\n\tprefix uint32\n\tmask   uint64\n\tnext   uint64\n}\n\n// SetNoncePrefixAndMask sets the fixed prefix and XOR mask for the nonces used\n// in Seal. It must be called before the first call to Seal.\n//\n// The first 32 bits of nonce are used as the fixed prefix, and the last 64 bits\n// are used as the XOR mask.\n//\n// Note that Seal expects the nonce to be already XOR'd with the mask. The mask\n// is provided here only to allow Seal to enforce that the counter is strictly\n// increasing.\nfunc (g *GCMWithXORCounterNonce) SetNoncePrefixAndMask(nonce []byte) error {\n\tif len(nonce) != gcmStandardNonceSize {\n\t\treturn errors.New(\"crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask\")\n\t}\n\tif g.ready {\n\t\treturn errors.New(\"crypto/cipher: SetNoncePrefixAndMask called twice or after first Seal\")\n\t}\n\tg.prefix = byteorder.BEUint32(nonce[:4])\n\tg.mask = byteorder.BEUint64(nonce[4:])\n\tg.ready = true\n\treturn nil\n}\n\nfunc (g *GCMWithXORCounterNonce) NonceSize() int { return gcmStandardNonceSize }\n\nfunc (g *GCMWithXORCounterNonce) Overhead() int { return gcmTagSize }\n\n// Seal implements the [cipher.AEAD] interface, checking that the nonce prefix\n// is stable and that the counter is strictly increasing.\n//\n// It is not safe for concurrent use.","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/aes/gcm/gcm_nonces.go#L213-L249","documentation":"Returned by GCMWithXORCounterNonce.SetNoncePrefixAndMask (the XOR-counter nonce variant used by QUIC) when the supplied nonce is not exactly gcmStandardNonceSize (12) bytes. The first 4 bytes are the fixed prefix and the last 8 bytes are the XOR mask, so a 12-byte input is mandatory.","triggerScenarios":"Calling g.SetNoncePrefixAndMask(iv) with len(iv) != 12, or indirectly via NewGCMForQUIC(cipher, iv) with a wrong-length iv.","commonSituations":"Passing a QUIC connection ID-derived IV that was not padded/truncated to 12 bytes; passing a 16-byte AES-GCM IV by mistake; config-derived IV whose length varies.","solutions":["Ensure the IV is exactly 12 bytes (gcmStandardNonceSize).","Prefer NewGCMForQUIC(cipher, iv) and validate iv length at the call site.","If the source material is shorter/longer, derive a 12-byte value via HKDF rather than padding naively."],"exampleFix":"// before\ng.SetNoncePrefixAndMask(connID) // connID may be 8 or 20 bytes\n// after\niv := make([]byte, 12)\nhkdf.Expand(h, secret, []byte(\"quic iv\")).Read(iv)\ng.SetNoncePrefixAndMask(iv)","handlingStrategy":"validation","validationCode":"func validQUICNonce(iv []byte) bool { return len(iv) == 12 }\n\nif !validQUICNonce(iv) { return errors.New(\"QUIC IV must be 12 bytes\") }\ng, err := gcm.NewGCMForQUIC(block, iv)","typeGuard":"// n/a","tryCatchPattern":"if err := g.SetNoncePrefixAndMask(iv); err != nil {\n    return fmt.Errorf(\"set nonce prefix: %w\", err)\n}","preventionTips":["Derive the 12-byte QUIC IV via HKDF-Expand from the connection secret.","Validate IV length at the QUIC handshake boundary.","Do not pass raw connection IDs as IVs."],"tags":["crypto","aes","gcm","quic","cipher","fips","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}