/root/bitcoin/src/crypto/chacha20poly1305.h
Line | Count | Source (jump to first uncovered line) |
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_CRYPTO_CHACHA20POLY1305_H |
6 | | #define BITCOIN_CRYPTO_CHACHA20POLY1305_H |
7 | | |
8 | | #include <cstddef> |
9 | | #include <stdint.h> |
10 | | |
11 | | #include <crypto/chacha20.h> |
12 | | #include <crypto/poly1305.h> |
13 | | #include <span.h> |
14 | | |
15 | | /** The AEAD_CHACHA20_POLY1305 authenticated encryption algorithm from RFC8439 section 2.8. */ |
16 | | class AEADChaCha20Poly1305 |
17 | | { |
18 | | /** Internal stream cipher. */ |
19 | | ChaCha20 m_chacha20; |
20 | | |
21 | | public: |
22 | | /** Expected size of key argument in constructor. */ |
23 | | static constexpr unsigned KEYLEN = 32; |
24 | | |
25 | | /** Expansion when encrypting. */ |
26 | | static constexpr unsigned EXPANSION = Poly1305::TAGLEN; |
27 | | |
28 | | /** Initialize an AEAD instance with a specified 32-byte key. */ |
29 | | AEADChaCha20Poly1305(Span<const std::byte> key) noexcept; |
30 | | |
31 | | /** Switch to another 32-byte key. */ |
32 | | void SetKey(Span<const std::byte> key) noexcept; |
33 | | |
34 | | /** 96-bit nonce type. */ |
35 | | using Nonce96 = ChaCha20::Nonce96; |
36 | | |
37 | | /** Encrypt a message with a specified 96-bit nonce and aad. |
38 | | * |
39 | | * Requires cipher.size() = plain.size() + EXPANSION. |
40 | | */ |
41 | | void Encrypt(Span<const std::byte> plain, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> cipher) noexcept |
42 | 0 | { |
43 | 0 | Encrypt(plain, {}, aad, nonce, cipher); |
44 | 0 | } |
45 | | |
46 | | /** Encrypt a message (given split into plain1 + plain2) with a specified 96-bit nonce and aad. |
47 | | * |
48 | | * Requires cipher.size() = plain1.size() + plain2.size() + EXPANSION. |
49 | | */ |
50 | | void Encrypt(Span<const std::byte> plain1, Span<const std::byte> plain2, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> cipher) noexcept; |
51 | | |
52 | | /** Decrypt a message with a specified 96-bit nonce and aad. Returns true if valid. |
53 | | * |
54 | | * Requires cipher.size() = plain.size() + EXPANSION. |
55 | | */ |
56 | | bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> plain) noexcept |
57 | 0 | { |
58 | 0 | return Decrypt(cipher, aad, nonce, plain, {}); |
59 | 0 | } |
60 | | |
61 | | /** Decrypt a message with a specified 96-bit nonce and aad and split the result. Returns true if valid. |
62 | | * |
63 | | * Requires cipher.size() = plain1.size() + plain2.size() + EXPANSION. |
64 | | */ |
65 | | bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> plain1, Span<std::byte> plain2) noexcept; |
66 | | |
67 | | /** Get a number of keystream bytes from the underlying stream cipher. |
68 | | * |
69 | | * This is equivalent to Encrypt() with plain set to that many zero bytes, and dropping the |
70 | | * last EXPANSION bytes off the result. |
71 | | */ |
72 | | void Keystream(Nonce96 nonce, Span<std::byte> keystream) noexcept; |
73 | | }; |
74 | | |
75 | | /** Forward-secure wrapper around AEADChaCha20Poly1305. |
76 | | * |
77 | | * This implements an AEAD which automatically increments the nonce on every encryption or |
78 | | * decryption, and cycles keys after a predetermined number of encryptions or decryptions. |
79 | | * |
80 | | * See BIP324 for details. |
81 | | */ |
82 | | class FSChaCha20Poly1305 |
83 | | { |
84 | | private: |
85 | | /** Internal AEAD. */ |
86 | | AEADChaCha20Poly1305 m_aead; |
87 | | |
88 | | /** Every how many iterations this cipher rekeys. */ |
89 | | const uint32_t m_rekey_interval; |
90 | | |
91 | | /** The number of encryptions/decryptions since the last rekey. */ |
92 | | uint32_t m_packet_counter{0}; |
93 | | |
94 | | /** The number of rekeys performed so far. */ |
95 | | uint64_t m_rekey_counter{0}; |
96 | | |
97 | | /** Update counters (and if necessary, key) to transition to the next message. */ |
98 | | void NextPacket() noexcept; |
99 | | |
100 | | public: |
101 | | /** Length of keys expected by the constructor. */ |
102 | | static constexpr auto KEYLEN = AEADChaCha20Poly1305::KEYLEN; |
103 | | |
104 | | /** Expansion when encrypting. */ |
105 | | static constexpr auto EXPANSION = AEADChaCha20Poly1305::EXPANSION; |
106 | | |
107 | | // No copy or move to protect the secret. |
108 | | FSChaCha20Poly1305(const FSChaCha20Poly1305&) = delete; |
109 | | FSChaCha20Poly1305(FSChaCha20Poly1305&&) = delete; |
110 | | FSChaCha20Poly1305& operator=(const FSChaCha20Poly1305&) = delete; |
111 | | FSChaCha20Poly1305& operator=(FSChaCha20Poly1305&&) = delete; |
112 | | |
113 | | /** Construct an FSChaCha20Poly1305 cipher that rekeys every rekey_interval operations. */ |
114 | | FSChaCha20Poly1305(Span<const std::byte> key, uint32_t rekey_interval) noexcept : |
115 | 0 | m_aead(key), m_rekey_interval(rekey_interval) {} |
116 | | |
117 | | /** Encrypt a message with a specified aad. |
118 | | * |
119 | | * Requires cipher.size() = plain.size() + EXPANSION. |
120 | | */ |
121 | | void Encrypt(Span<const std::byte> plain, Span<const std::byte> aad, Span<std::byte> cipher) noexcept |
122 | 0 | { |
123 | 0 | Encrypt(plain, {}, aad, cipher); |
124 | 0 | } |
125 | | |
126 | | /** Encrypt a message (given split into plain1 + plain2) with a specified aad. |
127 | | * |
128 | | * Requires cipher.size() = plain.size() + EXPANSION. |
129 | | */ |
130 | | void Encrypt(Span<const std::byte> plain1, Span<const std::byte> plain2, Span<const std::byte> aad, Span<std::byte> cipher) noexcept; |
131 | | |
132 | | /** Decrypt a message with a specified aad. Returns true if valid. |
133 | | * |
134 | | * Requires cipher.size() = plain.size() + EXPANSION. |
135 | | */ |
136 | | bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Span<std::byte> plain) noexcept |
137 | 0 | { |
138 | 0 | return Decrypt(cipher, aad, plain, {}); |
139 | 0 | } |
140 | | |
141 | | /** Decrypt a message with a specified aad and split the result. Returns true if valid. |
142 | | * |
143 | | * Requires cipher.size() = plain1.size() + plain2.size() + EXPANSION. |
144 | | */ |
145 | | bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Span<std::byte> plain1, Span<std::byte> plain2) noexcept; |
146 | | }; |
147 | | |
148 | | #endif // BITCOIN_CRYPTO_CHACHA20POLY1305_H |