Branch data Line data Source code
1 : : // Copyright (c) 2017-2022 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_CHACHA20_H 6 : : #define BITCOIN_CRYPTO_CHACHA20_H 7 : : 8 : : #include <span.h> 9 : : 10 : : #include <array> 11 : : #include <cstddef> 12 : : #include <cstdlib> 13 : : #include <stdint.h> 14 : : #include <utility> 15 : : 16 : : // classes for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein 17 : : // https://cr.yp.to/chacha/chacha-20080128.pdf. 18 : : // 19 : : // The 128-bit input is here implemented as a 96-bit nonce and a 32-bit block 20 : : // counter, as in RFC8439 Section 2.3. When the 32-bit block counter overflows 21 : : // the first 32-bit part of the nonce is automatically incremented, making it 22 : : // conceptually compatible with variants that use a 64/64 split instead. 23 : : 24 : : /** ChaCha20 cipher that only operates on multiples of 64 bytes. */ 25 : : class ChaCha20Aligned 26 : : { 27 : : private: 28 : : uint32_t input[12]; 29 : : 30 : : public: 31 : : /** Expected key length in constructor and SetKey. */ 32 : : static constexpr unsigned KEYLEN{32}; 33 : : 34 : : /** Block size (inputs/outputs to Keystream / Crypt should be multiples of this). */ 35 : : static constexpr unsigned BLOCKLEN{64}; 36 : : 37 : : /** For safety, disallow initialization without key. */ 38 : : ChaCha20Aligned() noexcept = delete; 39 : : 40 : : /** Initialize a cipher with specified 32-byte key. */ 41 : : ChaCha20Aligned(Span<const std::byte> key) noexcept; 42 : : 43 : : /** Destructor to clean up private memory. */ 44 : : ~ChaCha20Aligned(); 45 : : 46 : : /** Set 32-byte key, and seek to nonce 0 and block position 0. */ 47 : : void SetKey(Span<const std::byte> key) noexcept; 48 : : 49 : : /** Type for 96-bit nonces used by the Set function below. 50 : : * 51 : : * The first field corresponds to the LE32-encoded first 4 bytes of the nonce, also referred 52 : : * to as the '32-bit fixed-common part' in Example 2.8.2 of RFC8439. 53 : : * 54 : : * The second field corresponds to the LE64-encoded last 8 bytes of the nonce. 55 : : * 56 : : */ 57 : : using Nonce96 = std::pair<uint32_t, uint64_t>; 58 : : 59 : : /** Set the 96-bit nonce and 32-bit block counter. 60 : : * 61 : : * Block_counter selects a position to seek to (to byte BLOCKLEN*block_counter). After 256 GiB, 62 : : * the block counter overflows, and nonce.first is incremented. 63 : : */ 64 : : void Seek(Nonce96 nonce, uint32_t block_counter) noexcept; 65 : : 66 : : /** outputs the keystream into out, whose length must be a multiple of BLOCKLEN. */ 67 : : void Keystream(Span<std::byte> out) noexcept; 68 : : 69 : : /** en/deciphers the message <input> and write the result into <output> 70 : : * 71 : : * The size of input and output must be equal, and be a multiple of BLOCKLEN. 72 : : */ 73 : : void Crypt(Span<const std::byte> input, Span<std::byte> output) noexcept; 74 : : }; 75 : : 76 : : /** Unrestricted ChaCha20 cipher. */ 77 : : class ChaCha20 78 : : { 79 : : private: 80 : : ChaCha20Aligned m_aligned; 81 : : std::array<std::byte, ChaCha20Aligned::BLOCKLEN> m_buffer; 82 : 2777 : unsigned m_bufleft{0}; 83 : : 84 : : public: 85 : : /** Expected key length in constructor and SetKey. */ 86 : : static constexpr unsigned KEYLEN = ChaCha20Aligned::KEYLEN; 87 : : 88 : : /** For safety, disallow initialization without key. */ 89 : : ChaCha20() noexcept = delete; 90 : : 91 : : /** Initialize a cipher with specified 32-byte key. */ 92 : 5554 : ChaCha20(Span<const std::byte> key) noexcept : m_aligned(key) {} 93 : : 94 : : /** Destructor to clean up private memory. */ 95 : : ~ChaCha20(); 96 : : 97 : : /** Set 32-byte key, and seek to nonce 0 and block position 0. */ 98 : : void SetKey(Span<const std::byte> key) noexcept; 99 : : 100 : : /** 96-bit nonce type. */ 101 : : using Nonce96 = ChaCha20Aligned::Nonce96; 102 : : 103 : : /** Set the 96-bit nonce and 32-bit block counter. See ChaCha20Aligned::Seek. */ 104 : 0 : void Seek(Nonce96 nonce, uint32_t block_counter) noexcept 105 : : { 106 : 0 : m_aligned.Seek(nonce, block_counter); 107 : 0 : m_bufleft = 0; 108 : 0 : } 109 : : 110 : : /** en/deciphers the message <in_bytes> and write the result into <out_bytes> 111 : : * 112 : : * The size of in_bytes and out_bytes must be equal. 113 : : */ 114 : : void Crypt(Span<const std::byte> in_bytes, Span<std::byte> out_bytes) noexcept; 115 : : 116 : : /** outputs the keystream to out. */ 117 : : void Keystream(Span<std::byte> out) noexcept; 118 : : }; 119 : : 120 : : /** Forward-secure ChaCha20 121 : : * 122 : : * This implements a stream cipher that automatically transitions to a new stream with a new key 123 : : * and new nonce after a predefined number of encryptions or decryptions. 124 : : * 125 : : * See BIP324 for details. 126 : : */ 127 : 0 : class FSChaCha20 128 : : { 129 : : private: 130 : : /** Internal stream cipher. */ 131 : : ChaCha20 m_chacha20; 132 : : 133 : : /** The number of encryptions/decryptions before a rekey happens. */ 134 : : const uint32_t m_rekey_interval; 135 : : 136 : : /** The number of encryptions/decryptions since the last rekey. */ 137 : : uint32_t m_chunk_counter{0}; 138 : : 139 : : /** The number of rekey operations that have happened. */ 140 : : uint64_t m_rekey_counter{0}; 141 : : 142 : : public: 143 : : /** Length of keys expected by the constructor. */ 144 : : static constexpr unsigned KEYLEN = 32; 145 : : 146 : : // No copy or move to protect the secret. 147 : : FSChaCha20(const FSChaCha20&) = delete; 148 : : FSChaCha20(FSChaCha20&&) = delete; 149 : : FSChaCha20& operator=(const FSChaCha20&) = delete; 150 : : FSChaCha20& operator=(FSChaCha20&&) = delete; 151 : : 152 : : /** Construct an FSChaCha20 cipher that rekeys every rekey_interval Crypt() calls. */ 153 : : FSChaCha20(Span<const std::byte> key, uint32_t rekey_interval) noexcept; 154 : : 155 : : /** Encrypt or decrypt a chunk. */ 156 : : void Crypt(Span<const std::byte> input, Span<std::byte> output) noexcept; 157 : : }; 158 : : 159 : : #endif // BITCOIN_CRYPTO_CHACHA20_H