{"record":{"id":"6c370f47cb5f47f6","repo":"golang/go","slug":"invalid-encapsulated-key-size","errorCode":null,"errorMessage":"invalid encapsulated key size","messagePattern":"invalid encapsulated key size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/hpke/pq.go","lineNumber":335,"sourceCode":"\nfunc (k *hybridPrivateKey) Bytes() ([]byte, error) {\n\tif k.seed == nil {\n\t\treturn nil, errors.New(\"private key seed not available\")\n\t}\n\treturn k.seed, nil\n}\n\nfunc (k *hybridPrivateKey) PublicKey() PublicKey {\n\treturn &hybridPublicKey{\n\t\tkem: k.kem,\n\t\tt:   k.t.PublicKey(),\n\t\tpq:  k.pq.Encapsulator(),\n\t}\n}\n\nfunc (k *hybridPrivateKey) decap(enc []byte) ([]byte, error) {\n\tif len(enc) != k.kem.pqCiphertextSize+k.kem.curvePointSize {\n\t\treturn nil, errors.New(\"invalid encapsulated key size\")\n\t}\n\tctPQ, ctT := enc[:k.kem.pqCiphertextSize], enc[k.kem.pqCiphertextSize:]\n\tssPQ, err := k.pq.Decapsulate(ctPQ)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar pub *ecdh.PublicKey\n\tfips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.\n\t\tpub, err = k.t.Curve().NewPublicKey(ctT)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar ssT []byte\n\tfips140.WithoutEnforcement(func() {\n\t\tssT, err = k.t.ECDH(pub)\n\t})\n\tif err != nil {","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/hpke/pq.go#L317-L353","documentation":"Raised by hybridPrivateKey.decap when the encapsulated secret enc is not exactly pqCiphertextSize + curvePointSize bytes. HPKE hybrid enc is the concatenation of the ML-KEM ciphertext and the ECDH ephemeral public point; any other length is malformed.","triggerScenarios":"Calling decap (driven by KEM Decap/Open) with enc whose length != kem.pqCiphertextSize + kem.curvePointSize. For X25519: 1088+32=1120; for P-256: 1088+65=1153; for P-384: 1568+97=1665.","commonSituations":"Truncation or corruption of the enc in transit; using a ciphertext generated for a different hybrid suite; buffer slicing bugs that drop the trailing ECDH point or the leading PQ ciphertext; protocol version mismatch where sender and responder use different suites.","solutions":["Ensure the sender and responder use the same hybrid KEM suite so pqCiphertextSize and curvePointSize match.","Validate len(enc) against the suite's expected size before calling Decap.","Re-transmit/derive the encapsulated key if it was truncated or corrupted.","When splitting enc, slice at pqCiphertextSize exactly: ctPQ=enc[:pqCiphertextSize], ctT=enc[pqCiphertextSize:]."],"exampleFix":"// before\nss, err := privKem.decap(enc[:1088]) // missing ECDH point -> wrong size\n\n// after\nss, err := hybridKEM.Decap(enc) // enc is the full 1120-byte (X25519) blob","handlingStrategy":"validation","validationCode":"func validateHybridEnc(kem KEM, enc []byte) error {\n    want := kem.(*hybridKEM).pqCiphertextSize + kem.(*hybridKEM).curvePointSize\n    if len(enc) != want {\n        return fmt.Errorf(\"invalid encapsulated key size: got %d want %d\", len(enc), want)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin sender and responder to the same hybrid suite.","Slice enc exactly at pqCiphertextSize.","Length-check enc before Decap to fail fast."],"tags":["hpke","post-quantum","kem","hybrid","validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}