Botan 3.4.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/internal/cmac.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/ctr.h>
14#include <botan/internal/fmt.h>
15
16namespace Botan {
17
18namespace {
19
20/*
21* EAX MAC-based PRF
22*/
23secure_vector<uint8_t> eax_prf(
24 uint8_t tag, size_t block_size, MessageAuthenticationCode& mac, const uint8_t in[], size_t length) {
25 for(size_t i = 0; i != block_size - 1; ++i) {
26 mac.update(0);
27 }
28 mac.update(tag);
29 mac.update(in, length);
30 return mac.final();
31}
32
33} // namespace
34
35/*
36* EAX_Mode Constructor
37*/
38EAX_Mode::EAX_Mode(std::unique_ptr<BlockCipher> cipher, size_t tag_size) :
39 m_tag_size(tag_size),
40 m_cipher(std::move(cipher)),
41 m_ctr(std::make_unique<CTR_BE>(m_cipher->new_object())),
42 m_cmac(std::make_unique<CMAC>(m_cipher->new_object())) {
43 if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) {
44 throw Invalid_Argument(fmt("Tag size {} is not allowed for {}", tag_size, name()));
45 }
46}
47
49 m_cipher->clear();
50 m_ctr->clear();
51 m_cmac->clear();
52 reset();
53}
54
56 m_ad_mac.clear();
57 m_nonce_mac.clear();
58
59 // Clear out any data added to the CMAC calculation
60 try {
61 m_cmac->final();
62 } catch(Key_Not_Set&) {}
63}
64
65std::string EAX_Mode::name() const {
66 return (m_cipher->name() + "/EAX");
67}
68
70 return 1;
71}
72
74 return m_cipher->parallel_bytes();
75}
76
78 return m_ctr->key_spec();
79}
80
82 return m_ctr->has_keying_material() && m_cmac->has_keying_material();
83}
84
85/*
86* Set the EAX key
87*/
88void EAX_Mode::key_schedule(std::span<const uint8_t> key) {
89 /*
90 * These could share the key schedule, which is one nice part of EAX,
91 * but it's much easier to ignore that here...
92 */
93 m_ctr->set_key(key);
94 m_cmac->set_key(key);
95}
96
97/*
98* Set the EAX associated data
99*/
100void EAX_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
101 BOTAN_ARG_CHECK(idx == 0, "EAX: cannot handle non-zero index in set_associated_data_n");
102 if(m_nonce_mac.empty() == false) {
103 throw Invalid_State("Cannot set AD for EAX while processing a message");
104 }
105 m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad.data(), ad.size());
106}
107
108void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
109 if(!valid_nonce_length(nonce_len)) {
110 throw Invalid_IV_Length(name(), nonce_len);
111 }
112
113 m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len);
114
115 m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size());
116
117 for(size_t i = 0; i != block_size() - 1; ++i) {
118 m_cmac->update(0);
119 }
120 m_cmac->update(2);
121}
122
123size_t EAX_Encryption::process_msg(uint8_t buf[], size_t sz) {
125 m_ctr->cipher(buf, buf, sz);
126 m_cmac->update(buf, sz);
127 return sz;
128}
129
130void EAX_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
132 update(buffer, offset);
133
134 secure_vector<uint8_t> data_mac = m_cmac->final();
135 xor_buf(data_mac, m_nonce_mac, data_mac.size());
136
137 if(m_ad_mac.empty()) {
138 m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
139 }
140
141 xor_buf(data_mac, m_ad_mac, data_mac.size());
142
143 buffer += std::make_pair(data_mac.data(), tag_size());
144
145 m_nonce_mac.clear();
146}
147
148size_t EAX_Decryption::process_msg(uint8_t buf[], size_t sz) {
150 m_cmac->update(buf, sz);
151 m_ctr->cipher(buf, buf, sz);
152 return sz;
153}
154
155void EAX_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
156 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
157 const size_t sz = buffer.size() - offset;
158 uint8_t* buf = buffer.data() + offset;
159
160 BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
161
162 const size_t remaining = sz - tag_size();
163
164 if(remaining) {
165 m_cmac->update(buf, remaining);
166 m_ctr->cipher(buf, buf, remaining);
167 }
168
169 const uint8_t* included_tag = &buf[remaining];
170
171 secure_vector<uint8_t> mac = m_cmac->final();
172 mac ^= m_nonce_mac;
173
174 if(m_ad_mac.empty()) {
175 m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
176 }
177
178 mac ^= m_ad_mac;
179
180 const bool accept_mac = CT::is_equal(mac.data(), included_tag, tag_size()).as_bool();
181
182 buffer.resize(offset + remaining);
183
184 m_nonce_mac.clear();
185
186 if(!accept_mac) {
187 throw Invalid_Authentication_Tag("EAX tag check failed");
188 }
189}
190
191} // namespace Botan
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
size_t tag_size() const final
Definition eax.h:37
size_t update_granularity() const final
Definition eax.cpp:69
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) final
Definition eax.cpp:100
size_t block_size() const
Definition eax.h:52
size_t ideal_granularity() const final
Definition eax.cpp:73
void clear() final
Definition eax.cpp:48
bool valid_nonce_length(size_t) const final
Definition eax.h:35
std::unique_ptr< BlockCipher > m_cipher
Definition eax.h:56
bool has_keying_material() const final
Definition eax.cpp:81
EAX_Mode(std::unique_ptr< BlockCipher > cipher, size_t tag_size)
Definition eax.cpp:38
std::unique_ptr< StreamCipher > m_ctr
Definition eax.h:57
std::unique_ptr< MessageAuthenticationCode > m_cmac
Definition eax.h:58
Key_Length_Specification key_spec() const final
Definition eax.cpp:77
secure_vector< uint8_t > m_nonce_mac
Definition eax.h:62
void reset() final
Definition eax.cpp:55
std::string name() const final
Definition eax.cpp:65
secure_vector< uint8_t > m_ad_mac
Definition eax.h:60
int(* update)(CTX *, const void *, CC_LONG len)
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:345
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:343