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