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

XChaCha20 Inconsistencies #811

Open
Michael-Coveware opened this issue May 31, 2024 · 0 comments
Open

XChaCha20 Inconsistencies #811

Michael-Coveware opened this issue May 31, 2024 · 0 comments

Comments

@Michael-Coveware
Copy link

The implementations for XChaCha20 and its documentation is all over the place when it comes to Draft 02 vs Draft 03. There is a very minor, but critical difference between the two revisions... the counter value used (0 vs. 1 respectively).

The documentation and code comments for XChaCha20 currently link to Draft 03.

"8 bytes (default)", "The original ChaCha20 designed by Bernstein.", "No limitations", "Max 200 000 messages"
"12 bytes", "The TLS ChaCha20 as defined in `RFC7539`_.", "256 GB", "Max 13 billions messages"
"24 bytes", "XChaCha20, still in `draft stage <https://tools.ietf.org/html/draft-arciszewski-xchacha-03>`_.", "256 GB", "No limitations"

However, when using XChaCha20, the ChaCha20 class actually internally implements Draft 02 (despite the comment referencing Draft 03). It does not increment the counter to 1 when using the ChaCha20 stream.

# XChaCha20 requires a key derivation with HChaCha20
# See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03
if len(nonce) == 24:
key = _HChaCha20(key, nonce[:16])
nonce = b'\x00' * 4 + nonce[16:]
self._name = "XChaCha20"
else:
self._name = "ChaCha20"
nonce = self.nonce

The unit test vectors even refer to Draft 02 as well.

However, the XChaCha20-Poly1305 implementation in the class ChaCha20_Poly1305 does increment the counter, as per Draft 03.

self._authenticator = Poly1305.new(key=key, nonce=nonce, cipher=ChaCha20)
self._cipher = ChaCha20.new(key=key, nonce=nonce)
self._cipher.seek(64) # Block counter starts at 1

As does this unit test manually?

cipher = ChaCha20.new(key=key, nonce=iv)
cipher.seek(64) # Counter = 1
ct_test = cipher.encrypt(pt)

It appears it is up to the user of ChaCha20 to increment the counter themselves in order to adhere to Draft 03. This can be confusing when using the class and its output does not match that of other libraries.

I would make a PR, but I'm unsure the direction the maintainers would wish to take:

  1. Change all implementations to adhere to Draft 03, and increment the counter internally (inside ChaCha20)
  2. Update the documentation to state the base behavior is Draft 02 (updating the link), and how to adhere to Draft 03 by incrementing the counter manually

Option 1 would possibly break user's code, so I would believe Option 2 to be better. However, the unit tests would need updated as well, as they are lying.

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

1 participant