Skip to content
This repository was archived by the owner on Jul 15, 2018. It is now read-only.

Implementation of xchacha20poly1035 aead #98

Merged
merged 5 commits into from
May 23, 2018

Conversation

zmanian
Copy link
Contributor

@zmanian zmanian commented May 13, 2018

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

@zmanian zmanian requested review from ebuchman and jaekwon as code owners May 13, 2018 15:30
@zmanian
Copy link
Contributor Author

zmanian commented May 22, 2018

Libsodium test vector passes. I think this is good to merge

@zmanian zmanian requested a review from liamsi May 22, 2018 03:49
@zmanian zmanian changed the title (WIP)Initial implementation of xchacha20poly1035 aead Implementation of xchacha20poly1035 aead May 22, 2018
Copy link
Contributor

@ebuchman ebuchman left a 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!

@@ -0,0 +1,237 @@
package xchacha20poly1305
Copy link
Contributor

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

@ebuchman
Copy link
Contributor

Oh I see, we're just copying the hChaCha20Generic function from https://github.com/aead/chacha20/blob/master/chacha/chacha_generic.go


chacha20poly1305, _ := chacha20poly1305.New(subKey[:])

copy(subNonce[4:], nonce[16:])
Copy link
Contributor

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 ?

Copy link
Contributor Author

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.


copy(subNonce[4:], nonce[16:])

return chacha20poly1305.Seal(dst, subNonce[:], plaintext, additionalData)
Copy link
Contributor

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 ?

Copy link
Contributor

@ebuchman ebuchman May 23, 2018

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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is correct

@zmanian
Copy link
Contributor Author

zmanian commented May 23, 2018

So xchacha20 was covered in Matt Green's audit of libsodium last years.
https://www.privateinternetaccess.com/blog/2017/08/libsodium-v1-0-12-and-v1-0-13-security-assessment/

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

func (c *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
if len(nonce) != NonceSize {
panic("xchacha20poly1305: bad nonce length passed to Open")
}
Copy link
Contributor

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 ?

@ebuchman
Copy link
Contributor

Awesome work zaki

@ebuchman
Copy link
Contributor

Two outstanding questions for my understanding:

  • how does chacha20poly1305 compare to AES-GCD ? I understand it's faster on non-specialized hardware, is there anything else significant?
  • how will TLS1.3 deal with the nonce bound ? Or do they assume 2^96 is enough ?!

@ebuchman
Copy link
Contributor

Oh, from https://tools.ietf.org/html/draft-paragon-paseto-rfc-00#section-7:

  XChaCha20-Poly1305 is a variant of the ChaCha20-Poly1305 AEAD
   construction as defined in [RFC7539] that uses a 192-bit nonce
   instead of a 64-bit nonce.

This should say "instead of a 96-bit nonce", right ?

ie. from https://tools.ietf.org/html/rfc7539#section-2.3:


   The ChaCha block function transforms a ChaCha state by running
   multiple quarter rounds.

   The inputs to ChaCha20 are:

   o  A 256-bit key, treated as a concatenation of eight 32-bit little-
      endian integers.

   o  A 96-bit nonce, treated as a concatenation of three 32-bit little-
      endian integers.

   o  A 32-bit block count parameter, treated as a 32-bit little-endian
      integer.

@ebuchman
Copy link
Contributor

Oh, is this the same thing as this PR? https://github.com/jedisct1/xsecretbox

@zmanian
Copy link
Contributor Author

zmanian commented May 23, 2018

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

@ebuchman ebuchman merged commit f0b1f6e into tendermint:develop May 23, 2018
@zmanian zmanian deleted the xChaChaPoly1035 branch May 24, 2018 03:12
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants