Bitcoin ABC  0.22.12
P2P Digital Currency
chacha_poly_aead.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 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 
6 
7 #include <crypto/poly1305.h>
8 #include <support/cleanse.h>
9 
10 #include <cassert>
11 #include <cstring>
12 
13 #include <cstdio>
14 #include <limits>
15 
16 #ifndef HAVE_TIMINGSAFE_BCMP
17 
18 int timingsafe_bcmp(const uint8_t *b1, const uint8_t *b2, size_t n) {
19  const uint8_t *p1 = b1, *p2 = b2;
20  int ret = 0;
21 
22  for (; n > 0; n--) {
23  ret |= *p1++ ^ *p2++;
24  }
25  return (ret != 0);
26 }
27 
28 #endif // TIMINGSAFE_BCMP
29 
30 ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const uint8_t *K_1, size_t K_1_len,
31  const uint8_t *K_2, size_t K_2_len) {
32  assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
33  assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
36 
37  // set the cached sequence number to uint64 max which hints for an unset
38  // cache. we can't hit uint64 max since the rekey rule (which resets the
39  // sequence number) is 1GB
40  m_cached_aad_seqnr = std::numeric_limits<uint64_t>::max();
41 }
42 
44  uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, uint8_t *dest,
45  size_t dest_len /* length of the output buffer for sanity checks */,
46  const uint8_t *src, size_t src_len, bool is_encrypt) {
47  // check buffer boundaries
48  if (
49  // if we encrypt, make sure the source contains at least the expected
50  // AAD and the destination has at least space for the source + MAC
51  (is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN ||
52  dest_len < src_len + POLY1305_TAGLEN)) ||
53  // if we decrypt, make sure the source contains at least the expected
54  // AAD+MAC and the destination has at least space for the source - MAC
55  (!is_encrypt &&
57  dest_len < src_len - POLY1305_TAGLEN))) {
58  return false;
59  }
60 
61  uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
62  memset(poly_key, 0, sizeof(poly_key));
63  m_chacha_main.SetIV(seqnr_payload);
64 
65  // block counter 0 for the poly1305 key
66  // use lower 32bytes for the poly1305 key
67  // (throws away 32 unused bytes (upper 32) from this ChaCha20 round)
69  m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key));
70 
71  // if decrypting, verify the tag prior to decryption
72  if (!is_encrypt) {
73  const uint8_t *tag = src + src_len - POLY1305_TAGLEN;
74  poly1305_auth(expected_tag, src, src_len - POLY1305_TAGLEN, poly_key);
75 
76  // constant time compare the calculated MAC with the provided MAC
77  if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
78  memory_cleanse(expected_tag, sizeof(expected_tag));
79  memory_cleanse(poly_key, sizeof(poly_key));
80  return false;
81  }
82  memory_cleanse(expected_tag, sizeof(expected_tag));
83  // MAC has been successfully verified, make sure we don't covert it in
84  // decryption
85  src_len -= POLY1305_TAGLEN;
86  }
87 
88  // calculate and cache the next 64byte keystream block if requested sequence
89  // number is not yet the cache
90  if (m_cached_aad_seqnr != seqnr_aad) {
91  m_cached_aad_seqnr = seqnr_aad;
92  m_chacha_header.SetIV(seqnr_aad);
96  }
97  // crypt the AAD (3 bytes message length) with given position in AAD cipher
98  // instance keystream
99  dest[0] = src[0] ^ m_aad_keystream_buffer[aad_pos];
100  dest[1] = src[1] ^ m_aad_keystream_buffer[aad_pos + 1];
101  dest[2] = src[2] ^ m_aad_keystream_buffer[aad_pos + 2];
102 
103  // Set the playload ChaCha instance block counter to 1 and crypt the payload
104  m_chacha_main.Seek(1);
108 
109  // If encrypting, calculate and append tag
110  if (is_encrypt) {
111  // the poly1305 tag expands over the AAD (3 bytes length) & encrypted
112  // payload
113  poly1305_auth(dest + src_len, dest, src_len, poly_key);
114  }
115 
116  // cleanse no longer required MAC and polykey
117  memory_cleanse(poly_key, sizeof(poly_key));
118  return true;
119 }
120 
121 bool ChaCha20Poly1305AEAD::GetLength(uint32_t *len24_out, uint64_t seqnr_aad,
122  int aad_pos, const uint8_t *ciphertext) {
123  // enforce valid aad position to avoid accessing outside of the 64byte
124  // keystream cache (there is space for 21 times 3 bytes)
125  assert(aad_pos >= 0 &&
127  if (m_cached_aad_seqnr != seqnr_aad) {
128  // we need to calculate the 64 keystream bytes since we reached a new
129  // aad sequence number
130  m_cached_aad_seqnr = seqnr_aad;
131  // use LE for the nonce
132  m_chacha_header.SetIV(seqnr_aad);
133  // block counter 0
135  // write keystream to the cache
138  }
139 
140  // decrypt the ciphertext length by XORing the right position of the 64byte
141  // keystream cache with the ciphertext
142  *len24_out = (ciphertext[0] ^ m_aad_keystream_buffer[aad_pos + 0]) |
143  (ciphertext[1] ^ m_aad_keystream_buffer[aad_pos + 1]) << 8 |
144  (ciphertext[2] ^ m_aad_keystream_buffer[aad_pos + 2]) << 16;
145 
146  return true;
147 }
void Keystream(uint8_t *c, size_t bytes)
outputs the keystream of size <bytes> into
Definition: chacha20.cpp:79
#define POLY1305_TAGLEN
Definition: poly1305.h:12
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
static constexpr int CHACHA20_POLY1305_AEAD_KEY_LEN
void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN])
Definition: poly1305.cpp:15
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
Definition: cleanse.cpp:14
static constexpr int CHACHA20_POLY1305_AEAD_AAD_LEN
bool Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, uint8_t *dest, size_t dest_len, const uint8_t *src, size_t src_len, bool is_encrypt)
Encrypts/decrypts a packet.
int timingsafe_bcmp(const uint8_t *b1, const uint8_t *b2, size_t n)
void Seek(uint64_t pos)
Definition: chacha20.cpp:74
void SetKey(const uint8_t *key, size_t keylen)
set key with flexible keylength; 256bit recommended
Definition: chacha20.cpp:32
ChaCha20Poly1305AEAD(const uint8_t *K_1, size_t K_1_len, const uint8_t *K_2, size_t K_2_len)
void Crypt(const uint8_t *input, uint8_t *output, size_t bytes)
enciphers the message <input> of length <bytes> and write the enciphered representation into <output>...
Definition: chacha20.cpp:194
static constexpr int CHACHA20_ROUND_OUTPUT
void SetIV(uint64_t iv)
Definition: chacha20.cpp:69
#define POLY1305_KEYLEN
Definition: poly1305.h:11
uint8_t m_aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]