Bitcoin Core  25.99.0
P2P Digital Currency
chacha_poly_aead.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-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 #if defined(HAVE_CONFIG_H)
7 #endif
8 
10 
11 #include <crypto/poly1305.h>
12 #include <support/cleanse.h>
13 
14 #include <assert.h>
15 #include <string.h>
16 
17 #include <cstdio>
18 #include <limits>
19 
20 #ifndef HAVE_TIMINGSAFE_BCMP
21 
22 int timingsafe_bcmp(const unsigned char* b1, const unsigned char* b2, size_t n)
23 {
24  const unsigned char *p1 = b1, *p2 = b2;
25  int ret = 0;
26 
27  for (; n > 0; n--)
28  ret |= *p1++ ^ *p2++;
29  return (ret != 0);
30 }
31 
32 #endif // TIMINGSAFE_BCMP
33 
34 ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len)
35 {
38 
39  static_assert(CHACHA20_POLY1305_AEAD_KEY_LEN == 32);
42 
43  // set the cached sequence number to uint64 max which hints for an unset cache.
44  // we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB
45  m_cached_aad_seqnr = std::numeric_limits<uint64_t>::max();
46 }
47 
48 bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char* dest, size_t dest_len /* length of the output buffer for sanity checks */, const unsigned char* src, size_t src_len, bool is_encrypt)
49 {
50  // check buffer boundaries
51  if (
52  // if we encrypt, make sure the source contains at least the expected AAD and the destination has at least space for the source + MAC
53  (is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN || dest_len < src_len + Poly1305::TAGLEN)) ||
54  // if we decrypt, make sure the source contains at least the expected AAD+MAC and the destination has at least space for the source - MAC
55  (!is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN + Poly1305::TAGLEN || dest_len < src_len - Poly1305::TAGLEN))) {
56  return false;
57  }
58 
59  unsigned char expected_tag[Poly1305::TAGLEN], poly_key[Poly1305::KEYLEN];
60  memset(poly_key, 0, sizeof(poly_key));
61 
62  // block counter 0 for the poly1305 key
63  // use lower 32bytes for the poly1305 key
64  // (throws away 32 unused bytes (upper 32) from this ChaCha20 round)
65  m_chacha_main.Seek64({0, seqnr_payload}, 0);
66  m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key));
67 
68  // if decrypting, verify the tag prior to decryption
69  if (!is_encrypt) {
70  const unsigned char* tag = src + src_len - Poly1305::TAGLEN;
71  Poly1305{MakeByteSpan(poly_key)}
72  .Update(AsBytes(Span{src, src_len - Poly1305::TAGLEN}))
73  .Finalize(MakeWritableByteSpan(expected_tag));
74 
75  // constant time compare the calculated MAC with the provided MAC
76  if (timingsafe_bcmp(expected_tag, tag, Poly1305::TAGLEN) != 0) {
77  memory_cleanse(expected_tag, sizeof(expected_tag));
78  memory_cleanse(poly_key, sizeof(poly_key));
79  return false;
80  }
81  memory_cleanse(expected_tag, sizeof(expected_tag));
82  // MAC has been successfully verified, make sure we don't convert it in decryption
83  src_len -= Poly1305::TAGLEN;
84  }
85 
86  // calculate and cache the next 64byte keystream block if requested sequence number is not yet the cache
87  if (m_cached_aad_seqnr != seqnr_aad) {
88  m_cached_aad_seqnr = seqnr_aad;
89  m_chacha_header.Seek64({0, seqnr_aad}, 0);
91  }
92  // crypt the AAD (3 bytes message length) with given position in AAD cipher instance keystream
93  dest[0] = src[0] ^ m_aad_keystream_buffer[aad_pos];
94  dest[1] = src[1] ^ m_aad_keystream_buffer[aad_pos + 1];
95  dest[2] = src[2] ^ m_aad_keystream_buffer[aad_pos + 2];
96 
97  // Set the playload ChaCha instance block counter to 1 and crypt the payload
98  m_chacha_main.Seek64({0, seqnr_payload}, 1);
100 
101  // If encrypting, calculate and append tag
102  if (is_encrypt) {
103  // the poly1305 tag expands over the AAD (3 bytes length) & encrypted payload
104  Poly1305{MakeByteSpan(poly_key)}
105  .Update(AsBytes(Span{dest, src_len}))
106  .Finalize(AsWritableBytes(Span{dest + src_len, Poly1305::TAGLEN}));
107  }
108 
109  // cleanse no longer required MAC and polykey
110  memory_cleanse(poly_key, sizeof(poly_key));
111  return true;
112 }
113 
114 bool ChaCha20Poly1305AEAD::GetLength(uint32_t* len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t* ciphertext)
115 {
116  // enforce valid aad position to avoid accessing outside of the 64byte keystream cache
117  // (there is space for 21 times 3 bytes)
118  assert(aad_pos >= 0 && aad_pos < CHACHA20_ROUND_OUTPUT - CHACHA20_POLY1305_AEAD_AAD_LEN);
119  if (m_cached_aad_seqnr != seqnr_aad) {
120  // we need to calculate the 64 keystream bytes since we reached a new aad sequence number
121  m_cached_aad_seqnr = seqnr_aad;
122  m_chacha_header.Seek64({0, seqnr_aad}, 0); // use LE for the nonce
123  m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); // write keystream to the cache
124  }
125 
126  // decrypt the ciphertext length by XORing the right position of the 64byte keystream cache with the ciphertext
127  *len24_out = (ciphertext[0] ^ m_aad_keystream_buffer[aad_pos + 0]) |
128  (ciphertext[1] ^ m_aad_keystream_buffer[aad_pos + 1]) << 8 |
129  (ciphertext[2] ^ m_aad_keystream_buffer[aad_pos + 2]) << 16;
130 
131  return true;
132 }
int ret
static constexpr int CHACHA20_POLY1305_AEAD_KEY_LEN
static constexpr int CHACHA20_POLY1305_AEAD_AAD_LEN
static constexpr int CHACHA20_ROUND_OUTPUT
void SetKey32(const unsigned char *key32)
set 32-byte key.
Definition: chacha20.h:76
void Keystream(unsigned char *c, size_t bytes)
outputs the keystream of size <bytes> into
Definition: chacha20.cpp:270
void Seek64(Nonce96 nonce, uint32_t block_counter)
Set the 96-bit nonce and 32-bit block counter.
Definition: chacha20.h:86
void Crypt(const unsigned char *input, unsigned char *output, size_t bytes)
enciphers the message <input> of length <bytes> and write the enciphered representation into <output>...
Definition: chacha20.cpp:293
bool Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char *dest, size_t dest_len, const unsigned char *src, size_t src_len, bool is_encrypt)
Encrypts/decrypts a packet seqnr_payload, the message sequence number seqnr_aad, the messages AAD seq...
bool GetLength(uint32_t *len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t *ciphertext)
decrypts the 3 bytes AAD data and decodes it into a uint32_t field
ChaCha20Poly1305AEAD(const unsigned char *K_1, size_t K_1_len, const unsigned char *K_2, size_t K_2_len)
unsigned char m_aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]
C++ wrapper with std::byte Span interface around poly1305_donna code.
Definition: poly1305.h:38
static constexpr unsigned KEYLEN
Length of the keys expected by the constructor.
Definition: poly1305.h:46
static constexpr unsigned TAGLEN
Length of the output produced by Finalize().
Definition: poly1305.h:43
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:97
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
Definition: cleanse.cpp:14
int timingsafe_bcmp(const unsigned char *b1, const unsigned char *b2, size_t n)
Span< std::byte > AsWritableBytes(Span< T > s) noexcept
Definition: span.h:253
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:259
Span< const std::byte > AsBytes(Span< T > s) noexcept
Definition: span.h:248
Span< std::byte > MakeWritableByteSpan(V &&v) noexcept
Definition: span.h:264
assert(!tx.IsCoinBase())