Coverage Report

Created: 2020-09-16 07:52

/src/botan/src/lib/modes/aead/eax/eax.cpp
Line
Count
Source (jump to first uncovered line)
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
13
namespace Botan {
14
15
namespace {
16
17
/*
18
* EAX MAC-based PRF
19
*/
20
secure_vector<uint8_t> eax_prf(uint8_t tag, size_t block_size,
21
                           MessageAuthenticationCode& mac,
22
                           const uint8_t in[], size_t length)
23
0
   {
24
0
   for(size_t i = 0; i != block_size - 1; ++i)
25
0
      {
26
0
      mac.update(0);
27
0
      }
28
0
   mac.update(tag);
29
0
   mac.update(in, length);
30
0
   return mac.final();
31
0
   }
32
33
}
34
35
/*
36
* EAX_Mode Constructor
37
*/
38
EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) :
39
   m_tag_size(tag_size),
40
   m_cipher(cipher),
41
   m_ctr(new CTR_BE(m_cipher->clone())),
42
   m_cmac(new CMAC(m_cipher->clone()))
43
0
   {
44
0
   if(m_tag_size < 8 || m_tag_size > m_cmac->output_length())
45
0
      throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size));
46
0
   }
47
48
void EAX_Mode::clear()
49
0
   {
50
0
   m_cipher->clear();
51
0
   m_ctr->clear();
52
0
   m_cmac->clear();
53
0
   reset();
54
0
   }
55
56
void EAX_Mode::reset()
57
0
   {
58
0
   m_ad_mac.clear();
59
0
   m_nonce_mac.clear();
60
0
61
   // Clear out any data added to the CMAC calculation
62
0
   try {
63
0
      m_cmac->final();
64
0
   }
65
0
   catch(Key_Not_Set&) {}
66
0
   }
67
68
std::string EAX_Mode::name() const
69
0
   {
70
0
   return (m_cipher->name() + "/EAX");
71
0
   }
72
73
size_t EAX_Mode::update_granularity() const
74
0
   {
75
   /*
76
   * For EAX this actually can be as low as 1 but that causes problems
77
   * for applications which use update_granularity as the buffer size.
78
   */
79
0
   return m_cipher->parallel_bytes();
80
0
   }
81
82
Key_Length_Specification EAX_Mode::key_spec() const
83
0
   {
84
0
   return m_cipher->key_spec();
85
0
   }
86
87
/*
88
* Set the EAX key
89
*/
90
void EAX_Mode::key_schedule(const uint8_t key[], size_t length)
91
0
   {
92
   /*
93
   * These could share the key schedule, which is one nice part of EAX,
94
   * but it's much easier to ignore that here...
95
   */
96
0
   m_ctr->set_key(key, length);
97
0
   m_cmac->set_key(key, length);
98
0
   }
99
100
/*
101
* Set the EAX associated data
102
*/
103
void EAX_Mode::set_associated_data(const uint8_t ad[], size_t length)
104
0
   {
105
0
   if(m_nonce_mac.empty() == false)
106
0
      throw Invalid_State("Cannot set AD for EAX while processing a message");
107
0
   m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length);
108
0
   }
109
110
void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
111
0
   {
112
0
   if(!valid_nonce_length(nonce_len))
113
0
      throw Invalid_IV_Length(name(), nonce_len);
114
0
115
0
   m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len);
116
0
117
0
   m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size());
118
0
119
0
   for(size_t i = 0; i != block_size() - 1; ++i)
120
0
      m_cmac->update(0);
121
0
   m_cmac->update(2);
122
0
   }
123
124
size_t EAX_Encryption::process(uint8_t buf[], size_t sz)
125
0
   {
126
0
   BOTAN_STATE_CHECK(m_nonce_mac.size() > 0);
127
0
   m_ctr->cipher(buf, buf, sz);
128
0
   m_cmac->update(buf, sz);
129
0
   return sz;
130
0
   }
131
132
void EAX_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
133
0
   {
134
0
   BOTAN_ASSERT_NOMSG(m_nonce_mac.empty() == false);
135
0
   update(buffer, offset);
136
0
137
0
   secure_vector<uint8_t> data_mac = m_cmac->final();
138
0
   xor_buf(data_mac, m_nonce_mac, data_mac.size());
139
0
140
0
   if(m_ad_mac.empty())
141
0
      {
142
0
      m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
143
0
      }
144
0
145
0
   xor_buf(data_mac, m_ad_mac, data_mac.size());
146
0
147
0
   buffer += std::make_pair(data_mac.data(), tag_size());
148
0
   }
149
150
size_t EAX_Decryption::process(uint8_t buf[], size_t sz)
151
0
   {
152
0
   BOTAN_STATE_CHECK(m_nonce_mac.size() > 0);
153
0
   m_cmac->update(buf, sz);
154
0
   m_ctr->cipher(buf, buf, sz);
155
0
   return sz;
156
0
   }
157
158
void EAX_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
159
0
   {
160
0
   BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
161
0
   const size_t sz = buffer.size() - offset;
162
0
   uint8_t* buf = buffer.data() + offset;
163
0
164
0
   BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input");
165
0
166
0
   const size_t remaining = sz - tag_size();
167
0
168
0
   if(remaining)
169
0
      {
170
0
      m_cmac->update(buf, remaining);
171
0
      m_ctr->cipher(buf, buf, remaining);
172
0
      }
173
0
174
0
   const uint8_t* included_tag = &buf[remaining];
175
0
176
0
   secure_vector<uint8_t> mac = m_cmac->final();
177
0
   mac ^= m_nonce_mac;
178
0
179
0
   if(m_ad_mac.empty())
180
0
      {
181
0
      m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
182
0
      }
183
0
184
0
   mac ^= m_ad_mac;
185
0
186
0
   if(!constant_time_compare(mac.data(), included_tag, tag_size()))
187
0
      throw Invalid_Authentication_Tag("EAX tag check failed");
188
0
189
0
   buffer.resize(offset + remaining);
190
0
191
0
   m_nonce_mac.clear();
192
0
   }
193
194
}