/Users/eugenesiegel/btc/bitcoin/src/crypto/chacha20poly1305.h
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2023-present 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 <cstdint> | 
| 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(std::span<const std::byte> key) noexcept; | 
| 30 |  |  | 
| 31 |  |     /** Switch to another 32-byte key. */ | 
| 32 |  |     void SetKey(std::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(std::span<const std::byte> plain, std::span<const std::byte> aad, Nonce96 nonce, std::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(std::span<const std::byte> plain1, std::span<const std::byte> plain2, std::span<const std::byte> aad, Nonce96 nonce, std::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(std::span<const std::byte> cipher, std::span<const std::byte> aad, Nonce96 nonce, std::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(std::span<const std::byte> cipher, std::span<const std::byte> aad, Nonce96 nonce, std::span<std::byte> plain1, std::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, std::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(std::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(std::span<const std::byte> plain, std::span<const std::byte> aad, std::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(std::span<const std::byte> plain1, std::span<const std::byte> plain2, std::span<const std::byte> aad, std::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(std::span<const std::byte> cipher, std::span<const std::byte> aad, std::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(std::span<const std::byte> cipher, std::span<const std::byte> aad, std::span<std::byte> plain1, std::span<std::byte> plain2) noexcept; | 
| 146 |  | }; | 
| 147 |  |  | 
| 148 |  | #endif // BITCOIN_CRYPTO_CHACHA20POLY1305_H |