chacha20poly1305.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2019 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_MODE_AEAD_CHACHA20_POLY1305_HPP
26 #define CRYPTO3_MODE_AEAD_CHACHA20_POLY1305_HPP
27 
29 
30 namespace nil {
31  namespace crypto3 {
32  namespace mac {
33  class poly_1305;
34  }
35  namespace stream {
36  template<std::size_t IVBits = 64, std::size_t KeyBits = 128, std::size_t Rounds = 20>
37  class chacha;
38 
39  namespace modes {
40  namespace detail {
41  template<typename Padding,
42  std::size_t NonceBits,
43  std::size_t TagBits,
44  typename StreamCipher,
45  typename MessageAuthenticationCode,
46  template<typename>
47  class Allocator>
49  typedef std::size_t size_type;
50 
51  typedef StreamCipher stream_cipher_type;
52  typedef MessageAuthenticationCode mac_type;
53  typedef Padding padding_type;
54 
55  constexpr static const std::size_t nonce_bits = NonceBits;
56  constexpr static const std::size_t nonce_size = nonce_bits / CHAR_BIT;
57  typedef std::array<std::uint8_t, nonce_size> nonce_type;
58 
59  BOOST_STATIC_ASSERT(nonce_bits == 8 * CHAR_BIT || nonce_bits == 12 * CHAR_BIT);
60 
61  typedef std::vector<boost::uint_t<CHAR_BIT>, Allocator<boost::uint_t<CHAR_BIT>>>
63  };
64 
65  template<typename Padding,
66  std::size_t NonceBits,
67  std::size_t TagBits,
68  typename StreamCipher,
69  typename MessageAuthenticationCode,
70  template<typename>
71  class Allocator>
73  : public chacha20poly1305_policy<Padding,
74  NonceBits,
75  TagBits,
76  StreamCipher,
77  MessageAuthenticationCode,
78  Allocator> {
79  typedef chacha20poly1305_policy<Padding,
80  NonceBits,
81  TagBits,
82  StreamCipher,
83  MessageAuthenticationCode,
84  Allocator>
86 
89 
92 
93  constexpr static const std::size_t block_bits = policy_type::block_bits;
94  constexpr static const std::size_t block_words = policy_type::block_words;
95  typedef typename policy_type::block_type block_type;
96 
97  inline static block_type begin_message(const stream_cipher_type &cipher,
98  const block_type &plaintext) {
99  block_type block = {0};
100 
101  m_ctext_len = 0;
102  m_nonce_len = nonce_len;
103 
104  m_chacha->set_iv(nonce, nonce_len);
105 
106  secure_vector<uint8_t> init(64); // zeros
107  m_chacha->encrypt(init);
108 
109  m_poly1305->set_key(init.data(), 32);
110  // Remainder of output is discard
111 
112  m_poly1305->update(m_ad);
113 
114  if (cfrg_version()) {
115  if (m_ad.size() % 16) {
116  const uint8_t zeros[16] = {0};
117  m_poly1305->update(zeros, 16 - m_ad.size() % 16);
118  }
119  } else {
120  update_len(m_ad.size());
121  }
122 
123  return cipher.encrypt(block);
124  }
125 
126  inline static block_type process_block(const stream_cipher_type &cipher,
127  const block_type &plaintext) {
128  block_type block = {0};
129 
130  m_chacha->cipher1(buf, sz);
131  m_poly1305->update(buf, sz); // poly1305 of ciphertext
132  m_ctext_len += sz;
133 
134  return cipher.encrypt(block);
135  }
136 
137  inline static block_type end_message(const stream_cipher_type &cipher,
138  const block_type &plaintext) {
139  block_type result = {0};
140 
141  update(buffer, offset);
142  if (cfrg_version()) {
143  if (m_ctext_len % 16) {
144  const uint8_t zeros[16] = {0};
145  m_poly1305->update(zeros, 16 - m_ctext_len % 16);
146  }
147  update_len(m_ad.size());
148  }
149  update_len(m_ctext_len);
150 
151  const secure_vector<uint8_t> mac = m_poly1305->final();
152  buffer += std::make_pair(mac.data(), tag_size());
153  m_ctext_len = 0;
154 
155  return result;
156  }
157  };
158 
159  template<typename Padding,
160  std::size_t NonceBits,
161  std::size_t TagBits,
162  typename StreamCipher,
163  typename MessageAuthenticationCode,
164  template<typename>
165  class Allocator>
167  : public chacha20poly1305_policy<Padding,
168  NonceBits,
169  TagBits,
170  StreamCipher,
171  MessageAuthenticationCode,
172  Allocator> {
173  typedef chacha20poly1305_policy<Padding,
174  NonceBits,
175  TagBits,
176  StreamCipher,
177  MessageAuthenticationCode,
178  Allocator>
180 
183 
186 
187  constexpr static const std::size_t block_bits = policy_type::block_bits;
188  constexpr static const std::size_t block_words = policy_type::block_words;
189  typedef typename policy_type::block_type block_type;
190 
191  inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext) {
192  block_type block = {0};
193 
194  m_ctext_len = 0;
195  m_nonce_len = nonce_len;
196 
197  m_chacha->set_iv(nonce, nonce_len);
198 
199  secure_vector<uint8_t> init(64); // zeros
200  m_chacha->encrypt(init);
201 
202  m_poly1305->set_key(init.data(), 32);
203  // Remainder of output is discard
204 
205  m_poly1305->update(m_ad);
206 
207  if (cfrg_version()) {
208  if (m_ad.size() % 16) {
209  const uint8_t zeros[16] = {0};
210  m_poly1305->update(zeros, 16 - m_ad.size() % 16);
211  }
212  } else {
213  update_len(m_ad.size());
214  }
215 
216  return cipher.encrypt(block);
217  }
218 
219  inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext) {
220  block_type block = {0};
221 
222  m_poly1305->update(buf, sz); // poly1305 of ciphertext
223  m_chacha->cipher1(buf, sz);
224  m_ctext_len += sz;
225 
226  return cipher.encrypt(block);
227  }
228 
229  inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
230  block_type result = {0};
231 
232  BOOST_ASSERT_MSG(buffer.size() >= offset, "Offset is sane");
233  const size_t sz = buffer.size() - offset;
234  uint8_t *buf = buffer.data() + offset;
235 
236  BOOST_ASSERT_MSG(sz >= tag_size(), "Have the tag as part of final input");
237 
238  const size_t remaining = sz - tag_size();
239 
240  if (remaining) {
241  m_poly1305->update(buf, remaining); // poly1305 of ciphertext
242  m_chacha->cipher1(buf, remaining);
243  m_ctext_len += remaining;
244  }
245 
246  if (cfrg_version()) {
247  if (m_ctext_len % 16) {
248  const uint8_t zeros[16] = {0};
249  m_poly1305->update(zeros, 16 - m_ctext_len % 16);
250  }
251  update_len(m_ad.size());
252  }
253 
254  update_len(m_ctext_len);
255  const secure_vector<uint8_t> mac = m_poly1305->final();
256 
257  const uint8_t *included_tag = &buf[remaining];
258 
259  m_ctext_len = 0;
260 
261  if (!constant_time_compare(mac.data(), included_tag, tag_size())) {
262  throw integrity_failure("ChaCha20Poly1305 tag check failed");
263  }
264  buffer.resize(offset + remaining);
265 
266  return result;
267  }
268  };
269 
270  template<typename Policy>
272  typedef Policy policy_type;
273 
274  public:
275  typedef typename policy_type::stream_cipher_type stream_cipher_type;
276  typedef typename policy_type::padding_type padding_type;
277  typedef typename policy_type::mac_type mac_type;
278 
279  typedef typename stream_cipher_type::key_type key_type;
280  typedef typename policy_type::associated_data_type associated_data_type;
281 
282  constexpr static const std::size_t block_bits = policy_type::block_bits;
283  constexpr static const std::size_t block_words = policy_type::block_words;
284  typedef typename stream_cipher_type::block_type block_type;
285 
286  template<typename AssociatedDataContainer>
288  const AssociatedDataContainer &associated_data) :
289  cipher(cipher) {
290  schedule_associated_data(associated_data);
291  }
292 
293  inline block_type begin_message(const block_type &plaintext) {
294  return policy_type::begin_message(cipher, plaintext, ad);
295  }
296 
297  inline block_type process_block(const block_type &plaintext) {
298  return policy_type::process_block(cipher, plaintext, ad);
299  }
300 
301  inline block_type end_message(const block_type &plaintext) {
302  return policy_type::end_message(cipher, plaintext, ad);
303  }
304 
305  inline static std::size_t required_output_size(std::size_t inputlen) {
306  return padding_type::required_output_size(inputlen);
307  }
308 
309  protected:
310  template<typename AssociatedDataContainer>
311  inline void schedule_associated_data(const AssociatedDataContainer &iad) {
312  }
313 
315 
318  };
319  } // namespace detail
320 
330  template<template<typename> class Padding,
331  std::size_t NonceBits,
332  std::size_t TagBits = 16 * CHAR_BIT,
333  typename StreamCipher = stream::chacha<>,
334  typename MessageAuthenticationCode = mac::poly_1305,
335  template<typename> class Allocator = std::allocator>
337  typedef StreamCipher stream_cipher_type;
338  typedef MessageAuthenticationCode mac_type;
339  typedef Padding<StreamCipher> padding_type;
340 
342  NonceBits,
343  TagBits,
345  mac_type,
346  Allocator>
349  NonceBits,
350  TagBits,
352  mac_type,
353  Allocator>
355 
356  template<template<typename, typename, std::size_t, std::size_t, template<typename> class>
357  class Policy>
358  struct bind {
359  typedef detail::chacha20poly1305<
360  Policy<stream_cipher_type, padding_type, NonceBits, TagBits, Allocator>>
362  };
363  };
364  } // namespace modes
365  } // namespace stream
366  } // namespace crypto3
367 } // namespace nil
368 
369 #endif
DJB's Poly1305.
Definition: poly1305.hpp:40
DJB's ChaCha (https://cr.yp.to/chacha.html)
Definition: chacha.hpp:69
Definition: chacha20poly1305.hpp:271
block_type begin_message(const block_type &plaintext)
Definition: chacha20poly1305.hpp:293
policy_type::mac_type mac_type
Definition: chacha20poly1305.hpp:277
constexpr static const std::size_t block_words
Definition: chacha20poly1305.hpp:283
block_type process_block(const block_type &plaintext)
Definition: chacha20poly1305.hpp:297
policy_type::padding_type padding_type
Definition: chacha20poly1305.hpp:276
mac_type mac
Definition: chacha20poly1305.hpp:317
void schedule_associated_data(const AssociatedDataContainer &iad)
Definition: chacha20poly1305.hpp:311
stream_cipher_type::key_type key_type
Definition: chacha20poly1305.hpp:279
associated_data_type ad
Definition: chacha20poly1305.hpp:314
policy_type::stream_cipher_type stream_cipher_type
Definition: chacha20poly1305.hpp:275
constexpr static const std::size_t block_bits
Definition: chacha20poly1305.hpp:282
stream_cipher_type cipher
Definition: chacha20poly1305.hpp:316
stream_cipher_type::block_type block_type
Definition: chacha20poly1305.hpp:284
static std::size_t required_output_size(std::size_t inputlen)
Definition: chacha20poly1305.hpp:305
policy_type::associated_data_type associated_data_type
Definition: chacha20poly1305.hpp:280
block_type end_message(const block_type &plaintext)
Definition: chacha20poly1305.hpp:301
chacha20poly1305(const stream_cipher_type &cipher, const AssociatedDataContainer &associated_data)
Definition: chacha20poly1305.hpp:287
boost::mpl::apply< AccumulatorSet, tag::mac< ProcessingPolicy > >::type::result_type mac(const AccumulatorSet &acc)
Definition: accumulators/mac.hpp:99
boost::mpl::apply< AccumulatorSet, tag::block< Mode > >::type::result_type block(const AccumulatorSet &acc)
Definition: accumulators/block.hpp:259
boost::mpl::apply< AccumulatorSet, tag::stream< Mode > >::type::result_type stream(const AccumulatorSet &acc)
Definition: accumulators/stream.hpp:175
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: memory_operations.hpp:143
Definition: pair.hpp:31
Definition: chacha20poly1305.hpp:358
detail::chacha20poly1305< Policy< stream_cipher_type, padding_type, NonceBits, TagBits, Allocator > > type
Definition: chacha20poly1305.hpp:361
See draft-irtf-cfrg-chacha20-poly1305-03 for specification If a nonce of 64 bits is used the older ve...
Definition: chacha20poly1305.hpp:336
detail::chacha20poly1305_encryption_policy< padding_type, NonceBits, TagBits, stream_cipher_type, mac_type, Allocator > encryption_policy
Definition: chacha20poly1305.hpp:347
StreamCipher stream_cipher_type
Definition: chacha20poly1305.hpp:337
detail::chacha20poly1305_decryption_policy< padding_type, NonceBits, TagBits, stream_cipher_type, mac_type, Allocator > decryption_policy
Definition: chacha20poly1305.hpp:354
MessageAuthenticationCode mac_type
Definition: chacha20poly1305.hpp:338
Padding< StreamCipher > padding_type
Definition: chacha20poly1305.hpp:339
policy_type::associated_data_type associated_data_type
Definition: chacha20poly1305.hpp:184
static block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: chacha20poly1305.hpp:191
static block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: chacha20poly1305.hpp:229
static block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: chacha20poly1305.hpp:219
policy_type::nonce_type nonce_type
Definition: chacha20poly1305.hpp:185
constexpr static const std::size_t block_words
Definition: chacha20poly1305.hpp:188
policy_type::padding_type padding_type
Definition: chacha20poly1305.hpp:182
policy_type::stream_cipher_type cipher_type
Definition: chacha20poly1305.hpp:181
chacha20poly1305_policy< Padding, NonceBits, TagBits, StreamCipher, MessageAuthenticationCode, Allocator > policy_type
Definition: chacha20poly1305.hpp:179
policy_type::block_type block_type
Definition: chacha20poly1305.hpp:189
constexpr static const std::size_t block_bits
Definition: chacha20poly1305.hpp:187
static block_type begin_message(const stream_cipher_type &cipher, const block_type &plaintext)
Definition: chacha20poly1305.hpp:97
static block_type process_block(const stream_cipher_type &cipher, const block_type &plaintext)
Definition: chacha20poly1305.hpp:126
policy_type::stream_cipher_type stream_cipher_type
Definition: chacha20poly1305.hpp:87
policy_type::padding_type padding_type
Definition: chacha20poly1305.hpp:88
static block_type end_message(const stream_cipher_type &cipher, const block_type &plaintext)
Definition: chacha20poly1305.hpp:137
constexpr static const std::size_t block_bits
Definition: chacha20poly1305.hpp:93
policy_type::nonce_type nonce_type
Definition: chacha20poly1305.hpp:91
policy_type::block_type block_type
Definition: chacha20poly1305.hpp:95
chacha20poly1305_policy< Padding, NonceBits, TagBits, StreamCipher, MessageAuthenticationCode, Allocator > policy_type
Definition: chacha20poly1305.hpp:85
constexpr static const std::size_t block_words
Definition: chacha20poly1305.hpp:94
policy_type::associated_data_type associated_data_type
Definition: chacha20poly1305.hpp:90
MessageAuthenticationCode mac_type
Definition: chacha20poly1305.hpp:52
std::size_t size_type
Definition: chacha20poly1305.hpp:49
constexpr static const std::size_t nonce_bits
Definition: chacha20poly1305.hpp:55
BOOST_STATIC_ASSERT(nonce_bits==8 *CHAR_BIT||nonce_bits==12 *CHAR_BIT)
Padding padding_type
Definition: chacha20poly1305.hpp:53
std::array< std::uint8_t, nonce_size > nonce_type
Definition: chacha20poly1305.hpp:57
StreamCipher stream_cipher_type
Definition: chacha20poly1305.hpp:51
constexpr static const std::size_t nonce_size
Definition: chacha20poly1305.hpp:56
std::vector< boost::uint_t< CHAR_BIT >, Allocator< boost::uint_t< CHAR_BIT > > > associated_data_type
Definition: chacha20poly1305.hpp:62