Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AES GCM Nonce reuse #6

Open
pix opened this issue Jul 17, 2023 · 2 comments
Open

AES GCM Nonce reuse #6

pix opened this issue Jul 17, 2023 · 2 comments

Comments

@pix
Copy link

pix commented Jul 17, 2023

I was trying to understand the underlying crypto when I found this:

// Decrypt will provide a decryption mechanism for an arbitrary bytestream
// func (private *PrivateKey) Decrypt(data []byte) (decrypted []byte, err error) {
	hashed := sha256.Sum256(buf.Bytes())
	buf.Reset()

	block, err := aes.NewCipher(hashed[0:16])
	if err != nil {
		return
	}
	ch, err := cipher.NewGCMWithNonceSize(block, 16)
	if err != nil {
		return
	}
	decrypted, err = ch.Open(nil, hashed[16:], data[33:], nil)
	return
}

The hashed data will be the same given a pair of client/server, therefore the same key will be used with the same nonce more than once.

This StackOverflow post explains the situations: https://crypto.stackexchange.com/questions/26790/how-bad-it-is-using-the-same-iv-twice-with-aes-gcm

Even a single AES-GCM nonce reuse can be catastrophic.

  • A single nonce reuse leaks the xor of plaintexts, so if one plaintext is known the adversary can completely decrypt the other. This is the same as for a two-time pad.
  • In messages up to $\ell$ blocks long, after a single nonce reuse the adversary can narrow the authentication key down to $\ell$ possibilities with polynomial root-finding and thereby forge messages with high success probability $1/\ell$.
  • How? An $\ell$-block message is a polynomial of degree $\ell$ with zero constant term; the authenticator under secret key $r, s$ is $m \mapsto m(r) + s$, where $r$ is reused between messages and $s$ is derived as a secret function of the nonce. Find authenticators $a = m(r) + s$ and $a' = m'(r) + s$ for distinct messages under the same nonce, and only the ${\leq}\ell$ possible roots of the degree-$\ell$ polynomial $m(r) - m'(r) + a' - a$ in $r$ are possible values of the authentication key.

Use 96-bit nonces; if you don't—if, instead, you use smaller or larger nonces—it will be as if you chose nonces randomly, and the number of messages you can safely handle drops dramatically. But you can, of course, pad, say, a 64-bit nonce into 96 bits: what matters is only that the nonces be unique.

If the cost of a >32-bit nonce is prohibitive, you could periodically rekey. For example, if you first establish a long-term key $k$, you can use ${HMAC-SHA256}_k(i)$ as the key during the $i^{\mathit{th}}$ epoch, where each epoch covers four billion messages, and $i$ is encoded into a bit string in some canonical way.

Generating a nonce and appending it before the encrypted data and using this as the nonce should resolve the issue.

@mosajjal
Copy link
Owner

Hi.

thanks for this. I'll take a look and read upon this and will make appropriate changes.

@mosajjal
Copy link
Owner

mosajjal commented Aug 4, 2023

@pix I'd be keen to dig deeper and come up with a proof-of-concept for this. let me add some logging here and there and see if we can get to plaintext with just sniffing the traffic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants