-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Alter the ChaCha20Poly1305@Bitcoin AEAD to the new specification #20962
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
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
8579374 to
c22f607
Compare
|
Rebased |
PastaPastaPasta
left a comment
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.
utACK;
this PR matches to the best of my understanding what is outlined in the BIP.
I saw no significant formatting problems
That's basically where my expertise stops. However, I'm not sure that we should be using the p2p tag since this is pure crypto but #15649 had p2p tag so I guess that's okay.
Is this PR waiting on some other PR / BIP change, or is the blocker here review by sipa and others?
|
@sipa @jonasschnelli Is there a reason why this PR has stalled? |
dhruv
left a comment
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.
Approach ACK c22f607b62af59969b9378d4cd8ed72b866dec11
I reviewed the code to reconcile with the new, accepted recommendation in BIP324 and ran the test.
The test vector changes are harder to review. I am happy to re-implement the AEAD in python so we can fuzz the C++ implementation against it(different language and author) if that is useful.
src/crypto/chacha_poly_aead.h
Outdated
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.
In #18242, I see that the bytes are accessible as a Span and Span::size() seems available. Would it be useful to say something like: "If the decrypted length does not match the payload length, the connection MUST be immediately terminated?"
At first I thought that is implicitly delegated to the MAC, but we don't seem to confirm that the length is correct when encrypting either.
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.
Thinking through this more, I realized that:
- Sender errors in encrypted length cannot be corrected since the bytes for multiple p2p messages are in a single TCP stream. Such sender errors are protocol errors.
- MITM errors/attacks will be caught by the MAC check.
src/test/crypto_tests.cpp
Outdated
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.
This line implies that the decrypted length is len(AAD) + len(payload). I interpreted, this to mean that the decrypted length is the length of the ciphertext of the payload alone.
If this is intentional, can we make it clearer in the BIP? IIUC, typically, in other protocols, the length in the preamble is the length of the payload that follows. Did we want to do it that way?
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 BIP, the unit test and the bench test have been updated to be consistently clear that the encrypted length is len(ciphertext_payload) and not len(ciphertext_payload + ciphertext_aad)
1a868b1 to
424e010
Compare
|
I will be taking on this PR. Rebased with master. Addressed my own comments. Ready for further review. |
stratospher
left a comment
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.
Approach ACK.
It would be nice to remove a few redundant lines of code.
src/crypto/chacha_poly_aead.h
Outdated
| #include <crypto/poly1305.h> | ||
|
|
||
| #include <cmath> | ||
|
|
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.
AAD_PACKAGES_PER_ROUND is defined but not used anywhere. Couldn't we remove it?
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.
Good catch. Fixed.
src/crypto/chacha_poly_aead.cpp
Outdated
| m_ctx.SetKey(key, keylen); | ||
|
|
||
| // set initial sequence number | ||
| m_seqnr = 0; |
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.
Since we're already initialising m_seqnr with 0 in the class definition of ChaCha20Forward4064,
bitcoin/src/crypto/chacha_poly_aead.h
Line 107 in 424e010
| uint64_t m_seqnr{0}; |
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.
Done.
src/crypto/chacha_poly_aead.cpp
Outdated
|
|
||
| // precompute first chunk of keystream | ||
| m_ctx.Keystream(m_keystream, KEYSTREAM_SIZE); | ||
| m_keystream_pos = 0; |
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.
Since we're already initialising m_keystream_pos with 0 in the class definition of ChaCha20Forward4064,
bitcoin/src/crypto/chacha_poly_aead.h
Line 108 in 424e010
| size_t m_keystream_pos{0}; |
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.
Done.
src/crypto/chacha_poly_aead.cpp
Outdated
| assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN); | ||
| assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN); |
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.
We are checking whether the key length is 32 on this line
bitcoin/src/crypto/chacha_poly_aead.cpp
Line 33 in 424e010
| assert(keylen == 32); |
m_chacha_header and m_chacha_main get called. So couldn't we remove these 2 lines?
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.
I find these asserts clarifying and afaict, C++ asserts are optimized away in release builds so it's not slowing anything down. Leaving these in here for now.
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.
Update: Turns out this was mistaken. assert() is not optimized away in optimized Bitcoin Core builds.
424e010 to
8a9daf5
Compare
|
Comments from @stratospher addressed. Ready for further review. |
8a9daf5 to
0b93e3d
Compare
|
Addressed #23233 (comment) - ready for further review |
stratospher
left a comment
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.
Concept ACK 0b93e3d
It’s super awesome to see BIP 324 shaping up! This PR captures the ChaCha20Forward4064-Poly1305@Bitcoin cipher suite proposed in BIP 324 beautifully.
| BIP 324 | PR | |
|---|---|---|
| Prerequisites |
|
Defined in:
|
| Encryption | ![]() |
Crypt() is in line with the BIP's specifications. |
| Decryption | ![]() |
Crypt() handles both encryption and decryption. |
I noticed some more refactoring which could be done.
src/crypto/chacha_poly_aead.h
Outdated
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.
#include <cmath> isn't being used.
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.
Done
src/crypto/chacha_poly_aead.h
Outdated
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.
a typo for semantics? :)
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.
:) done.
src/crypto/chacha_poly_aead.cpp
Outdated
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.
These imports can be removed since they aren't used:
#include <string.h>#include <cstdio>#include <limits>
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.
Need string.h for size_t: https://en.cppreference.com/w/c/types/size_t
Added cstring for memset: https://en.cppreference.com/w/cpp/string/byte/memset
Removed cstdio and limits
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.
These header files aren't used too and can be removed:
EDIT: I'm a bit confused about whether cassert needs to be removed. Even though an assert statement isn't used anywhere in the fuzz test file, it maybe needed in the fuzzing environment?
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.
Done.
src/bench/chacha_poly_aead.cpp
Outdated
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.
#include <limits> can be removed since it's usage in the file has been removed.
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.
Done.
src/bench/chacha_poly_aead.cpp
Outdated
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.
This comment suggestion can be applied here too.
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.
Ah, I was looking for another place this was useful and didn't remember correctly. Thanks, @stratospher !
0b93e3d to
0de3cb9
Compare
|
Thank you for the great diagrams, @stratospher ! They'll come in handy at a future review club meeting and in docs. Review comments addressed. Rebased. Ready for further review. |
6a651b5 to
41deee4
Compare
|
Addressed some comments for this PR left over at #23233 by @laanwj: #23233 (comment) I also rebased against master because at one point I had trouble running fuzz tests(but it turned out to be unrelated). Ready for further review. |
41deee4 to
8b474d1
Compare
|
Rebased. Ready for further review.
|
|
Concept ACK, will review soon. |
|
Thanks to @stratospher for finding a bug in the test code. We were using
Ready for further review. |
src/crypto/chacha_poly_aead.cpp
Outdated
| m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key)); | ||
| // 1. AAD (the encrypted packet length), use the header-keystream | ||
| if (is_encrypt) { | ||
| m_chacha_header.Crypt(src, dest, 3); |
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 ChaCha20Poly1305AEAD::Crypt function uses argument order dest, len, src
The ChaCha20Forward4064::Crypt function uses argument order input, output, bytes
Let's standardize on one, please.
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.
Done. New implementation uses spans and I went with input, output everywhere.
src/bench/chacha_poly_aead.cpp
Outdated
| static const unsigned char k2[32] = {0}; | ||
|
|
||
| static ChaCha20Poly1305AEAD aead(k1, 32, k2, 32); | ||
| static std::vector<unsigned char> zero_key(32, 0x00); |
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.
Having this mutable is slightly risky. Can we add const or constexpr?
Edit: ok, this is "only" bench code, but still.
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.
Done.
src/crypto/chacha_poly_aead.cpp
Outdated
| #endif // TIMINGSAFE_BCMP | ||
|
|
||
| ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len) | ||
| ChaCha20Forward4064::ChaCha20Forward4064(const Span<unsigned char> key) |
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.
If your intent is to have the contents of the Span const (which I think it is), this should be Span<const unsigned char>.
(more of these below)
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.
Done across the board.
src/crypto/chacha_poly_aead.h
Outdated
| src_len, the length of the source buffer | ||
| is_encrypt, set to true if we encrypt (creates and appends the MAC instead of verifying it) | ||
| Returns true if encipher succeeds. Upon failure, the data at dest should not be used. |
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.
Is "encipher" a word? If it means the same, I prefer "encrypt or decrypt".
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.
Done.
|
First commit is from #25354 and should be reviewed there. This PR just depends on it. Updated the implementation of the BIP324 Cipher Suite to be in accordance with the latest draft in the working group(still pending public release). The changes to intent and code from the original PR are large and since I didn't originally open this PR, I can't change the PR description. I suspect it makes sense to close this PR and open a new one, but we'd lose the history. I'd welcome thoughts on that from reviewers and maintainers. Ready for further review. |
|
Superseded by #25361 because:
|


During discussions and reviews of BIP324 (p2p transport encryption), a more efficient AEAD was proposed.
The main difference is how the construct implements re-keying. Since both, the original and the new BIP324 AEAD will not repeat the key handshake over time (no re-keying on the ECDH level), a simpler form of direct re-keying has been proposed.
The new AEAD uses a ChaCha20 stream cipher where byte 4064 till byte 4096 (last 32 bytes in a 4096 window) are used to re-key the same instance. Re-keying in that context means re-setting the ChaCha20 key (thus setting the constant "expand 32-byte k" again, resetting the counter) to the last 32bytes of the current 4096 chunk. We never encrypt more than 4096bytes with the same key. On every re-key, we increase the IV by 1 (a sequence number).
This should allow forward secrecy in the same way as the old (and slightly cumbersome) rekeying approach.
The AEAD is currently only used in tests. The serializer and deserializer for the V2 transport are in #23233.
BIP324 proposal can be found here: https://gist.github.com/dhruv/5b1275751bc98f3b64bcafce7876b489