golang/go · error
ciphertext too short
Error message
ciphertext too short
What it means
The package-level convenience Open() expects ciphertext to be the concatenation of the KEM encapsulated key and the AEAD ciphertext. It reads the first encSize bytes (k.KEM().encSize()) as the encapsulated key; if the input is shorter than encSize, there is no encapsulated key to decapsulate and the call fails fast.
Source
Thrown at src/crypto/hpke/hpke.go:227
func (r *Recipient) Open(aad, ciphertext []byte) ([]byte, error) {
if r.aead == nil {
return nil, errors.New("export-only instantiation")
}
plaintext, err := r.aead.Open(nil, r.nextNonce(), ciphertext, aad)
if err != nil {
return nil, err
}
r.seqNum++
return plaintext, nil
}
// Open instantiates a single-use HPKE receiving HPKE context like [NewRecipient],
// and then decrypts the provided ciphertext like [Recipient.Open] (with no aad).
// ciphertext must be the concatenation of the encapsulated key and the actual ciphertext.
func Open(k PrivateKey, kdf KDF, aead AEAD, info, ciphertext []byte) ([]byte, error) {
encSize := k.KEM().encSize()
if len(ciphertext) < encSize {
return nil, errors.New("ciphertext too short")
}
enc, ciphertext := ciphertext[:encSize], ciphertext[encSize:]
r, err := NewRecipient(enc, k, kdf, aead, info)
if err != nil {
return nil, err
}
return r.Open(nil, ciphertext)
}
// Export produces a secret value derived from the shared key between sender and
// recipient. length must be at most 65,535.
func (r *Recipient) Export(exporterContext string, length int) ([]byte, error) {
if length < 0 || length > 0xFFFF {
return nil, errors.New("invalid length")
}
return r.export(exporterContext, uint16(length))
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Pass the full enc||ciphertext blob exactly as returned by hpke.Seal.
- Ensure sender and recipient use the same KEM so encSize matches.
- Check len(ciphertext) >= k.KEM().encSize() before calling Open and surface a clearer framing error if not.
Example fix
// before
blob := []byte{} // accidentally stripped
pt, err := hpke.Open(k, kdf, aead, info, blob) // "ciphertext too short"
// after
// blob is enc||ct straight from hpke.Seal
pt, err := hpke.Open(k, kdf, aead, info, blob) Defensive patterns
Strategy: validation
Validate before calling
func openChecked(k hpke.PrivateKey, kdf hpke.KDF, aead hpke.AEAD, info, blob []byte) ([]byte, error) {
if min := k.KEM().encSize(); len(blob) < min {
return nil, fmt.Errorf("blob too short: got %d, need >= %d", len(blob), min)
}
return hpke.Open(k, kdf, aead, info, blob)
} Try / catch
pt, err := hpke.Open(k, kdf, aead, info, blob)
if err != nil {
if err.Error() == "ciphertext too short" {
return nil, fmt.Errorf("framing error: need enc(%d)+ct, got %d", k.KEM().encSize(), len(blob))
}
return nil, err
} Prevention
- Always pass the full enc||ct blob from Seal straight through to Open without stripping.
- Length-prefix the blob on the wire and verify the total before calling Open.
- Keep sender and recipient KEM selections in lockstep.
When it happens
Trigger: Calling hpke.Open(k, kdf, aead, info, ciphertext) where len(ciphertext) < k.KEM().encSize(). Happens when the caller passes only the AEAD ciphertext (omitting the enc prefix), passes an empty slice, or uses a different KEM whose encSize is larger than the data.
Common situations: Sender used the convenience Seal() (which returns enc||ct) but receiver strips the enc prefix before calling Open(); or the framing on the wire truncated the message; or sender/recipient were provisioned with different KEMs.
Related errors
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/941120841a724625.
Report an issue: GitHub.