-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
ChaCha20
API does not allow updating the nonce
#10193
Comments
What sort of performance do you see on current main? We actually had a context reuse system (fixedpool) for ChaCha20Poly1305 but we got rid of it in the latest transition because the rust conversion gave us 20% better performance even without reuse.
|
Slight correction: we still reuse the ctx on openssl3.2.
…On Wed, Jan 17, 2024, 10:32 AM Paul Kehrer ***@***.***> wrote:
What sort of performance do you see on current main? We actually had a
context reuse system (fixedpool) for ChaCha20Poly1305 but we got rid of it
in the latest transition because the rust conversion gave us 20% better
performance even without reuse.On Jan 16, 2024, at 5:10 PM, Jeremy Lainé
***@***.***> wrote:
Hello cryptographistas!
Currently aioquic's QUIC header protection and encryption features use C
code linked against OpenSSL. I am considering porting this to pure Python
using only cryptography. On the whole things work, and a work in progress
is here:
aiortc/aioquic#457
One thing I noticed is that the ChaCha20 class takes the nonce in its
constructor. Unfortunately QUIC uses a nonce which is derived from each
packet's header. This means that when using the CHACHA20_POLY1305_SHA256
cipher suite, for every packet we need to tear down / recreate the ChaCha20
instance which is not cheap.
Would you consider an API which allows updating the nonce? This can be
implemented by calling:
EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, operation)
—Reply to this email directly, view it on GitHub, or unsubscribe.You are
receiving this because you are subscribed to this thread.Message ID:
***@***.***>
—
Reply to this email directly, view it on GitHub
<#10193 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAAGBHJ4VFJBMV4UQNLOGTYO7VJDAVCNFSM6AAAAABB5KGZZ6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOJWGA2TMNJUGM>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
I tried putting together a very crude benchmark to get feel for how much it cost to create a new import time
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
ITERATIONS = 1000000
KEY = bytes(32)
NONCE = bytes(16)
DATA = bytes(64)
start = time.time()
for i in range(ITERATIONS):
r = Cipher(
algorithm=algorithms.ChaCha20(KEY, NONCE),
mode=None,
).encryptor().update(DATA)
elapsed = time.time() - start
print(f"{ITERATIONS} iterations with teardown in {elapsed:.1f} s")
start = time.time()
encryptor = Cipher(
algorithm=algorithms.ChaCha20(KEY, NONCE),
mode=None,
).encryptor()
for i in range(ITERATIONS):
encryptor.update(DATA)
elapsed = time.time() - start
print(f"{ITERATIONS} iterations without teardown in {elapsed:.1f} s") I then ran these tests against both main - OpenSSL 3.01000000 iterations with teardown in 11.1 s crypto-rust - OpenSSL 3.01000000 iterations with teardown in 7.5 s AFAICT it tells us the |
In your test example you're using the Cipher/ChaCha20 construction but in your draft PR you're using In cryptography 42.0.x we shifted If we use this test script import random
import time
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
ITERATIONS = 1000000
KEY = bytes(32)
DATA = bytes(64)
start = time.time()
c = ChaCha20Poly1305(KEY)
for i in range(ITERATIONS):
nonce = random.randbytes(12) # non-CSPRNG but just used to ensure there's always a new nonce
c.encrypt(nonce, DATA, None)
elapsed = time.time() - start
print(f"{ITERATIONS} iterations with teardown in {elapsed:.1f} s") And some performance:
So with the latest changes we are now >20% faster than the old reuseable context hack (which is broken for 42.0.0+ anyway). Is there an easy way for me to do aioquic perf testing? |
Looking a bit more closely I realize you're also using the traditional Cipher API later in the file. Well, I made ChaCha20Poly1305 much faster at least 😄. We would definitely need to come up with a new API for allowing |
QUIC indeed uses both AEAD for payload encryption (AES-GCM or ChaCha20Poly1305) and AES-ECB or ChaCha20 to mask the packet headers. I currently have a huge performance gap (about 10x) between my C implementation and the Python one, but its not all due to encryption, I suspect my bytearray manipulations are sub-optimal. I'd really like to get rid of the C code, both because of the inherent risks of a foot-gun and because it forces me to vendor another copy of OpenSSL, I know there are performance gains coming thanks to Alex's PRs, but what struck me was the assumption in the Cryptography API that a nonce is set only once for ChaCha20, which does not line up with how QUIC uses it. Hence my ticket :) |
Some draft work on this in #10437 |
resolved |
Hello cryptographistas!
Currently
aioquic
's QUIC header protection and encryption features use C code linked against OpenSSL. I am considering porting this to pure Python using onlycryptography
. On the whole things work, and a work in progress is here:aiortc/aioquic#457
One thing I noticed is that the
ChaCha20
class takes the nonce in its constructor. Unfortunately QUIC uses a nonce which is derived from each packet's header. This means that when using theCHACHA20_POLY1305_SHA256
cipher suite, for every packet we need to tear down / recreate theChaCha20
instance which is not cheap.Would you consider an API which allows updating the nonce? This can be implemented by calling:
EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, operation)
The text was updated successfully, but these errors were encountered: