Coverage Report

Created: 2023-01-25 06:35

/src/botan/src/lib/modes/aead/siv/siv.cpp
Line
Count
Source (jump to first uncovered line)
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
#include <botan/block_cipher.h>
11
#include <botan/internal/cmac.h>
12
#include <botan/internal/poly_dbl.h>
13
#include <botan/internal/ctr.h>
14
15
namespace Botan {
16
17
SIV_Mode::SIV_Mode(std::unique_ptr<BlockCipher> cipher) :
18
   m_name(cipher->name() + "/SIV"),
19
   m_bs(cipher->block_size()),
20
   m_ctr(new CTR_BE(cipher->new_object(), 8)),
21
   m_mac(new CMAC(std::move(cipher)))
22
0
   {
23
   // Not really true but only 128 bit allowed at the moment
24
0
   if(m_bs != 16)
25
0
      throw Invalid_Argument("SIV requires a 128 bit block cipher");
26
0
   }
27
28
SIV_Mode::~SIV_Mode()
29
0
   {
30
   // for ~unique_ptr
31
0
   }
32
33
void SIV_Mode::clear()
34
0
   {
35
0
   m_ctr->clear();
36
0
   m_mac->clear();
37
0
   reset();
38
0
   }
39
40
void SIV_Mode::reset()
41
0
   {
42
0
   m_nonce.clear();
43
0
   m_msg_buf.clear();
44
0
   m_ad_macs.clear();
45
0
   }
46
47
std::string SIV_Mode::name() const
48
0
   {
49
0
   return m_name;
50
0
   }
51
52
bool SIV_Mode::valid_nonce_length(size_t /*nonce_len*/) const
53
0
   {
54
0
   return true;
55
0
   }
56
57
size_t SIV_Mode::update_granularity() const
58
0
   {
59
0
   return 1;
60
0
   }
61
62
size_t SIV_Mode::ideal_granularity() const
63
0
   {
64
   // Completely arbitrary value:
65
0
   return 128;
66
0
   }
67
68
bool SIV_Mode::requires_entire_message() const
69
0
   {
70
0
   return true;
71
0
   }
72
73
Key_Length_Specification SIV_Mode::key_spec() const
74
0
   {
75
0
   return m_mac->key_spec().multiple(2);
76
0
   }
77
78
void SIV_Mode::key_schedule(const uint8_t key[], size_t length)
79
0
   {
80
0
   const size_t keylen = length / 2;
81
0
   m_mac->set_key(key, keylen);
82
0
   m_ctr->set_key(key + keylen, keylen);
83
0
   m_ad_macs.clear();
84
0
   }
85
86
size_t SIV_Mode::maximum_associated_data_inputs() const
87
0
   {
88
0
   return block_size() * 8 - 2;
89
0
   }
90
91
void SIV_Mode::set_associated_data_n(size_t n, const uint8_t ad[], size_t length)
92
0
   {
93
0
   const size_t max_ads = maximum_associated_data_inputs();
94
0
   if(n > max_ads)
95
0
      throw Invalid_Argument(name() + " allows no more than " + std::to_string(max_ads) + " ADs");
96
97
0
   if(n >= m_ad_macs.size())
98
0
      m_ad_macs.resize(n+1);
99
100
0
   m_ad_macs[n] = m_mac->process(ad, length);
101
0
   }
102
103
void SIV_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
104
0
   {
105
0
   if(!valid_nonce_length(nonce_len))
106
0
      throw Invalid_IV_Length(name(), nonce_len);
107
108
0
   if(nonce_len)
109
0
      m_nonce = m_mac->process(nonce, nonce_len);
110
0
   else
111
0
      m_nonce.clear();
112
113
0
   m_msg_buf.clear();
114
0
   }
115
116
size_t SIV_Mode::process(uint8_t buf[], size_t sz)
117
0
   {
118
   // all output is saved for processing in finish
119
0
   m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
120
0
   return 0;
121
0
   }
122
123
secure_vector<uint8_t> SIV_Mode::S2V(const uint8_t* text, size_t text_len)
124
0
   {
125
0
   const std::vector<uint8_t> zeros(block_size());
126
127
0
   secure_vector<uint8_t> V = m_mac->process(zeros.data(), zeros.size());
128
129
0
   for(size_t i = 0; i != m_ad_macs.size(); ++i)
130
0
      {
131
0
      poly_double_n(V.data(), V.size());
132
0
      V ^= m_ad_macs[i];
133
0
      }
134
135
0
   if(!m_nonce.empty())
136
0
      {
137
0
      poly_double_n(V.data(), V.size());
138
0
      V ^= m_nonce;
139
0
      }
140
141
0
   if(text_len < block_size())
142
0
      {
143
0
      poly_double_n(V.data(), V.size());
144
0
      xor_buf(V.data(), text, text_len);
145
0
      V[text_len] ^= 0x80;
146
0
      return m_mac->process(V);
147
0
      }
148
149
0
   m_mac->update(text, text_len - block_size());
150
0
   xor_buf(V.data(), &text[text_len - block_size()], block_size());
151
0
   m_mac->update(V);
152
153
0
   return m_mac->final();
154
0
   }
155
156
void SIV_Mode::set_ctr_iv(secure_vector<uint8_t> V)
157
0
   {
158
0
   V[m_bs-8] &= 0x7F;
159
0
   V[m_bs-4] &= 0x7F;
160
161
0
   ctr().set_iv(V.data(), V.size());
162
0
   }
163
164
void SIV_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
165
0
   {
166
0
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
167
168
0
   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
169
0
   msg_buf().clear();
170
171
0
   const secure_vector<uint8_t> V = S2V(buffer.data() + offset, buffer.size() - offset);
172
173
0
   buffer.insert(buffer.begin() + offset, V.begin(), V.end());
174
175
0
   if(buffer.size() != offset + V.size())
176
0
      {
177
0
      set_ctr_iv(V);
178
0
      ctr().cipher1(&buffer[offset + V.size()], buffer.size() - offset - V.size());
179
0
      }
180
0
   }
181
182
void SIV_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
183
0
   {
184
0
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
185
186
0
   if(!msg_buf().empty())
187
0
      {
188
0
      buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
189
0
      msg_buf().clear();
190
0
      }
191
192
0
   const size_t sz = buffer.size() - offset;
193
194
0
   BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
195
196
0
   secure_vector<uint8_t> V(buffer.data() + offset,
197
0
                            buffer.data() + offset + block_size());
198
199
0
   if(buffer.size() != offset + V.size())
200
0
      {
201
0
      set_ctr_iv(V);
202
203
0
      ctr().cipher(buffer.data() + offset + V.size(),
204
0
                   buffer.data() + offset,
205
0
                   buffer.size() - offset - V.size());
206
0
      }
207
208
0
   const secure_vector<uint8_t> T = S2V(buffer.data() + offset, buffer.size() - offset - V.size());
209
210
0
   if(!constant_time_compare(T.data(), V.data(), T.size()))
211
0
      throw Invalid_Authentication_Tag("SIV tag check failed");
212
213
0
   buffer.resize(buffer.size() - tag_size());
214
0
   }
215
216
}