Botan 3.13.0
Crypto and TLS for C&
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/internal/eax.h>
10
11#include <botan/exceptn.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/cmac.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/ctr.h>
16#include <botan/internal/fmt.h>
17#include <botan/internal/int_utils.h>
18
19namespace Botan {
20
21namespace {
22
23/*
24* EAX MAC-based PRF
25*/
27 uint8_t tag, size_t block_size, MessageAuthenticationCode& mac, const uint8_t in[], size_t length) {
28 for(size_t i = 0; i != block_size - 1; ++i) {
29 mac.update(0);
30 }
31 mac.update(tag);
32 mac.update(in, length);
33 return mac.final();
34}
35
36} // namespace
37
38/*
39* EAX_Mode Constructor
40*/
41EAX_Mode::EAX_Mode(std::unique_ptr<BlockCipher> cipher, size_t tag_size) :
43 m_cipher(std::move(cipher)),
44 m_ctr(std::make_unique<CTR_BE>(m_cipher->new_object())),
45 m_cmac(std::make_unique<CMAC>(m_cipher->new_object())) {
46 if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) {
47 throw Invalid_Argument(fmt("Tag size {} is not allowed for {}", tag_size, name()));
48 }
49}
50
52 m_cipher->clear();
53 m_ctr->clear();
54 m_cmac->clear();
55 m_ad_mac.clear();
56 reset();
57}
58
60 m_nonce_mac.clear();
61
62 // Clear out any data added to the CMAC calculation
63 try {
64 m_cmac->final();
65 } catch(Key_Not_Set&) {}
66}
67
68std::string EAX_Mode::name() const {
69 return (m_cipher->name() + "/EAX");
70}
71
73 return 1;
74}
75
77 return m_cipher->parallel_bytes();
78}
79
81 return m_ctr->key_spec();
82}
83
85 return m_ctr->has_keying_material() && m_cmac->has_keying_material();
86}
87
88/*
89* Set the EAX key
90*/
91void EAX_Mode::key_schedule(std::span<const uint8_t> key) {
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 m_ctr->set_key(key);
97 m_cmac->set_key(key);
98
99 // m_ad_mac was precomputed under the previous CMAC key (if any).
100 // Re-keying invalidates it; AD must be re-set after set_key.
101 m_ad_mac.clear();
102
103 // Also drop any per-message state.
104 reset();
105}
106
107/*
108* Set the EAX associated data
109*/
110void EAX_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
111 BOTAN_ARG_CHECK(idx == 0, "EAX: cannot handle non-zero index in set_associated_data_n");
112 if(!m_nonce_mac.empty()) {
113 throw Invalid_State("Cannot set AD for EAX while processing a message");
114 }
115 m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad.data(), ad.size());
116}
117
118void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
120
121 if(!valid_nonce_length(nonce_len)) {
122 throw Invalid_IV_Length(name(), nonce_len);
123 }
124
125 m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len);
126
127 m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size());
128
129 for(size_t i = 0; i != block_size() - 1; ++i) {
130 m_cmac->update(0);
131 }
132 m_cmac->update(2);
133}
134
135size_t EAX_Encryption::output_length(size_t input_length) const {
136 return add_or_throw(input_length, tag_size(), "EAX input too large");
137}
138
139size_t EAX_Encryption::process_msg(uint8_t buf[], size_t sz) {
141 m_ctr->cipher(buf, buf, sz);
142 m_cmac->update(buf, sz);
143 return sz;
144}
145
146void EAX_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
148 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
149 update(buffer, offset);
150
151 secure_vector<uint8_t> data_mac = m_cmac->final();
152 xor_buf(data_mac, m_nonce_mac, data_mac.size());
153
154 if(m_ad_mac.empty()) {
155 m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
156 }
157
158 xor_buf(data_mac, m_ad_mac, data_mac.size());
159
160 buffer += std::make_pair(data_mac.data(), tag_size());
161
162 m_nonce_mac.clear();
163}
164
165size_t EAX_Decryption::output_length(size_t input_length) const {
166 BOTAN_ARG_CHECK(input_length >= tag_size(), "Message too short to be valid");
167 return input_length - tag_size();
168}
169
170size_t EAX_Decryption::process_msg(uint8_t buf[], size_t sz) {
172 m_cmac->update(buf, sz);
173 m_ctr->cipher(buf, buf, sz);
174 return sz;
175}
176
177void EAX_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
179 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
180 const size_t sz = buffer.size() - offset;
181 uint8_t* buf = buffer.data() + offset;
182
183 BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
184
185 const size_t remaining = sz - tag_size();
186
187 if(remaining > 0) {
188 m_cmac->update(buf, remaining);
189 m_ctr->cipher(buf, buf, remaining);
190 }
191
192 const uint8_t* included_tag = &buf[remaining];
193
194 secure_vector<uint8_t> mac = m_cmac->final();
195 mac ^= m_nonce_mac;
196
197 if(m_ad_mac.empty()) {
198 m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
199 }
200
201 mac ^= m_ad_mac;
202
203 const bool accept_mac = CT::is_equal(mac.data(), included_tag, tag_size()).as_bool();
204
205 buffer.resize(offset + remaining);
206
207 m_nonce_mac.clear();
208
209 if(!accept_mac) {
210 clear_mem(std::span{buffer}.subspan(offset, remaining));
211 throw Invalid_Authentication_Tag("EAX tag check failed");
212 }
213}
214
215} // namespace Botan
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
void update(T &buffer, size_t offset=0)
size_t output_length(size_t input_length) const override
Definition eax.cpp:165
size_t output_length(size_t input_length) const override
Definition eax.cpp:135
size_t tag_size() const final
Definition eax.h:39
size_t update_granularity() const final
Definition eax.cpp:72
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) final
Definition eax.cpp:110
size_t block_size() const
Definition eax.h:54
size_t ideal_granularity() const final
Definition eax.cpp:76
void clear() final
Definition eax.cpp:51
bool valid_nonce_length(size_t) const final
Definition eax.h:37
std::unique_ptr< BlockCipher > m_cipher
Definition eax.h:58
bool has_keying_material() const final
Definition eax.cpp:84
EAX_Mode(std::unique_ptr< BlockCipher > cipher, size_t tag_size)
Definition eax.cpp:41
std::unique_ptr< StreamCipher > m_ctr
Definition eax.h:59
std::unique_ptr< MessageAuthenticationCode > m_cmac
Definition eax.h:60
Key_Length_Specification key_spec() const final
Definition eax.cpp:80
secure_vector< uint8_t > m_nonce_mac
Definition eax.h:64
size_t m_tag_size
Definition eax.h:56
void reset() final
Definition eax.cpp:59
std::string name() const final
Definition eax.cpp:68
secure_vector< uint8_t > m_ad_mac
Definition eax.h:62
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
constexpr T add_or_throw(T a, T b, std::string_view msg)
Definition int_utils.h:66
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:403
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118