gcm.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_GCM_HPP
26 #define CRYPTO3_MODE_AEAD_GCM_HPP
27 
29 
30 #include <nil/crypto3/hash/ghash.hpp>
31 
32 namespace nil {
33  namespace crypto3 {
34  namespace hashes {
35  struct ghash;
36  }
37  namespace stream {
38  template<typename BlockCipher>
39  class ctr;
40  }
41  namespace block {
42  namespace modes {
43  namespace detail {
44  template<typename Cipher, std::size_t TagBits, typename Padding, typename StreamCipher,
45  typename Hash, template<typename> class Allocator>
46  struct gcm_policy {
47  typedef Cipher cipher_type;
48  typedef Padding padding_type;
49  typedef StreamCipher stream_cipher_type;
50  typedef Hash hash_type;
51 
52  template<typename T>
53  using allocator_type = Allocator<T>;
54 
55  constexpr static const std::size_t tag_bits = TagBits;
56 
57  BOOST_STATIC_ASSERT(tag_bits >= 12 * CHAR_BIT && tag_bits <= 16 * CHAR_BIT);
58 
59  constexpr static const std::size_t block_bits = cipher_type::block_bits;
60  constexpr static const std::size_t block_words = cipher_type::block_words;
61  typedef typename cipher_type::block_type block_type;
62 
64 
65  typedef std::vector<boost::uint_t<CHAR_BIT>, allocator_type<boost::uint_t<CHAR_BIT>>>
67  typedef std::vector<boost::uint_t<CHAR_BIT>, allocator_type<boost::uint_t<CHAR_BIT>>>
69 
70  inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext) {
71  block_type block = {0};
72 
73  // any size is valid for GCM nonce
74 
75  secure_vector<uint8_t> y0(GCM_BS);
76 
77  if (nonce_len == 12) {
78  copy_mem(y0.data(), nonce, nonce_len);
79  y0[15] = 1;
80  } else {
81  y0 = m_ghash->nonce_hash(nonce, nonce_len);
82  }
83 
84  m_ctr->set_iv(y0.data(), y0.size());
85 
86  zeroise(y0);
87  m_ctr->encipher(y0);
88 
89  m_ghash->start(y0.data(), y0.size());
90 
91  return cipher.encrypt(block);
92  }
93  };
94 
95  template<typename Cipher, std::size_t TagBits, typename Padding, typename StreamCipher,
96  typename Hash, template<typename> class Allocator>
98  : public gcm_policy<Cipher, TagBits, Padding, StreamCipher, Hash, Allocator> {
100 
101  public:
106 
109 
110  constexpr static const std::size_t tag_bits = policy_type::tag_bits;
111 
112  constexpr static const std::size_t block_bits = policy_type::block_bits;
113  constexpr static const std::size_t block_words = policy_type::block_words;
115 
116  inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext) {
117  return policy_type::begin_message(cipher, plaintext);
118  }
119 
120  inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext) {
121  block_type block = {0};
122 
123  CRYPTO3_ARG_CHECK(sz % update_granularity() == 0);
124  m_ctr->cipher(buf, buf, sz);
125  m_ghash->update(buf, sz);
126 
127  return cipher.encrypt(block);
128  }
129 
130  inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
131  block_type result = {0};
132 
133  CRYPTO3_ARG_CHECK(offset <= buffer.size());
134  const size_t sz = buffer.size() - offset;
135  uint8_t *buf = buffer.data() + offset;
136 
137  m_ctr->cipher(buf, buf, sz);
138  m_ghash->update(buf, sz);
139  auto mac = m_ghash->final();
140  buffer += std::make_pair(mac.data(), tag_size());
141 
142  return result;
143  }
144  };
145 
146  template<typename Cipher, std::size_t TagBits, typename Padding, typename StreamCipher,
147  typename Hash, template<typename> class Allocator>
149  : public gcm_policy<Cipher, TagBits, Padding, StreamCipher, Hash, Allocator> {
151 
152  public:
157 
160 
161  constexpr static const std::size_t tag_bits = policy_type::tag_bits;
162 
163  constexpr static const std::size_t block_bits = policy_type::block_bits;
164  constexpr static const std::size_t block_words = policy_type::block_words;
166 
167  inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext) {
168  return policy_type::begin_message(cipher, plaintext);
169  }
170 
171  inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext) {
172  block_type block = {0};
173 
174  CRYPTO3_ARG_CHECK(sz % update_granularity() == 0);
175  m_ghash->update(buf, sz);
176  m_ctr->cipher(buf, buf, sz);
177 
178  return cipher.encrypt(block);
179  }
180 
181  inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
182  block_type result = {0};
183 
184  CRYPTO3_ARG_CHECK(offset <= buffer.size());
185  const size_t sz = buffer.size() - offset;
186  uint8_t *buf = buffer.data() + offset;
187 
188  if (sz < tag_size()) {
189  throw Exception("Insufficient input for GCM decryption, tag missing");
190  }
191 
192  const size_t remaining = sz - tag_size();
193 
194  // handle any final input before the tag
195  if (remaining) {
196  m_ghash->update(buf, remaining);
197  m_ctr->cipher(buf, buf, remaining);
198  }
199 
200  auto mac = m_ghash->final();
201 
202  const uint8_t *included_tag = &buffer[remaining + offset];
203 
204  if (!constant_time_compare(mac.data(), included_tag, tag_size())) {
205  throw integrity_failure("GCM tag check failed");
206  }
207 
208  buffer.resize(offset + remaining);
209 
210  return result;
211  }
212  };
213 
214  template<typename Policy>
215  class gcm {
216  typedef Policy policy_type;
217 
218  public:
219  typedef typename policy_type::cipher_type cipher_type;
220  typedef typename policy_type::padding_type padding_type;
221 
222  typedef typename cipher_type::key_type key_type;
223  typedef typename policy_type::associated_data_type associated_data_type;
224  typedef typename policy_type::nonce_type nonce_type;
225 
226  constexpr static const std::size_t block_bits = policy_type::block_bits;
227  constexpr static const std::size_t block_words = policy_type::block_words;
228  typedef typename cipher_type::block_type block_type;
229 
230  template<typename AssociatedDataContainer>
231  gcm(const cipher_type &cipher, const AssociatedDataContainer &associated_data) :
232  cipher(cipher) {
233  schedule_associated_data(associated_data);
234  }
235 
236  template<typename AssociatedDataContainer>
237  gcm(const key_type &key, const AssociatedDataContainer &associated_data) : cipher(key) {
238 
239  m_ctr->set_key(key, keylen);
240 
241  const std::vector<uint8_t> zeros(GCM_BS);
242  m_ctr->set_iv(zeros.data(), zeros.size());
243 
244  secure_vector<uint8_t> H(GCM_BS);
245  m_ctr->encipher(H);
246  m_ghash->set_key(H);
247 
248  schedule_associated_data(associated_data);
249  }
250 
251  inline block_type begin_message(const block_type &plaintext) {
252  return policy_type::begin_message(cipher, plaintext, ad);
253  }
254 
255  inline block_type process_block(const block_type &plaintext) {
256  return policy_type::process_block(cipher, plaintext, ad);
257  }
258 
259  inline block_type end_message(const block_type &plaintext) {
260  return policy_type::end_message(cipher, plaintext, ad);
261  }
262 
263  inline static std::size_t required_output_size(std::size_t inputlen) {
264  return padding_type::required_output_size(inputlen);
265  }
266 
267  protected:
268  template<typename AssociatedDataContainer>
269  inline void schedule_associated_data(const AssociatedDataContainer &iad) {
270  m_ghash->set_associated_data(ad, ad_len);
271  }
272 
275 
277  };
278  } // namespace detail
279 
288  template<typename BlockCipher, template<typename> class Padding, std::size_t TagBits = 16,
289 
290  typename Hash = hashes::ghash, typename StreamCipher = stream::ctr<BlockCipher>,
291  template<typename> class Allocator = std::allocator>
292  struct gcm {
294  typedef Padding<BlockCipher> padding_type;
295  typedef StreamCipher stream_cipher_type;
296  typedef Hash hash_type;
297 
298  template<typename T>
299  using allocator_type = Allocator<T>;
300 
307 
308  template<template<typename, std::size_t, typename, typename, typename, template<typename> class>
309  class Policy>
310  struct bind {
311  typedef detail::gcm<
312  Policy<cipher_type, TagBits, padding_type, stream_cipher_type, hash_type, allocator_type>>
314  };
315  };
316  } // namespace modes
317  } // namespace block
318  } // namespace crypto3
319 } // namespace nil
320 
321 #endif
policy_type::stream_cipher_type stream_cipher_type
Definition: gcm.hpp:104
constexpr static const std::size_t block_words
Definition: gcm.hpp:113
policy_type::block_type block_type
Definition: gcm.hpp:114
constexpr static const std::size_t tag_bits
Definition: gcm.hpp:110
policy_type::associated_data_type associated_data_type
Definition: gcm.hpp:107
policy_type::nonce_type nonce_type
Definition: gcm.hpp:108
static block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:116
policy_type::padding_type padding_type
Definition: gcm.hpp:103
static block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:130
constexpr static const std::size_t block_bits
Definition: gcm.hpp:112
policy_type::hash_type hash_type
Definition: gcm.hpp:105
policy_type::cipher_type cipher_type
Definition: gcm.hpp:102
static block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:120
constexpr static const std::size_t block_words
Definition: gcm.hpp:227
block_type process_block(const block_type &plaintext)
Definition: gcm.hpp:255
cipher_type::block_type block_type
Definition: gcm.hpp:228
static std::size_t required_output_size(std::size_t inputlen)
Definition: gcm.hpp:263
block_type end_message(const block_type &plaintext)
Definition: gcm.hpp:259
nonce_type nonce
Definition: gcm.hpp:274
policy_type::cipher_type cipher_type
Definition: gcm.hpp:219
associated_data_type ad
Definition: gcm.hpp:273
void schedule_associated_data(const AssociatedDataContainer &iad)
Definition: gcm.hpp:269
policy_type::padding_type padding_type
Definition: gcm.hpp:220
constexpr static const std::size_t block_bits
Definition: gcm.hpp:226
policy_type::nonce_type nonce_type
Definition: gcm.hpp:224
cipher_type::key_type key_type
Definition: gcm.hpp:222
gcm(const cipher_type &cipher, const AssociatedDataContainer &associated_data)
Definition: gcm.hpp:231
block_type begin_message(const block_type &plaintext)
Definition: gcm.hpp:251
cipher_type cipher
Definition: gcm.hpp:276
gcm(const key_type &key, const AssociatedDataContainer &associated_data)
Definition: gcm.hpp:237
policy_type::associated_data_type associated_data_type
Definition: gcm.hpp:223
Definition: eax.hpp:39
counter< Cipher, Padding, CiphertextStealingMode > ctr
Definition: ctr.hpp:531
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
boost::accumulators::accumulator_set< mac::digest< MessageAuthenticationCode::input_block_bits >, boost::accumulators::features< accumulators::tag::mac< MessageAuthenticationCode > >> BlockCipher
Definition: cbc_mac_state.hpp:40
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: memory_operations.hpp:143
void copy_mem(T *out, const T *in, size_t n)
Definition: memory_operations.hpp:186
Definition: pair.hpp:31
Definition: cipher.hpp:38
policy_type::hash_type hash_type
Definition: gcm.hpp:156
policy_type::associated_data_type associated_data_type
Definition: gcm.hpp:158
constexpr static const std::size_t tag_bits
Definition: gcm.hpp:161
policy_type::nonce_type nonce_type
Definition: gcm.hpp:159
policy_type::cipher_type cipher_type
Definition: gcm.hpp:153
constexpr static const std::size_t block_bits
Definition: gcm.hpp:163
static block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:181
gcm_policy< Cipher, TagBits, Padding, StreamCipher, Hash, Allocator > policy_type
Definition: gcm.hpp:150
static block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:171
constexpr static const std::size_t block_words
Definition: gcm.hpp:164
policy_type::block_type block_type
Definition: gcm.hpp:165
policy_type::padding_type padding_type
Definition: gcm.hpp:154
policy_type::stream_cipher_type stream_cipher_type
Definition: gcm.hpp:155
static block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:167
BOOST_STATIC_ASSERT(tag_bits >=12 *CHAR_BIT &&tag_bits<=16 *CHAR_BIT)
Cipher cipher_type
Definition: gcm.hpp:47
std::vector< boost::uint_t< CHAR_BIT >, allocator_type< boost::uint_t< CHAR_BIT > > > nonce_type
Definition: gcm.hpp:68
constexpr static const std::size_t block_words
Definition: gcm.hpp:60
StreamCipher stream_cipher_type
Definition: gcm.hpp:49
Padding padding_type
Definition: gcm.hpp:48
cipher_type::block_type block_type
Definition: gcm.hpp:61
static block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: gcm.hpp:70
constexpr static const std::size_t block_bits
Definition: gcm.hpp:59
std::vector< boost::uint_t< CHAR_BIT >, allocator_type< boost::uint_t< CHAR_BIT > > > associated_data_type
Definition: gcm.hpp:66
Allocator< T > allocator_type
Definition: gcm.hpp:53
constexpr static const std::size_t tag_bits
Definition: gcm.hpp:55
detail::gcm< Policy< cipher_type, TagBits, padding_type, stream_cipher_type, hash_type, allocator_type > > type
Definition: gcm.hpp:313
Galois/Counter Mode.
Definition: gcm.hpp:292
Hash hash_type
Definition: gcm.hpp:296
detail::gcm_decryption_policy< cipher_type, TagBits, padding_type, stream_cipher_type, hash_type, allocator_type > decryption_policy
Definition: gcm.hpp:306
Padding< BlockCipher > padding_type
Definition: gcm.hpp:294
detail::gcm_encryption_policy< cipher_type, TagBits, padding_type, stream_cipher_type, hash_type, allocator_type > encryption_policy
Definition: gcm.hpp:303
Allocator< T > allocator_type
Definition: gcm.hpp:299
BlockCipher cipher_type
Definition: gcm.hpp:293
StreamCipher stream_cipher_type
Definition: gcm.hpp:295