FiloSottile / FiloSottile/hpke

ciphertext slice is overwritten in single-use HPKE Open

Open
#1 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
18
Forks
1
PR merge metrics
No merged PRs in 30d

Description

## tl;dr

Single-use HPKE [Open](https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/hpke.go#L232) accepts `enc` and `ciphertext` in a single argument and then creates [two slices](https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/hpke.go#L237) for each, while both referencing the same underlying array.

An [`append`](https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/kem.go#L386) with `enc` slice in [`dhKEMPrivateKey.decap`](https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/kem.go#L377C10-L377C32) (called by [`hpke.NewRecipient`](https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/hpke.go#L162)) appears to be overwriting the underlying array, thus overwriting the `ciphertext` slice and causing `aead.Open` to fail.

## How to reproduce

See [my code on go playground](https://go.dev/play/p/GBusnBxJUX-):

```go
package main

import (
"crypto/ecdh"
"encoding/hex"
"fmt"

"filippo.io/hpke"
)

func main() {
kem, kdf, aead := hpke.DHKEM(ecdh.X25519()), hpke.HKDFSHA256(), hpke.ChaCha20Poly1305()

k, _ := kem.GenerateKey()
pk := k.PublicKey()

// Single-use Open: ciphersuite overwrite!
encANDcipher, _ := hpke.Seal(pk, kdf, aead, nil, []byte("hello world"))
pt, err := hpke.Open(k, kdf, aead, nil, encANDcipher)
fmt.Printf("Plaintext: '%s' / err: %s\n", pt, err) // Plaintext: '' / err: chacha20poly1305: message authentication failed

// Root cause is passing slices to hpke.NewRecipient
encANDcipher, _ = hpke.Seal(pk, kdf, aead, nil, []byte("hello world"))
copied := make([]byte, len(encANDcipher))
copy(copied, encANDcipher)

hpke.NewRecipient(encANDcipher[:32], k, kdf, aead, nil)
fmt.Printf(
"Ciphersuit:\n├── Before:\t%s\n└── After:\t%s\n",
hex.EncodeToString(encANDcipher[32:]),
hex.EncodeToString(copied[32:]))
}
```

## Code
Single-use HPKE Open splits `ciphtertext` (concatenation of `enc` and `ciphertext`) into two slices on line 237:

https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/hpke.go#L229-L243

and passes `enc` to [`NewRecipient`](https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/hpke.go#L162), where it is passed to `decap`:

https://github.com/FiloSottile/hpke/blob/8aa8a04dacd2fb6d7c40e16c3d57037d4eb5e659/kem.go#L377-L388

on line 386, the `append` modifies the underlying array where `ciphertext` resides, causing the subsequent `aead.Open` to fail.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.