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