Branch data Line data Source code
1 : : // Copyright (c) 2023 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_BIP324_H
6 : : #define BITCOIN_BIP324_H
7 : :
8 : : #include <array>
9 : : #include <cstddef>
10 : : #include <optional>
11 : :
12 : : #include <crypto/chacha20.h>
13 : : #include <crypto/chacha20poly1305.h>
14 : : #include <key.h>
15 : : #include <pubkey.h>
16 : : #include <span.h>
17 : :
18 : : /** The BIP324 packet cipher, encapsulating its key derivation, stream cipher, and AEAD. */
19 : : class BIP324Cipher
20 : : {
21 : : public:
22 : : static constexpr unsigned SESSION_ID_LEN{32};
23 : : static constexpr unsigned GARBAGE_TERMINATOR_LEN{16};
24 : : static constexpr unsigned REKEY_INTERVAL{224};
25 : : static constexpr unsigned LENGTH_LEN{3};
26 : : static constexpr unsigned HEADER_LEN{1};
27 : : static constexpr unsigned EXPANSION = LENGTH_LEN + HEADER_LEN + FSChaCha20Poly1305::EXPANSION;
28 : : static constexpr std::byte IGNORE_BIT{0x80};
29 : :
30 : : private:
31 : : std::optional<FSChaCha20> m_send_l_cipher;
32 : : std::optional<FSChaCha20> m_recv_l_cipher;
33 : : std::optional<FSChaCha20Poly1305> m_send_p_cipher;
34 : : std::optional<FSChaCha20Poly1305> m_recv_p_cipher;
35 : :
36 : : CKey m_key;
37 : : EllSwiftPubKey m_our_pubkey;
38 : :
39 : : std::array<std::byte, SESSION_ID_LEN> m_session_id;
40 : : std::array<std::byte, GARBAGE_TERMINATOR_LEN> m_send_garbage_terminator;
41 : : std::array<std::byte, GARBAGE_TERMINATOR_LEN> m_recv_garbage_terminator;
42 : :
43 : : public:
44 : : /** No default constructor; keys must be provided to create a BIP324Cipher. */
45 : : BIP324Cipher() = delete;
46 : :
47 : : /** Initialize a BIP324 cipher with specified key and encoding entropy (testing only). */
48 : : BIP324Cipher(const CKey& key, Span<const std::byte> ent32) noexcept;
49 : :
50 : : /** Initialize a BIP324 cipher with specified key (testing only). */
51 : : BIP324Cipher(const CKey& key, const EllSwiftPubKey& pubkey) noexcept;
52 : :
53 : : /** Retrieve our public key. */
54 : 0 : const EllSwiftPubKey& GetOurPubKey() const noexcept { return m_our_pubkey; }
55 : :
56 : : /** Initialize when the other side's public key is received. Can only be called once.
57 : : *
58 : : * initiator is set to true if we are the initiator establishing the v2 P2P connection.
59 : : * self_decrypt is only for testing, and swaps encryption/decryption keys, so that encryption
60 : : * and decryption can be tested without knowing the other side's private key.
61 : : */
62 : : void Initialize(const EllSwiftPubKey& their_pubkey, bool initiator, bool self_decrypt = false) noexcept;
63 : :
64 : : /** Determine whether this cipher is fully initialized. */
65 [ # # # # : 0 : explicit operator bool() const noexcept { return m_send_l_cipher.has_value(); }
# # # # ]
66 : :
67 : : /** Encrypt a packet. Only after Initialize().
68 : : *
69 : : * It must hold that output.size() == contents.size() + EXPANSION.
70 : : */
71 : : void Encrypt(Span<const std::byte> contents, Span<const std::byte> aad, bool ignore, Span<std::byte> output) noexcept;
72 : :
73 : : /** Decrypt the length of a packet. Only after Initialize().
74 : : *
75 : : * It must hold that input.size() == LENGTH_LEN.
76 : : */
77 : : unsigned DecryptLength(Span<const std::byte> input) noexcept;
78 : :
79 : : /** Decrypt a packet. Only after Initialize().
80 : : *
81 : : * It must hold that input.size() + LENGTH_LEN == contents.size() + EXPANSION.
82 : : * Contents.size() must equal the length returned by DecryptLength.
83 : : */
84 : : bool Decrypt(Span<const std::byte> input, Span<const std::byte> aad, bool& ignore, Span<std::byte> contents) noexcept;
85 : :
86 : : /** Get the Session ID. Only after Initialize(). */
87 : 0 : Span<const std::byte> GetSessionID() const noexcept { return m_session_id; }
88 : :
89 : : /** Get the Garbage Terminator to send. Only after Initialize(). */
90 : 0 : Span<const std::byte> GetSendGarbageTerminator() const noexcept { return m_send_garbage_terminator; }
91 : :
92 : : /** Get the expected Garbage Terminator to receive. Only after Initialize(). */
93 : 0 : Span<const std::byte> GetReceiveGarbageTerminator() const noexcept { return m_recv_garbage_terminator; }
94 : : };
95 : :
96 : : #endif // BITCOIN_BIP324_H
|