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

Add p2p layer encryption with ECDH/ChaCha20Poly1305 #14032

Closed
wants to merge 21 commits into from

Conversation

@jonasschnelli
Copy link
Member

@jonasschnelli jonasschnelli commented Aug 23, 2018

This PR adds encryption to the p2p communication after a slightly overhauled version of BIP151 defined here (there is the plan to change BIP151 or to propose this protocol in a new BIP)

The encryption is optional and by default disabled (-netencryption).

If enabled, a peer connecting to another peer signalling NODE_ENCRYPTED (or added via -connect=) will try to do the proposed key handshake and continue with encrypted communication.

If enabled, peers can request (and perform) encrypted communications by sending a handshake request.

Peers not supporting encryption are still accepted (no option to enforce encrypted communication).

There is a plan to make the handshake quantum resistance by adding NewHope to the key handshake (https://newhopecrypto.org). But since this PR is already very large, it's unclear wether this should be an independent patch (probably another ~600 lines of code).

Out of scope:

  • optimized ChaCha20 implementation (for review and security reasons, the implementation is extracted from openssh)
  • benchmarks added to bench (I have done comparison against the v1 protocol with dbl-SHA256 the performance seems very similar)
  • Please no discussion about the used crypto scheme or the proposal itself (better place would be the mailing list)

TODO:

  • add option to -connect= RPC addnode where it is possible to specify the expected service flags (currently -connect= will always try for encrypted coms).
src/net.cpp Outdated
CNetMessage& msg = vRecvMsg.back();
if (vRecvMsg.empty() || vRecvMsg.back()->complete()) {
if (m_encryption_handler && m_encryption_handler->shouldCryptMsg()) {
vRecvMsg.emplace_back(std::make_shared<NetCryptedMessageEnvelop>(m_encryption_handler, Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION));
Copy link
Contributor

@practicalswift practicalswift Aug 23, 2018

Nit: Should this be ”envelope” instead of ”envelop”? If so, change applies throughout this PR and also the BIP.

src/init.cpp Outdated
@@ -477,6 +478,7 @@ void SetupServerArgs()
gArgs.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-netencryptionfastrekey", "Rekeys every 10 seconds and after 10kb of data", true, OptionsCategory::DEBUG_TEST);
Copy link
Contributor

@practicalswift practicalswift Aug 23, 2018

If I’m reading the logic correct then this should be ”every 10 seconds or after 10kb of data”?

src/net.cpp Outdated
msg->nTime = nTimeMicros;
if (msg->m_type == NetMessageType::PLAINTEXT_ENCRYPTION_HANDSHAKE && !msg->verifyHeader()) {
// message contains expected network magic and "version" message command
// threat as version message
Copy link
Contributor

@practicalswift practicalswift Aug 23, 2018

Nit: “treat”

LOCK(cs);
if (m_bytes_decrypted + vsize > ABORT_LIMIT_BYTES || GetTime() - m_time_last_rekey_send > ABORT_LIMIT_TIME ||
(gArgs.GetBoolArg("-netencryptionfastrekey", false) && m_bytes_decrypted + vsize > 12 * 1024)) {
// don't further decrypt and therefor abort connection when counterparty failed to respect rekey limits
Copy link
Contributor

@practicalswift practicalswift Aug 23, 2018

Nit: “therefore”?

}

virtual bool complete() const = 0;
virtual uint32_t getMessageSize() const = 0; //returns 0 when message hat not yet been parsed
Copy link
Contributor

@practicalswift practicalswift Aug 23, 2018

Nit: “has”?

@DrahtBot
Copy link
Contributor

@DrahtBot DrahtBot commented Aug 23, 2018

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #16362 (gui: Bilingual translation by hebasto)
  • #16324 (Get cs_main out of the critical path in ProcessMessages by TheBlueMatt)
  • #16323 (Call ProcessNewBlock() asynchronously by TheBlueMatt)
  • #16273 (refactor: Remove unused includes by practicalswift)
  • #16248 (Make whitebind/whitelist permissions more flexible by NicolasDorier)
  • #16224 (gui: Bilingual GUI error messages by hebasto)
  • #16202 (Refactor network message deserialization by jonasschnelli)
  • #16097 (WIP: Prevent meaningless negating of arguments by hebasto)
  • #16060 (Bury bip9 deployments by jnewbery)
  • #15649 (Add ChaCha20Poly1305@Bitcoin AEAD by jonasschnelli)
  • #15505 ([p2p] Request NOTFOUND transactions immediately from other outbound peers, when possible by sdaftuar)
  • #15206 (Immediately disconnect on invalid net message checksum by jonasschnelli)
  • #15197 (Refactor and slightly stricter p2p message processing by jonasschnelli)
  • #14046 (net: Refactor message parsing (CNetMessage), adds flexibility by jonasschnelli)
  • #10102 ([experimental] Multiprocess bitcoin by ryanofsky)

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.

@jonasschnelli
Copy link
Member Author

@jonasschnelli jonasschnelli commented Aug 23, 2018

Fixed @practicalswift points.

@laanwj laanwj removed this from Blockers in High-priority for review Aug 23, 2018
@gmaxwell
Copy link
Contributor

@gmaxwell gmaxwell commented Aug 23, 2018

Great work!

Although optimized crypto is certainly out of scope, we do want to be mindful of making any protocol decisions that would preclude using them. :)

@jonasschnelli
Copy link
Member Author

@jonasschnelli jonasschnelli commented Aug 24, 2018

Note to reviewers: please review...

  • #14046 Refactor message parsing (CNetMessage), adds flexibility
  • #14047 Add HKDF_HMAC256_L32 and method to negate a private key
  • #14049 Enable libsecp256k1 ecdh module, add ECDH function to CKey
  • #14050 Add chacha20/poly1305 and chacha20poly1305_AEAD from openssh
    ... first (extracted commits from this PR)

@luke-jr
Copy link
Member

@luke-jr luke-jr commented Aug 29, 2018

What is the point of NODE_ENCRYPTED? Service bits shouldn't be used for mere protocol negotiation...

@jonasschnelli
Copy link
Member Author

@jonasschnelli jonasschnelli commented Aug 29, 2018

What is the point of NODE_ENCRYPTED? Service bits shouldn't be used for mere protocol negotiation...

This has now been discussed on IRC:
https://botbot.me/freenode/bitcoin-core-dev/2018-08-29/?msg=103889728&page=3

@DrahtBot
Copy link
Contributor

@DrahtBot DrahtBot commented Jul 12, 2019

Needs rebase

PastaPastaPasta added a commit to PastaPastaPasta/dash that referenced this issue Jan 25, 2020
…ate key

8794a4b QA: add test for HKDF HMAC_SHA256 L32 (Jonas Schnelli)
551d489 Add HKDF HMAC_SHA256 L=32 implementations (Jonas Schnelli)
3b64f85 QA: add test for CKey::Negate() (Jonas Schnelli)
463921b CKey: add method to negate the key (Jonas Schnelli)

Pull request description:

  This adds a limited implementation of `HKDF` (defined by rfc5869) that supports only HMAC-SHA256  and length output of 32 bytes (will be required for v2 transport protocol).

  This PR also includes a method to negate a private key which is useful to enforce public keys starting with 0x02 (or 0x03) (a requirement for the v2 transport protocol). The new `CKey::Negate()` method is pretty much a wrapper around `secp256k1_ec_privkey_negate()`.

  Including tests.

  This is a subset of bitcoin#14032 and a pre-requirement for the v2 transport protocol.

ACKs for commit 8794a4:

Tree-SHA512: 5341929dfa29f5da766ec3612784baec6a3ad69972f08b5a985a8aafdae4dae36f104a2b888d1f5d1f33561456bd111f960d7e32c2cc4fd18e48358468f26c1a
PastaPastaPasta added a commit to PastaPastaPasta/dash that referenced this issue Jan 25, 2020
…ate key

8794a4b QA: add test for HKDF HMAC_SHA256 L32 (Jonas Schnelli)
551d489 Add HKDF HMAC_SHA256 L=32 implementations (Jonas Schnelli)
3b64f85 QA: add test for CKey::Negate() (Jonas Schnelli)
463921b CKey: add method to negate the key (Jonas Schnelli)

Pull request description:

  This adds a limited implementation of `HKDF` (defined by rfc5869) that supports only HMAC-SHA256  and length output of 32 bytes (will be required for v2 transport protocol).

  This PR also includes a method to negate a private key which is useful to enforce public keys starting with 0x02 (or 0x03) (a requirement for the v2 transport protocol). The new `CKey::Negate()` method is pretty much a wrapper around `secp256k1_ec_privkey_negate()`.

  Including tests.

  This is a subset of bitcoin#14032 and a pre-requirement for the v2 transport protocol.

ACKs for commit 8794a4:

Tree-SHA512: 5341929dfa29f5da766ec3612784baec6a3ad69972f08b5a985a8aafdae4dae36f104a2b888d1f5d1f33561456bd111f960d7e32c2cc4fd18e48358468f26c1a
Signed-off-by: Pasta <pasta@dashboost.org>
CNetMessage& msg = vRecvMsg.back();
if (vRecvMsg.empty() || vRecvMsg.back()->Complete()) {
if (m_encryption_handler && m_encryption_handler->ShouldCryptMsg()) {
vRecvMsg.emplace_back(MakeUnique<NetV2Message>(m_encryption_handler, Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION));
Copy link
Member

@fanquake fanquake Mar 12, 2021

UdjinM6 added a commit to UdjinM6/dash that referenced this issue Aug 10, 2021
…ate key

8794a4b QA: add test for HKDF HMAC_SHA256 L32 (Jonas Schnelli)
551d489 Add HKDF HMAC_SHA256 L=32 implementations (Jonas Schnelli)
3b64f85 QA: add test for CKey::Negate() (Jonas Schnelli)
463921b CKey: add method to negate the key (Jonas Schnelli)

Pull request description:

  This adds a limited implementation of `HKDF` (defined by rfc5869) that supports only HMAC-SHA256  and length output of 32 bytes (will be required for v2 transport protocol).

  This PR also includes a method to negate a private key which is useful to enforce public keys starting with 0x02 (or 0x03) (a requirement for the v2 transport protocol). The new `CKey::Negate()` method is pretty much a wrapper around `secp256k1_ec_privkey_negate()`.

  Including tests.

  This is a subset of bitcoin#14032 and a pre-requirement for the v2 transport protocol.

ACKs for commit 8794a4:

Tree-SHA512: 5341929dfa29f5da766ec3612784baec6a3ad69972f08b5a985a8aafdae4dae36f104a2b888d1f5d1f33561456bd111f960d7e32c2cc4fd18e48358468f26c1a
5tefan added a commit to 5tefan/dash that referenced this issue Aug 12, 2021
…ate key

8794a4b QA: add test for HKDF HMAC_SHA256 L32 (Jonas Schnelli)
551d489 Add HKDF HMAC_SHA256 L=32 implementations (Jonas Schnelli)
3b64f85 QA: add test for CKey::Negate() (Jonas Schnelli)
463921b CKey: add method to negate the key (Jonas Schnelli)

Pull request description:

  This adds a limited implementation of `HKDF` (defined by rfc5869) that supports only HMAC-SHA256  and length output of 32 bytes (will be required for v2 transport protocol).

  This PR also includes a method to negate a private key which is useful to enforce public keys starting with 0x02 (or 0x03) (a requirement for the v2 transport protocol). The new `CKey::Negate()` method is pretty much a wrapper around `secp256k1_ec_privkey_negate()`.

  Including tests.

  This is a subset of bitcoin#14032 and a pre-requirement for the v2 transport protocol.

ACKs for commit 8794a4:

Tree-SHA512: 5341929dfa29f5da766ec3612784baec6a3ad69972f08b5a985a8aafdae4dae36f104a2b888d1f5d1f33561456bd111f960d7e32c2cc4fd18e48358468f26c1a
@fanquake
Copy link
Member

@fanquake fanquake commented Aug 18, 2021

My understanding is that someone else is helping with / taking over these changes, and that the BIP is still being overhauled.
I think we'll be better off with new PRs, and clean discussion when work on the implementation resumes in this repo.
Changes from here are be cherry-picked if / when needed. So I'm going to close this PR for now.

@fanquake fanquake closed this Aug 18, 2021
@michaelfolkson
Copy link
Contributor

@michaelfolkson michaelfolkson commented Aug 23, 2021

For additional context on above from @fanquake BIP 151 has been withdrawn, the replacement is BIP 324 and the point of contact for BIP 324 appears to be @dhruv from this point on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

9 participants