• 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

97.27
/src/lib/modes/aead/siv/siv.cpp
1
/*
2
* SIV Mode Encryption
3
* (C) 2013,2017 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/siv.h>
10

11
#include <botan/block_cipher.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/poly_dbl.h>
17

18
namespace Botan {
19

20
SIV_Mode::SIV_Mode(std::unique_ptr<BlockCipher> cipher) :
1,299✔
21
      m_name(cipher->name() + "/SIV"),
2,598✔
22
      m_bs(cipher->block_size()),
1,299✔
23
      m_ctr(std::make_unique<CTR_BE>(cipher->new_object(), 8)),
1,299✔
24
      m_mac(std::make_unique<CMAC>(std::move(cipher))) {
3,897✔
25
   // Not really true but only 128 bit allowed at the moment
26
   if(m_bs != 16) {
1,299✔
27
      throw Invalid_Argument("SIV requires a 128 bit block cipher");
×
28
   }
29
}
1,299✔
30

31
SIV_Mode::~SIV_Mode() = default;
4,551✔
32

33
void SIV_Mode::clear() {
644✔
34
   m_ctr->clear();
644✔
35
   m_mac->clear();
644✔
36
   reset();
644✔
37
}
644✔
38

39
void SIV_Mode::reset() {
3,173✔
40
   m_nonce.clear();
3,173✔
41
   m_msg_buf.clear();
3,173✔
42
   m_ad_macs.clear();
3,173✔
43
}
3,173✔
44

45
std::string SIV_Mode::name() const {
322✔
46
   return m_name;
322✔
47
}
48

49
bool SIV_Mode::valid_nonce_length(size_t /*nonce_len*/) const {
3,506✔
50
   return true;
3,506✔
51
}
52

53
size_t SIV_Mode::update_granularity() const {
2,248✔
54
   return 1;
2,248✔
55
}
56

57
size_t SIV_Mode::ideal_granularity() const {
1,938✔
58
   // Completely arbitrary value:
59
   return 128;
1,938✔
60
}
61

62
bool SIV_Mode::requires_entire_message() const {
628✔
63
   return true;
628✔
64
}
65

66
Key_Length_Specification SIV_Mode::key_spec() const {
665✔
67
   return m_mac->key_spec().multiple(2);
665✔
68
}
69

70
bool SIV_Mode::has_keying_material() const {
2,254✔
71
   return m_ctr->has_keying_material() && m_mac->has_keying_material();
2,254✔
72
}
73

74
void SIV_Mode::key_schedule(std::span<const uint8_t> key) {
655✔
75
   const size_t keylen = key.size() / 2;
655✔
76
   m_mac->set_key(key.first(keylen));
655✔
77
   m_ctr->set_key(key.last(keylen));
655✔
78
   m_ad_macs.clear();
655✔
79
}
655✔
80

81
size_t SIV_Mode::maximum_associated_data_inputs() const {
5,121✔
82
   return block_size() * 8 - 2;
5,121✔
83
}
84

85
void SIV_Mode::set_associated_data_n(size_t n, std::span<const uint8_t> ad) {
5,121✔
86
   const size_t max_ads = maximum_associated_data_inputs();
5,121✔
87
   if(n > max_ads) {
5,121✔
88
      throw Invalid_Argument(name() + " allows no more than " + std::to_string(max_ads) + " ADs");
×
89
   }
90

91
   if(n >= m_ad_macs.size()) {
5,121✔
92
      m_ad_macs.resize(n + 1);
4,477✔
93
   }
94

95
   m_ad_macs[n] = m_mac->process(ad);
5,121✔
96
}
3,833✔
97

98
void SIV_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
3,184✔
99
   if(!valid_nonce_length(nonce_len)) {
3,184✔
100
      throw Invalid_IV_Length(name(), nonce_len);
×
101
   }
102

103
   if(nonce_len) {
3,184✔
104
      m_nonce = m_mac->process(nonce, nonce_len);
34✔
105
   } else {
106
      m_nonce.clear();
3,167✔
107
   }
108

109
   m_msg_buf.clear();
3,184✔
110
}
3,184✔
111

112
size_t SIV_Mode::process_msg(uint8_t buf[], size_t sz) {
26,322✔
113
   // all output is saved for processing in finish
114
   m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
26,322✔
115
   return 0;
26,322✔
116
}
117

118
secure_vector<uint8_t> SIV_Mode::S2V(const uint8_t* text, size_t text_len) {
3,192✔
119
   const std::vector<uint8_t> zeros(block_size());
3,192✔
120

121
   secure_vector<uint8_t> V = m_mac->process(zeros.data(), zeros.size());
3,192✔
122

123
   for(size_t i = 0; i != m_ad_macs.size(); ++i) {
5,085✔
124
      poly_double_n(V.data(), V.size());
2,545✔
125
      V ^= m_ad_macs[i];
2,545✔
126
   }
127

128
   if(!m_nonce.empty()) {
2,540✔
129
      poly_double_n(V.data(), V.size());
15✔
130
      V ^= m_nonce;
15✔
131
   }
132

133
   if(text_len < block_size()) {
2,540✔
134
      poly_double_n(V.data(), V.size());
976✔
135
      xor_buf(V.data(), text, text_len);
976✔
136
      V[text_len] ^= 0x80;
976✔
137
      return m_mac->process(V);
976✔
138
   }
139

140
   m_mac->update(text, text_len - block_size());
1,564✔
141
   xor_buf(V.data(), &text[text_len - block_size()], block_size());
1,564✔
142
   m_mac->update(V);
1,564✔
143

144
   return m_mac->final();
1,564✔
145
}
5,080✔
146

147
void SIV_Mode::set_ctr_iv(secure_vector<uint8_t> V) {
2,812✔
148
   V[m_bs - 8] &= 0x7F;
2,812✔
149
   V[m_bs - 4] &= 0x7F;
2,812✔
150

151
   ctr().set_iv(V.data(), V.size());
2,812✔
152
}
2,498✔
153

154
void SIV_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
1,586✔
155
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
1,586✔
156

157
   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
1,586✔
158
   msg_buf().clear();
1,586✔
159

160
   const secure_vector<uint8_t> V = S2V(buffer.data() + offset, buffer.size() - offset);
1,586✔
161

162
   buffer.insert(buffer.begin() + offset, V.begin(), V.end());
942✔
163

164
   if(buffer.size() != offset + V.size()) {
942✔
165
      set_ctr_iv(V);
931✔
166
      ctr().cipher1(&buffer[offset + V.size()], buffer.size() - offset - V.size());
1,873✔
167
   }
168
}
942✔
169

170
void SIV_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
2,242✔
171
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
2,242✔
172

173
   if(!msg_buf().empty()) {
2,242✔
174
      buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
621✔
175
      msg_buf().clear();
621✔
176
   }
177

178
   const size_t sz = buffer.size() - offset;
2,242✔
179

180
   BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
2,242✔
181

182
   secure_vector<uint8_t> V(buffer.data() + offset, buffer.data() + offset + block_size());
1,920✔
183

184
   if(buffer.size() != offset + V.size()) {
1,920✔
185
      set_ctr_iv(V);
2,848✔
186

187
      ctr().cipher(buffer.data() + offset + V.size(), buffer.data() + offset, buffer.size() - offset - V.size());
1,567✔
188
   }
189

190
   const secure_vector<uint8_t> T = S2V(buffer.data() + offset, buffer.size() - offset - V.size());
1,606✔
191

192
   if(!CT::is_equal(T.data(), V.data(), T.size()).as_bool()) {
3,196✔
193
      throw Invalid_Authentication_Tag("SIV tag check failed");
645✔
194
   }
195

196
   buffer.resize(buffer.size() - tag_size());
953✔
197
}
2,551✔
198

199
}  // 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