Botan  2.1.0
Crypto and TLS for C++11
eax.cpp
Go to the documentation of this file.
1 /*
2 * EAX Mode Encryption
3 * (C) 1999-2007 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/eax.h>
10 #include <botan/cmac.h>
11 #include <botan/ctr.h>
12 #include <botan/parsing.h>
13 
14 namespace Botan {
15 
16 namespace {
17 
18 /*
19 * EAX MAC-based PRF
20 */
21 secure_vector<uint8_t> eax_prf(uint8_t tag, size_t block_size,
22  MessageAuthenticationCode& mac,
23  const uint8_t in[], size_t length)
24  {
25  for(size_t i = 0; i != block_size - 1; ++i)
26  {
27  mac.update(0);
28  }
29  mac.update(tag);
30  mac.update(in, length);
31  return mac.final();
32  }
33 
34 }
35 
36 /*
37 * EAX_Mode Constructor
38 */
39 EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) :
40  m_tag_size(tag_size ? tag_size : cipher->block_size()),
41  m_cipher(cipher),
42  m_ctr(new CTR_BE(m_cipher->clone())),
43  m_cmac(new CMAC(m_cipher->clone()))
44  {
45  if(m_tag_size < 8 || m_tag_size > m_cmac->output_length())
46  throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size));
47  }
48 
50  {
51  m_cipher->clear();
52  m_ctr->clear();
53  m_cmac->clear();
54  reset();
55  }
56 
58  {
59  m_ad_mac.clear();
60  m_nonce_mac.clear();
61  }
62 
63 std::string EAX_Mode::name() const
64  {
65  return (m_cipher->name() + "/EAX");
66  }
67 
69  {
70  return 1;
71  }
72 
74  {
75  return m_cipher->key_spec();
76  }
77 
78 /*
79 * Set the EAX key
80 */
81 void EAX_Mode::key_schedule(const uint8_t key[], size_t length)
82  {
83  /*
84  * These could share the key schedule, which is one nice part of EAX,
85  * but it's much easier to ignore that here...
86  */
87  m_ctr->set_key(key, length);
88  m_cmac->set_key(key, length);
89  }
90 
91 /*
92 * Set the EAX associated data
93 */
94 void EAX_Mode::set_associated_data(const uint8_t ad[], size_t length)
95  {
96  m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length);
97  }
98 
99 void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
100  {
101  if(!valid_nonce_length(nonce_len))
102  throw Invalid_IV_Length(name(), nonce_len);
103 
104  m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len);
105 
106  m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size());
107 
108  for(size_t i = 0; i != block_size() - 1; ++i)
109  m_cmac->update(0);
110  m_cmac->update(2);
111  }
112 
113 size_t EAX_Encryption::process(uint8_t buf[], size_t sz)
114  {
115  m_ctr->cipher(buf, buf, sz);
116  m_cmac->update(buf, sz);
117  return sz;
118  }
119 
120 void EAX_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
121  {
122  update(buffer, offset);
123 
124  secure_vector<uint8_t> data_mac = m_cmac->final();
125  xor_buf(data_mac, m_nonce_mac, data_mac.size());
126 
127  if(m_ad_mac.empty())
128  {
129  m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
130  }
131 
132  xor_buf(data_mac, m_ad_mac, data_mac.size());
133 
134  buffer += std::make_pair(data_mac.data(), tag_size());
135  }
136 
137 size_t EAX_Decryption::process(uint8_t buf[], size_t sz)
138  {
139  m_cmac->update(buf, sz);
140  m_ctr->cipher(buf, buf, sz);
141  return sz;
142  }
143 
144 void EAX_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
145  {
146  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
147  const size_t sz = buffer.size() - offset;
148  uint8_t* buf = buffer.data() + offset;
149 
150  BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input");
151 
152  const size_t remaining = sz - tag_size();
153 
154  if(remaining)
155  {
156  m_cmac->update(buf, remaining);
157  m_ctr->cipher(buf, buf, remaining);
158  }
159 
160  const uint8_t* included_tag = &buf[remaining];
161 
162  secure_vector<uint8_t> mac = m_cmac->final();
163  mac ^= m_nonce_mac;
164 
165  if(m_ad_mac.empty())
166  {
167  m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
168  }
169 
170  mac ^= m_ad_mac;
171 
172  if(!same_mem(mac.data(), included_tag, tag_size()))
173  throw Integrity_Failure("EAX tag check failed");
174 
175  buffer.resize(offset + remaining);
176  }
177 
178 }
void xor_buf(T out[], const T in[], size_t length)
Definition: mem_ops.h:115
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: eax.cpp:144
Key_Length_Specification key_spec() const override
Definition: eax.cpp:73
size_t process(uint8_t buf[], size_t size) override
Definition: eax.cpp:113
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
std::string name() const override
Definition: eax.cpp:63
void clear() override
Definition: eax.cpp:49
void update(secure_vector< uint8_t > &buffer, size_t offset=0)
Definition: cipher_mode.h:81
secure_vector< uint8_t > m_ad_mac
Definition: eax.h:57
secure_vector< uint8_t > m_nonce_mac
Definition: eax.h:59
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
bool valid_nonce_length(size_t) const override
Definition: eax.h:34
EAX_Mode(BlockCipher *cipher, size_t tag_size)
Definition: eax.cpp:39
size_t process(uint8_t buf[], size_t size) override
Definition: eax.cpp:137
Definition: alg_id.cpp:13
size_t block_size() const
Definition: eax.h:49
std::unique_ptr< BlockCipher > m_cipher
Definition: eax.h:53
size_t tag_size() const override
Definition: eax.h:36
void reset() override
Definition: eax.cpp:57
std::unique_ptr< MessageAuthenticationCode > m_cmac
Definition: eax.h:55
size_t update_granularity() const override
Definition: eax.cpp:68
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: eax.cpp:94
std::unique_ptr< StreamCipher > m_ctr
Definition: eax.h:54
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: eax.cpp:120