Botan 3.3.0
Crypto and TLS for C&
ctr.cpp
Go to the documentation of this file.
1/*
2* Counter mode
3* (C) 1999-2011,2014 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/ctr.h>
9
10#include <botan/exceptn.h>
11#include <botan/internal/bit_ops.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/loadstor.h>
14
15namespace Botan {
16
17CTR_BE::CTR_BE(std::unique_ptr<BlockCipher> cipher) :
18 m_cipher(std::move(cipher)),
19 m_block_size(m_cipher->block_size()),
20 m_ctr_size(m_block_size),
21 m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
22 m_counter(m_cipher->parallel_bytes()),
23 m_pad(m_counter.size()),
24 m_pad_pos(0) {}
25
26CTR_BE::CTR_BE(std::unique_ptr<BlockCipher> cipher, size_t ctr_size) :
27 m_cipher(std::move(cipher)),
28 m_block_size(m_cipher->block_size()),
29 m_ctr_size(ctr_size),
30 m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
31 m_counter(m_cipher->parallel_bytes()),
32 m_pad(m_counter.size()),
33 m_pad_pos(0) {
34 BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size, "Invalid CTR-BE counter size");
35}
36
38 m_cipher->clear();
39 zeroise(m_pad);
40 zeroise(m_counter);
41 zap(m_iv);
42 m_pad_pos = 0;
43}
44
46 return m_block_size;
47}
48
49bool CTR_BE::valid_iv_length(size_t iv_len) const {
50 return (iv_len <= m_block_size);
51}
52
53size_t CTR_BE::buffer_size() const {
54 return m_pad.size();
55}
56
58 return m_cipher->key_spec();
59}
60
61std::unique_ptr<StreamCipher> CTR_BE::new_object() const {
62 return std::make_unique<CTR_BE>(m_cipher->new_object(), m_ctr_size);
63}
64
66 return m_cipher->has_keying_material();
67}
68
69void CTR_BE::key_schedule(std::span<const uint8_t> key) {
70 m_cipher->set_key(key);
71
72 // Set a default all-zeros IV
73 set_iv(nullptr, 0);
74}
75
76std::string CTR_BE::name() const {
77 if(m_ctr_size == m_block_size) {
78 return fmt("CTR-BE({})", m_cipher->name());
79 } else {
80 return fmt("CTR-BE({},{})", m_cipher->name(), m_ctr_size);
81 }
82}
83
84void CTR_BE::cipher_bytes(const uint8_t in[], uint8_t out[], size_t length) {
86
87 const uint8_t* pad_bits = &m_pad[0];
88 const size_t pad_size = m_pad.size();
89
90 if(m_pad_pos > 0) {
91 const size_t avail = pad_size - m_pad_pos;
92 const size_t take = std::min(length, avail);
93 xor_buf(out, in, pad_bits + m_pad_pos, take);
94 length -= take;
95 in += take;
96 out += take;
97 m_pad_pos += take;
98
99 if(take == avail) {
100 add_counter(m_ctr_blocks);
101 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
102 m_pad_pos = 0;
103 }
104 }
105
106 while(length >= pad_size) {
107 xor_buf(out, in, pad_bits, pad_size);
108 length -= pad_size;
109 in += pad_size;
110 out += pad_size;
111
112 add_counter(m_ctr_blocks);
113 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
114 }
115
116 xor_buf(out, in, pad_bits, length);
117 m_pad_pos += length;
118}
119
120void CTR_BE::generate_keystream(uint8_t out[], size_t length) {
122
123 const size_t avail = m_pad.size() - m_pad_pos;
124 const size_t take = std::min(length, avail);
125 copy_mem(out, &m_pad[m_pad_pos], take);
126 length -= take;
127 out += take;
128 m_pad_pos += take;
129
130 while(length >= m_pad.size()) {
131 add_counter(m_ctr_blocks);
132 m_cipher->encrypt_n(m_counter.data(), out, m_ctr_blocks);
133
134 length -= m_pad.size();
135 out += m_pad.size();
136 }
137
138 if(m_pad_pos == m_pad.size()) {
139 add_counter(m_ctr_blocks);
140 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
141 m_pad_pos = 0;
142 }
143
144 copy_mem(out, &m_pad[0], length);
145 m_pad_pos += length;
146 BOTAN_ASSERT_NOMSG(m_pad_pos < m_pad.size());
147}
148
149void CTR_BE::set_iv_bytes(const uint8_t iv[], size_t iv_len) {
150 if(!valid_iv_length(iv_len)) {
151 throw Invalid_IV_Length(name(), iv_len);
152 }
153
154 m_iv.resize(m_block_size);
155 zeroise(m_iv);
156 copy_mem(&m_iv[0], iv, iv_len);
157
158 seek(0);
159}
160
161void CTR_BE::add_counter(const uint64_t counter) {
162 const size_t ctr_size = m_ctr_size;
163 const size_t ctr_blocks = m_ctr_blocks;
164 const size_t BS = m_block_size;
165
166 if(ctr_size == 4) {
167 const size_t off = (BS - 4);
168 const uint32_t low32 = static_cast<uint32_t>(counter + load_be<uint32_t>(&m_counter[off], 0));
169
170 for(size_t i = 0; i != ctr_blocks; ++i) {
171 store_be(uint32_t(low32 + i), &m_counter[i * BS + off]);
172 }
173 } else if(ctr_size == 8) {
174 const size_t off = (BS - 8);
175 const uint64_t low64 = counter + load_be<uint64_t>(&m_counter[off], 0);
176
177 for(size_t i = 0; i != ctr_blocks; ++i) {
178 store_be(uint64_t(low64 + i), &m_counter[i * BS + off]);
179 }
180 } else if(ctr_size == 16) {
181 const size_t off = (BS - 16);
182 uint64_t b0 = load_be<uint64_t>(&m_counter[off], 0);
183 uint64_t b1 = load_be<uint64_t>(&m_counter[off], 1);
184 b1 += counter;
185 b0 += (b1 < counter) ? 1 : 0; // carry
186
187 for(size_t i = 0; i != ctr_blocks; ++i) {
188 store_be(b0, &m_counter[i * BS + off]);
189 store_be(b1, &m_counter[i * BS + off + 8]);
190 b1 += 1;
191 b0 += (b1 == 0); // carry
192 }
193 } else {
194 for(size_t i = 0; i != ctr_blocks; ++i) {
195 uint64_t local_counter = counter;
196 uint16_t carry = static_cast<uint8_t>(local_counter);
197 for(size_t j = 0; (carry || local_counter) && j != ctr_size; ++j) {
198 const size_t off = i * BS + (BS - 1 - j);
199 const uint16_t cnt = static_cast<uint16_t>(m_counter[off]) + carry;
200 m_counter[off] = static_cast<uint8_t>(cnt);
201 local_counter = (local_counter >> 8);
202 carry = (cnt >> 8) + static_cast<uint8_t>(local_counter);
203 }
204 }
205 }
206}
207
208void CTR_BE::seek(uint64_t offset) {
210
211 const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size());
212
213 zeroise(m_counter);
214 BOTAN_ASSERT_NOMSG(m_counter.size() >= m_iv.size());
215 copy_mem(&m_counter[0], &m_iv[0], m_iv.size());
216
217 const size_t BS = m_block_size;
218
219 // Set m_counter blocks to IV, IV + 1, ... IV + n
220
221 if(m_ctr_size == 4 && BS >= 8) {
222 const uint32_t low32 = load_be<uint32_t>(&m_counter[BS - 4], 0);
223
224 if(m_ctr_blocks >= 4 && is_power_of_2(m_ctr_blocks)) {
225 size_t written = 1;
226 while(written < m_ctr_blocks) {
227 copy_mem(&m_counter[written * BS], &m_counter[0], BS * written);
228 written *= 2;
229 }
230 } else {
231 for(size_t i = 1; i != m_ctr_blocks; ++i) {
232 copy_mem(&m_counter[i * BS], &m_counter[0], BS - 4);
233 }
234 }
235
236 for(size_t i = 1; i != m_ctr_blocks; ++i) {
237 const uint32_t c = static_cast<uint32_t>(low32 + i);
238 store_be(c, &m_counter[(BS - 4) + i * BS]);
239 }
240 } else {
241 // do everything sequentially:
242 for(size_t i = 1; i != m_ctr_blocks; ++i) {
243 copy_mem(&m_counter[i * BS], &m_counter[(i - 1) * BS], BS);
244
245 for(size_t j = 0; j != m_ctr_size; ++j) {
246 if(++m_counter[i * BS + (BS - 1 - j)]) {
247 break;
248 }
249 }
250 }
251 }
252
253 if(base_counter > 0) {
254 add_counter(base_counter);
255 }
256
257 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
258 m_pad_pos = offset % m_counter.size();
259}
260} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
void clear() override
Definition ctr.cpp:37
size_t default_iv_length() const override
Definition ctr.cpp:45
bool has_keying_material() const override
Definition ctr.cpp:65
size_t buffer_size() const override
Definition ctr.cpp:53
Key_Length_Specification key_spec() const override
Definition ctr.cpp:57
bool valid_iv_length(size_t iv_len) const override
Definition ctr.cpp:49
void seek(uint64_t offset) override
Definition ctr.cpp:208
std::unique_ptr< StreamCipher > new_object() const override
Definition ctr.cpp:61
std::string name() const override
Definition ctr.cpp:76
CTR_BE(std::unique_ptr< BlockCipher > cipher)
Definition ctr.cpp:17
void set_iv(const uint8_t iv[], size_t iv_len)
void assert_key_material_set() const
Definition sym_algo.h:139
void zeroise(std::vector< T, Alloc > &vec)
Definition secmem.h:108
constexpr bool is_power_of_2(T arg)
Definition bit_ops.h:45
constexpr void store_be(T in, OutR &&out_range)
Definition loadstor.h:358
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:117
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
void carry(int64_t &h0, int64_t &h1)
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:340
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146