Botan  2.6.0
Crypto and TLS for C++11
chacha20poly1305.cpp
Go to the documentation of this file.
1 /*
2 * ChaCha20Poly1305 AEAD
3 * (C) 2014,2016 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 
11 namespace Botan {
12 
14  m_chacha(StreamCipher::create("ChaCha")),
15  m_poly1305(MessageAuthenticationCode::create("Poly1305"))
16  {
17  if(!m_chacha || !m_poly1305)
18  throw Algorithm_Not_Found("ChaCha20Poly1305");
19  }
20 
22  {
23  return (n == 8 || n == 12);
24  }
25 
27  {
28  m_chacha->clear();
29  m_poly1305->clear();
30  reset();
31  }
32 
34  {
35  m_ad.clear();
36  m_ctext_len = 0;
37  m_nonce_len = 0;
38  }
39 
40 void ChaCha20Poly1305_Mode::key_schedule(const uint8_t key[], size_t length)
41  {
42  m_chacha->set_key(key, length);
43  }
44 
45 void ChaCha20Poly1305_Mode::set_associated_data(const uint8_t ad[], size_t length)
46  {
47  if(m_ctext_len)
48  throw Exception("Too late to set AD for ChaCha20Poly1305");
49  m_ad.assign(ad, ad + length);
50  }
51 
53  {
54  uint8_t len8[8] = { 0 };
55  store_le(static_cast<uint64_t>(len), len8);
56  m_poly1305->update(len8, 8);
57  }
58 
59 void ChaCha20Poly1305_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
60  {
61  if(!valid_nonce_length(nonce_len))
62  throw Invalid_IV_Length(name(), nonce_len);
63 
64  m_ctext_len = 0;
65  m_nonce_len = nonce_len;
66 
67  m_chacha->set_iv(nonce, nonce_len);
68 
69  secure_vector<uint8_t> init(64); // zeros
70  m_chacha->encrypt(init);
71 
72  m_poly1305->set_key(init.data(), 32);
73  // Remainder of output is discard
74 
75  m_poly1305->update(m_ad);
76 
77  if(cfrg_version())
78  {
79  if(m_ad.size() % 16)
80  {
81  const uint8_t zeros[16] = { 0 };
82  m_poly1305->update(zeros, 16 - m_ad.size() % 16);
83  }
84  }
85  else
86  {
87  update_len(m_ad.size());
88  }
89  }
90 
91 size_t ChaCha20Poly1305_Encryption::process(uint8_t buf[], size_t sz)
92  {
93  m_chacha->cipher1(buf, sz);
94  m_poly1305->update(buf, sz); // poly1305 of ciphertext
95  m_ctext_len += sz;
96  return sz;
97  }
98 
100  {
101  update(buffer, offset);
102  if(cfrg_version())
103  {
104  if(m_ctext_len % 16)
105  {
106  const uint8_t zeros[16] = { 0 };
107  m_poly1305->update(zeros, 16 - m_ctext_len % 16);
108  }
109  update_len(m_ad.size());
110  }
112 
113  const secure_vector<uint8_t> mac = m_poly1305->final();
114  buffer += std::make_pair(mac.data(), tag_size());
115  m_ctext_len = 0;
116  }
117 
118 size_t ChaCha20Poly1305_Decryption::process(uint8_t buf[], size_t sz)
119  {
120  m_poly1305->update(buf, sz); // poly1305 of ciphertext
121  m_chacha->cipher1(buf, sz);
122  m_ctext_len += sz;
123  return sz;
124  }
125 
127  {
128  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
129  const size_t sz = buffer.size() - offset;
130  uint8_t* buf = buffer.data() + offset;
131 
132  BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input");
133 
134  const size_t remaining = sz - tag_size();
135 
136  if(remaining)
137  {
138  m_poly1305->update(buf, remaining); // poly1305 of ciphertext
139  m_chacha->cipher1(buf, remaining);
140  m_ctext_len += remaining;
141  }
142 
143  if(cfrg_version())
144  {
145  if(m_ctext_len % 16)
146  {
147  const uint8_t zeros[16] = { 0 };
148  m_poly1305->update(zeros, 16 - m_ctext_len % 16);
149  }
150  update_len(m_ad.size());
151  }
152 
154  const secure_vector<uint8_t> mac = m_poly1305->final();
155 
156  const uint8_t* included_tag = &buf[remaining];
157 
158  m_ctext_len = 0;
159 
160  if(!constant_time_compare(mac.data(), included_tag, tag_size()))
161  throw Integrity_Failure("ChaCha20Poly1305 tag check failed");
162  buffer.resize(offset + remaining);
163  }
164 
165 }
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:115
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:51
std::unique_ptr< StreamCipher > m_chacha
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:30
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
bool valid_nonce_length(size_t n) const override
std::string name() const override
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
void store_le(uint16_t in, uint8_t out[2])
Definition: loadstor.h:450