{"record":{"id":"cd60af36fc9f8684","repo":"golang/go","slug":"cipher-incorrect-tag-size-given-to-gcm-cd60af","errorCode":null,"errorMessage":"cipher: incorrect tag size given to GCM","messagePattern":"cipher: incorrect tag size given to GCM","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/aes/gcm/gcm.go","lineNumber":33,"sourceCode":"type GCM struct {\n\tcipher    aes.Block\n\tnonceSize int\n\ttagSize   int\n\tgcmPlatformData\n}\n\nfunc New(cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {\n\t// This function is outlined to let the allocation happen on the parent stack.\n\treturn newGCM(&GCM{}, cipher, nonceSize, tagSize)\n}\n\n// newGCM is marked go:noinline to avoid it inlining into New, and making New\n// too complex to inline itself.\n//\n//go:noinline\nfunc newGCM(g *GCM, cipher *aes.Block, nonceSize, tagSize int) (*GCM, error) {\n\tif tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {\n\t\treturn nil, errors.New(\"cipher: incorrect tag size given to GCM\")\n\t}\n\tif nonceSize <= 0 {\n\t\treturn nil, errors.New(\"cipher: the nonce can't have zero length\")\n\t}\n\tif cipher.BlockSize() != gcmBlockSize {\n\t\treturn nil, errors.New(\"cipher: NewGCM requires 128-bit block cipher\")\n\t}\n\tg.cipher = *cipher\n\tg.nonceSize = nonceSize\n\tg.tagSize = tagSize\n\tinitGCM(g)\n\treturn g, nil\n}\n\nconst (\n\tgcmBlockSize         = 16\n\tgcmTagSize           = 16\n\tgcmMinimumTagSize    = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/aes/gcm/gcm.go#L15-L51","documentation":"Returned by gcm.New (the FIPS-140 AES-GCM constructor) when tagSize is outside [gcmMinimumTagSize, gcmBlockSize] = [12, 16]. NIST SP 800-38D requires tags of at least 12 bytes, and GCM's tag can be at most the 16-byte block size. This surfaces through cipher.NewGCMWithNonceSize/cipher.NewGCMWithTagSize in crypto/cipher.","triggerScenarios":"Calling cipher.NewGCM(block, cipher.WithTagSize(n)) or gcm.New(block, nonceSize, tagSize) with tagSize < 12 or > 16.","commonSituations":"Passing tagSize=0 (default int) by mistake; computing tag size from a config value that can be 8 or 32; copying a non-GCM tag length from another AEAD (e.g. Poly1305's 16 is fine, but ChaCha's defaults misremembered as 8).","solutions":["Use tagSize in {12,13,14,15,16}; prefer the default 16 unless you have a protocol constraint.","If omitted, omit the option entirely so the default gcmTagSize (16) applies.","Validate user-supplied tag size against [12,16] before constructing the AEAD."],"exampleFix":"// before\naead, err := cipher.NewGCM(block, cipher.WithTagSize(8))\n// after\naead, err := cipher.NewGCM(block) // default 16-byte tag\n// or explicit:\naead, err := cipher.NewGCM(block, cipher.WithTagSize(16))","handlingStrategy":"validation","validationCode":"func validGCMTagSize(n int) bool { return n >= 12 && n <= 16 }\n\n// usage\nif !validGCMTagSize(tagSize) { return errors.New(\"tag size must be 12..16\") }\naead, err := cipher.NewGCM(block, cipher.WithTagSize(tagSize))","typeGuard":"// n/a: int parameter; guard with range check.","tryCatchPattern":"aead, err := cipher.NewGCM(block, cipher.WithTagSize(tagSize))\nif err != nil { return fmt.Errorf(\"gcm init: %w\", err) }","preventionTips":["Default to the 16-byte tag; only deviate for a documented protocol constraint.","Validate user-supplied tag sizes against [12,16].","Unit-test the constructor with boundary values."],"tags":["crypto","aes","gcm","cipher","fips","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}