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