• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13262741994

11 Feb 2025 12:19PM UTC coverage: 91.656% (-0.003%) from 91.659%
13262741994

Pull #4647

github

web-flow
Merge 0b8e56724 into f372b5a9e
Pull Request #4647: Avoid using mem_ops.h or assert.h in public headers

94864 of 103500 relevant lines covered (91.66%)

11330304.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.97
/src/lib/modes/aead/eax/eax.cpp
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/mem_ops.h>
12
#include <botan/internal/cmac.h>
13
#include <botan/internal/ct_utils.h>
14
#include <botan/internal/ctr.h>
15
#include <botan/internal/fmt.h>
16

17
namespace Botan {
18

19
namespace {
20

21
/*
22
* EAX MAC-based PRF
23
*/
24
secure_vector<uint8_t> eax_prf(
6,384✔
25
   uint8_t tag, size_t block_size, MessageAuthenticationCode& mac, const uint8_t in[], size_t length) {
26
   for(size_t i = 0; i != block_size - 1; ++i) {
89,648✔
27
      mac.update(0);
83,341✔
28
   }
29
   mac.update(tag);
6,307✔
30
   mac.update(in, length);
6,300✔
31
   return mac.final();
5,857✔
32
}
33

34
}  // namespace
35

36
/*
37
* EAX_Mode Constructor
38
*/
39
EAX_Mode::EAX_Mode(std::unique_ptr<BlockCipher> cipher, size_t tag_size) :
1,151✔
40
      m_tag_size(tag_size),
1,151✔
41
      m_cipher(std::move(cipher)),
1,151✔
42
      m_ctr(std::make_unique<CTR_BE>(m_cipher->new_object())),
1,151✔
43
      m_cmac(std::make_unique<CMAC>(m_cipher->new_object())) {
2,302✔
44
   if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) {
1,151✔
45
      throw Invalid_Argument(fmt("Tag size {} is not allowed for {}", tag_size, name()));
×
46
   }
47
}
1,151✔
48

49
void EAX_Mode::clear() {
384✔
50
   m_cipher->clear();
384✔
51
   m_ctr->clear();
384✔
52
   m_cmac->clear();
384✔
53
   reset();
384✔
54
}
384✔
55

56
void EAX_Mode::reset() {
2,423✔
57
   m_ad_mac.clear();
2,423✔
58
   m_nonce_mac.clear();
2,423✔
59

60
   // Clear out any data added to the CMAC calculation
61
   try {
2,423✔
62
      m_cmac->final();
4,462✔
63
   } catch(Key_Not_Set&) {}
384✔
64
}
2,423✔
65

66
std::string EAX_Mode::name() const {
191✔
67
   return (m_cipher->name() + "/EAX");
382✔
68
}
69

70
size_t EAX_Mode::update_granularity() const {
1,331✔
71
   return 1;
1,331✔
72
}
73

74
size_t EAX_Mode::ideal_granularity() const {
1,161✔
75
   return m_cipher->parallel_bytes();
1,161✔
76
}
77

78
Key_Length_Specification EAX_Mode::key_spec() const {
779✔
79
   return m_ctr->key_spec();
779✔
80
}
81

82
bool EAX_Mode::has_keying_material() const {
1,337✔
83
   return m_ctr->has_keying_material() && m_cmac->has_keying_material();
1,337✔
84
}
85

86
/*
87
* Set the EAX key
88
*/
89
void EAX_Mode::key_schedule(std::span<const uint8_t> key) {
772✔
90
   /*
91
   * These could share the key schedule, which is one nice part of EAX,
92
   * but it's much easier to ignore that here...
93
   */
94
   m_ctr->set_key(key);
772✔
95
   m_cmac->set_key(key);
772✔
96
}
772✔
97

98
/*
99
* Set the EAX associated data
100
*/
101
void EAX_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
3,819✔
102
   BOTAN_ARG_CHECK(idx == 0, "EAX: cannot handle non-zero index in set_associated_data_n");
3,819✔
103
   if(m_nonce_mac.empty() == false) {
3,819✔
104
      throw Invalid_State("Cannot set AD for EAX while processing a message");
382✔
105
   }
106
   m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad.data(), ad.size());
3,437✔
107
}
2,673✔
108

109
void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
2,811✔
110
   if(!valid_nonce_length(nonce_len)) {
2,811✔
111
      throw Invalid_IV_Length(name(), nonce_len);
112
   }
113

114
   m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len);
2,811✔
115

116
   m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size());
2,811✔
117

118
   for(size_t i = 0; i != block_size() - 1; ++i) {
39,744✔
119
      m_cmac->update(0);
36,933✔
120
   }
121
   m_cmac->update(2);
2,811✔
122
}
2,811✔
123

124
size_t EAX_Encryption::process_msg(uint8_t buf[], size_t sz) {
5,854✔
125
   BOTAN_STATE_CHECK(!m_nonce_mac.empty());
5,854✔
126
   m_ctr->cipher(buf, buf, sz);
5,472✔
127
   m_cmac->update(buf, sz);
5,472✔
128
   return sz;
5,472✔
129
}
130

131
void EAX_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
1,302✔
132
   BOTAN_STATE_CHECK(!m_nonce_mac.empty());
1,302✔
133
   update(buffer, offset);
729✔
134

135
   secure_vector<uint8_t> data_mac = m_cmac->final();
729✔
136
   xor_buf(data_mac, m_nonce_mac, data_mac.size());
729✔
137

138
   if(m_ad_mac.empty()) {
729✔
139
      m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
68✔
140
   }
141

142
   xor_buf(data_mac, m_ad_mac, data_mac.size());
729✔
143

144
   buffer += std::make_pair(data_mac.data(), tag_size());
729✔
145

146
   m_nonce_mac.clear();
1,458✔
147
}
729✔
148

149
size_t EAX_Decryption::process_msg(uint8_t buf[], size_t sz) {
5,303✔
150
   BOTAN_STATE_CHECK(!m_nonce_mac.empty());
5,303✔
151
   m_cmac->update(buf, sz);
4,921✔
152
   m_ctr->cipher(buf, buf, sz);
4,921✔
153
   return sz;
4,921✔
154
}
155

156
void EAX_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
1,889✔
157
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
1,889✔
158
   const size_t sz = buffer.size() - offset;
1,889✔
159
   uint8_t* buf = buffer.data() + offset;
1,889✔
160

161
   BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
1,889✔
162

163
   const size_t remaining = sz - tag_size();
1,422✔
164

165
   if(remaining) {
1,422✔
166
      m_cmac->update(buf, remaining);
1,000✔
167
      m_ctr->cipher(buf, buf, remaining);
987✔
168
   }
169

170
   const uint8_t* included_tag = &buf[remaining];
1,325✔
171

172
   secure_vector<uint8_t> mac = m_cmac->final();
1,325✔
173
   mac ^= m_nonce_mac;
1,316✔
174

175
   if(m_ad_mac.empty()) {
1,316✔
176
      m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
636✔
177
   }
178

179
   mac ^= m_ad_mac;
1,316✔
180

181
   const bool accept_mac = CT::is_equal(mac.data(), included_tag, tag_size()).as_bool();
2,632✔
182

183
   buffer.resize(offset + remaining);
1,316✔
184

185
   m_nonce_mac.clear();
1,316✔
186

187
   if(!accept_mac) {
1,316✔
188
      throw Invalid_Authentication_Tag("EAX tag check failed");
568✔
189
   }
190
}
748✔
191

192
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc