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_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 : 1020 : 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 : 4 : void Encrypt(Span<const std::byte> plain, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> cipher) noexcept
42 : : {
43 : 4 : Encrypt(plain, {}, aad, nonce, cipher);
44 : 4 : }
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 : 4 : bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> plain) noexcept
57 : : {
58 : 4 : return Decrypt(cipher, aad, nonce, plain, {});
59 : : }
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 : 508 : 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 : 528 : FSChaCha20Poly1305(Span<const std::byte> key, uint32_t rekey_interval) noexcept :
115 : 528 : 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 : 605002 : void Encrypt(Span<const std::byte> plain, Span<const std::byte> aad, Span<std::byte> cipher) noexcept
122 : : {
123 : 605002 : Encrypt(plain, {}, aad, cipher);
124 : 2 : }
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 : 605002 : bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Span<std::byte> plain) noexcept
137 : : {
138 : 605002 : return Decrypt(cipher, aad, plain, {});
139 : : }
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
|