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