Botan  2.19.1
Crypto and TLS for C++11
chacha20poly1305.cpp
Go to the documentation of this file.
1 /*
2 * ChaCha20Poly1305 AEAD
3 * (C) 2014,2016,2018 Jack Lloyd
4 * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/chacha20poly1305.h>
10 #include <botan/loadstor.h>
11 
12 namespace Botan {
13 
15  m_chacha(StreamCipher::create("ChaCha")),
16  m_poly1305(MessageAuthenticationCode::create("Poly1305"))
17  {
18  if(!m_chacha || !m_poly1305)
19  throw Algorithm_Not_Found("ChaCha20Poly1305");
20  }
21 
23  {
24  return (n == 8 || n == 12 || n == 24);
25  }
26 
28  {
29  m_chacha->clear();
30  m_poly1305->clear();
31  reset();
32  }
33 
35  {
36  m_ad.clear();
37  m_ctext_len = 0;
38  m_nonce_len = 0;
39  }
40 
41 void ChaCha20Poly1305_Mode::key_schedule(const uint8_t key[], size_t length)
42  {
43  m_chacha->set_key(key, length);
44  }
45 
46 void ChaCha20Poly1305_Mode::set_associated_data(const uint8_t ad[], size_t length)
47  {
48  if(m_ctext_len > 0 || m_nonce_len > 0)
49  throw Invalid_State("Cannot set AD for ChaCha20Poly1305 while processing a message");
50  m_ad.assign(ad, ad + length);
51  }
52 
54  {
55  uint8_t len8[8] = { 0 };
56  store_le(static_cast<uint64_t>(len), len8);
57  m_poly1305->update(len8, 8);
58  }
59 
60 void ChaCha20Poly1305_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
61  {
62  if(!valid_nonce_length(nonce_len))
63  throw Invalid_IV_Length(name(), nonce_len);
64 
65  m_ctext_len = 0;
66  m_nonce_len = nonce_len;
67 
68  m_chacha->set_iv(nonce, nonce_len);
69 
70  uint8_t first_block[64];
71  m_chacha->write_keystream(first_block, sizeof(first_block));
72 
73  m_poly1305->set_key(first_block, 32);
74  // Remainder of first block is discarded
75  secure_scrub_memory(first_block, sizeof(first_block));
76 
77  m_poly1305->update(m_ad);
78 
79  if(cfrg_version())
80  {
81  if(m_ad.size() % 16)
82  {
83  const uint8_t zeros[16] = { 0 };
84  m_poly1305->update(zeros, 16 - m_ad.size() % 16);
85  }
86  }
87  else
88  {
89  update_len(m_ad.size());
90  }
91  }
92 
93 size_t ChaCha20Poly1305_Encryption::process(uint8_t buf[], size_t sz)
94  {
95  m_chacha->cipher1(buf, sz);
96  m_poly1305->update(buf, sz); // poly1305 of ciphertext
97  m_ctext_len += sz;
98  return sz;
99  }
100 
102  {
103  update(buffer, offset);
104  if(cfrg_version())
105  {
106  if(m_ctext_len % 16)
107  {
108  const uint8_t zeros[16] = { 0 };
109  m_poly1305->update(zeros, 16 - m_ctext_len % 16);
110  }
111  update_len(m_ad.size());
112  }
114 
115  buffer.resize(buffer.size() + tag_size());
116  m_poly1305->final(&buffer[buffer.size() - tag_size()]);
117  m_ctext_len = 0;
118  m_nonce_len = 0;
119  }
120 
121 size_t ChaCha20Poly1305_Decryption::process(uint8_t buf[], size_t sz)
122  {
123  m_poly1305->update(buf, sz); // poly1305 of ciphertext
124  m_chacha->cipher1(buf, sz);
125  m_ctext_len += sz;
126  return sz;
127  }
128 
130  {
131  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
132  const size_t sz = buffer.size() - offset;
133  uint8_t* buf = buffer.data() + offset;
134 
135  BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input");
136 
137  const size_t remaining = sz - tag_size();
138 
139  if(remaining)
140  {
141  m_poly1305->update(buf, remaining); // poly1305 of ciphertext
142  m_chacha->cipher1(buf, remaining);
143  m_ctext_len += remaining;
144  }
145 
146  if(cfrg_version())
147  {
148  if(m_ctext_len % 16)
149  {
150  const uint8_t zeros[16] = { 0 };
151  m_poly1305->update(zeros, 16 - m_ctext_len % 16);
152  }
153  update_len(m_ad.size());
154  }
155 
157 
158  uint8_t mac[16];
159  m_poly1305->final(mac);
160 
161  const uint8_t* included_tag = &buf[remaining];
162 
163  m_ctext_len = 0;
164  m_nonce_len = 0;
165 
166  if(!constant_time_compare(mac, included_tag, tag_size()))
167  throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed");
168  buffer.resize(offset + remaining);
169  }
170 
171 }
size_t process(uint8_t buf[], size_t size) override
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
size_t process(uint8_t buf[], size_t size) override
std::unique_ptr< MessageAuthenticationCode > m_poly1305
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
void update(secure_vector< uint8_t > &buffer, size_t offset=0)
Definition: cipher_mode.h:112
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
std::unique_ptr< StreamCipher > m_chacha
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:65
size_t tag_size() const override
secure_vector< uint8_t > m_ad
Definition: alg_id.cpp:13
void set_associated_data(const uint8_t ad[], size_t ad_len) override
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:66
bool valid_nonce_length(size_t n) const override
std::string name() const override
void store_le(uint16_t in, uint8_t out[2])
Definition: loadstor.h:454