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 : : 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 : 0 : void Encrypt(Span<const std::byte> plain, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> cipher) noexcept 42 : : { 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 : 0 : bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Nonce96 nonce, Span<std::byte> plain) noexcept 57 : : { 58 : 0 : 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 : : 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 : 670 : uint32_t m_packet_counter{0}; 93 : : 94 : : /** The number of rekeys performed so far. */ 95 : 670 : 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 : 670 : FSChaCha20Poly1305(Span<const std::byte> key, uint32_t rekey_interval) noexcept : 115 : 1340 : 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 : 0 : void Encrypt(Span<const std::byte> plain, Span<const std::byte> aad, Span<std::byte> cipher) noexcept 122 : : { 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 : 0 : bool Decrypt(Span<const std::byte> cipher, Span<const std::byte> aad, Span<std::byte> plain) noexcept 137 : : { 138 : 0 : 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