-
Notifications
You must be signed in to change notification settings - Fork 32
Implementation of xchacha20poly1035 aead #98
Conversation
Libsodium test vector passes. I think this is good to merge |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Want to make sure I understand.
There is already an impl of chacha20poly1305 in x/crypto: golang.org/x/crypto/chacha20poly1305
What we're doing here is implementing xchacha20poly1305 - the x indicating that we use hchacha20 to produce a longer nonce, which allows us to safely reuse the same key for more messages.
Is that all basically right ?
What do TLS implementations do about this nonce problem ? It looks like it only uses a 12-byte nonce (https://tools.ietf.org/html/rfc7905)
Also, can you give me a quick summary of how xchacha20poly1305 differs from AES-GCD ?
As for this code - looks like it's taken from https://github.com/aead/chacha20/blob/master/chacha/chacha_generic.go
Can you clarify how this differs from that, if at all ?S
Thanks!
xchacha20poly1035/xchachapoly.go
Outdated
@@ -0,0 +1,237 @@ | |||
package xchacha20poly1305 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dir name should be 1305 - currently 1035
Oh I see, we're just copying the |
xchacha20poly1035/xchachapoly.go
Outdated
|
||
chacha20poly1305, _ := chacha20poly1305.New(subKey[:]) | ||
|
||
copy(subNonce[4:], nonce[16:]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subnonce starts with 4 0s ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The algorithm for XChaCha20-Poly1305 is as follows:
1. Calculate a subkey from the first 16 bytes of the nonce and the
key, using HChaCha20 (Section 7.2).
2. Use the subkey and remaining 8 bytes of the nonce (prefixed with
4 NUL bytes) with AEAD_CHACHA20_POLY1305 from [RFC7539] as
normal.
xchacha20poly1035/xchachapoly.go
Outdated
|
||
copy(subNonce[4:], nonce[16:]) | ||
|
||
return chacha20poly1305.Seal(dst, subNonce[:], plaintext, additionalData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so chacha only accepts a 12 byte nonce. but we have a 24 byte nonce.
so we take the first 16 bytes, and use it as a nonce with our encryption key through Hchacha20 to get a new 32-byte encryption key (subKey
).
Then we can encrypt using our new key (subKey
) and a 12 byte nonce containing the final 8 bytes from the original nonce.
Is that all right?
And the reason this is good is because originally, we were limited to to 2^96 msgs with a given key due to the 12-byte nonce. but now, even though the nonce used in chacha20poly is still actually only 8 bytes, the other 16 bytes were used to alter the key, so we get a full 2^192 msgs per original key (ie 2^64 msgs per subkey, and 2^128 subkeys per original key).
Is that right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for hchacha20, is the only guarantee we need from it here collision resistance ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes this is correct
So xchacha20 was covered in Matt Green's audit of libsodium last years. The basic idea is you derive a subkey from original nonce and original key using the hChaCha PRF. In keeping with the goal of this library to be a thin wrapper around the standard library, I only extracted the hChaCha implementation from Andrew's implementation and used the standard library implementation of chacha20poly1035 to implement the encryption and decryption |
xchacha20poly1035/xchachapoly.go
Outdated
func (c *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { | ||
if len(nonce) != NonceSize { | ||
panic("xchacha20poly1305: bad nonce length passed to Open") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we add the
if len(ciphertext) < 16 {
return nil, errOpen
}
check ?
Awesome work zaki |
Two outstanding questions for my understanding:
|
Oh, from https://tools.ietf.org/html/draft-paragon-paseto-rfc-00#section-7:
This should say "instead of a 96-bit nonce", right ? ie. from https://tools.ietf.org/html/rfc7539#section-2.3:
|
Oh, is this the same thing as this PR? https://github.com/jedisct1/xsecretbox |
There reason for that is there was an earlier version chacha20poly1305 that used a 64 bit nonce, the version the ietf standardized for TLS has a 96 bit nonce. Frank's xsecretbox is functionally very similar to this pull request but mine uses the standard library's implementation of chacha20poly1035 and Frank is using Dennis's |
I want to add test vectors from libsodium for hChaCha and this is a good reference for exactly how it works.
https://tools.ietf.org/html/draft-paragon-paseto-rfc-00#section-7.2
This is a prerequisite for resolving tendermint/tendermint#1124