8#include <botan/internal/ctr.h>
10#include <botan/exceptn.h>
11#include <botan/internal/bit_ops.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/loadstor.h>
15#if defined(BOTAN_HAS_CTR_BE_AVX2) || defined(BOTAN_HAS_CTR_BE_SIMD32)
16 #include <botan/internal/cpuid.h>
22 m_cipher(std::move(
cipher)),
23 m_block_size(m_cipher->block_size()),
24 m_ctr_size(m_block_size),
25 m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
26 m_counter(m_cipher->parallel_bytes()),
27 m_pad(m_counter.size()),
31 m_cipher(std::move(
cipher)),
32 m_block_size(m_cipher->block_size()),
34 m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size),
35 m_counter(m_cipher->parallel_bytes()),
36 m_pad(m_counter.size()),
38 BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size,
"Invalid CTR-BE counter size");
54 return (iv_len <= m_block_size);
62 return m_cipher->key_spec();
66 return std::make_unique<CTR_BE>(m_cipher->new_object(), m_ctr_size);
70 return m_cipher->has_keying_material();
73void CTR_BE::key_schedule(std::span<const uint8_t> key) {
74 m_cipher->set_key(key);
81 if(m_ctr_size == m_block_size) {
82 return fmt(
"CTR-BE({})", m_cipher->name());
84 return fmt(
"CTR-BE({},{})", m_cipher->name(), m_ctr_size);
88void CTR_BE::cipher_bytes(
const uint8_t in[], uint8_t out[],
size_t length) {
91 const uint8_t* pad_bits = m_pad.data();
92 const size_t pad_size = m_pad.size();
97 const size_t avail = pad_size - m_pad_pos;
98 const size_t take = std::min(length, avail);
99 xor_buf(out, in, pad_bits + m_pad_pos, take);
106 add_counter(m_ctr_blocks);
107 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
114 [[maybe_unused]]
const bool can_use_bs16_ctr4_fastpath = m_block_size == 16 && m_ctr_size == 4 && pad_size % 64 == 0;
116#if defined(BOTAN_HAS_CTR_BE_AVX2)
118 const size_t consumed = ctr_proc_bs16_ctr4_avx2(in, out, length);
125#if defined(BOTAN_HAS_CTR_BE_SIMD32)
127 const size_t consumed = ctr_proc_bs16_ctr4_simd32(in, out, length);
134 while(length >= pad_size) {
135 xor_buf(out, in, pad_bits, pad_size);
140 add_counter(m_ctr_blocks);
141 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
146 xor_buf(out, in, pad_bits, length);
151void CTR_BE::generate_keystream(uint8_t out[],
size_t length) {
154 const size_t avail = m_pad.size() - m_pad_pos;
155 const size_t take = std::min(length, avail);
156 copy_mem(out, &m_pad[m_pad_pos], take);
161 while(length >= m_pad.size()) {
162 add_counter(m_ctr_blocks);
163 m_cipher->encrypt_n(m_counter.data(), out, m_ctr_blocks);
165 length -= m_pad.size();
169 if(m_pad_pos == m_pad.size()) {
170 add_counter(m_ctr_blocks);
171 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
175 copy_mem(out, m_pad.data(), length);
180void CTR_BE::set_iv_bytes(
const uint8_t iv[],
size_t iv_len) {
182 throw Invalid_IV_Length(
name(), iv_len);
185 m_iv.resize(m_block_size);
192void CTR_BE::add_counter(
const uint64_t counter) {
193 const size_t ctr_size = m_ctr_size;
194 const size_t ctr_blocks = m_ctr_blocks;
195 const size_t BS = m_block_size;
198 const size_t off = (BS - 4);
199 const uint32_t low32 =
static_cast<uint32_t
>(counter +
load_be<uint32_t>(&m_counter[off], 0));
201 for(
size_t i = 0; i != ctr_blocks; ++i) {
202 store_be(uint32_t(low32 + i), &m_counter[i * BS + off]);
204 }
else if(ctr_size == 8) {
205 const size_t off = (BS - 8);
208 for(
size_t i = 0; i != ctr_blocks; ++i) {
209 store_be(uint64_t(low64 + i), &m_counter[i * BS + off]);
211 }
else if(ctr_size == 16) {
212 const size_t off = (BS - 16);
216 b0 += (b1 < counter) ? 1 : 0;
218 for(
size_t i = 0; i != ctr_blocks; ++i) {
219 store_be(b0, &m_counter[i * BS + off]);
220 store_be(b1, &m_counter[i * BS + off + 8]);
227 for(
size_t i = 0; i != ctr_blocks; ++i) {
228 uint64_t local_counter = counter;
229 uint16_t
carry =
static_cast<uint8_t
>(local_counter);
230 for(
size_t j = 0; (
carry > 0 || local_counter > 0) && j != ctr_size; ++j) {
231 const size_t off = i * BS + (BS - 1 - j);
232 const uint16_t cnt =
static_cast<uint16_t
>(m_counter[off]) +
carry;
233 m_counter[off] =
static_cast<uint8_t
>(cnt);
234 local_counter = (local_counter >> 8);
235 carry = (cnt >> 8) +
static_cast<uint8_t
>(local_counter);
244 const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size());
248 copy_mem(m_counter.data(), m_iv.data(), m_iv.size());
250 const size_t BS = m_block_size;
254 if(m_ctr_size == 4 && BS >= 8) {
259 while(written < m_ctr_blocks) {
260 copy_mem(&m_counter[written * BS], &m_counter[0], BS * written);
264 for(
size_t i = 1; i != m_ctr_blocks; ++i) {
265 copy_mem(&m_counter[i * BS], &m_counter[0], BS - 4);
269 for(
size_t i = 1; i != m_ctr_blocks; ++i) {
270 const uint32_t c =
static_cast<uint32_t
>(low32 + i);
271 store_be(c, &m_counter[(BS - 4) + i * BS]);
275 for(
size_t i = 1; i != m_ctr_blocks; ++i) {
276 copy_mem(&m_counter[i * BS], &m_counter[(i - 1) * BS], BS);
278 for(
size_t j = 0; j != m_ctr_size; ++j) {
279 uint8_t& c = m_counter[i * BS + (BS - 1 - j)];
288 if(base_counter > 0) {
289 add_counter(base_counter);
292 m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks);
293 m_pad_pos = offset % m_counter.size();
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
static bool has(CPUID::Feature feat)
size_t default_iv_length() const override
bool has_keying_material() const override
size_t buffer_size() const override
Key_Length_Specification key_spec() const override
bool valid_iv_length(size_t iv_len) const override
void seek(uint64_t offset) override
std::unique_ptr< StreamCipher > new_object() const override
std::string name() const override
CTR_BE(std::unique_ptr< BlockCipher > cipher)
void set_iv(const uint8_t iv[], size_t iv_len)
void cipher(const uint8_t in[], uint8_t out[], size_t len)
void assert_key_material_set() const
BOTAN_FORCE_INLINE constexpr bool is_power_of_2(T arg)
void zeroise(std::vector< T, Alloc > &vec)
constexpr void copy_mem(T *out, const T *in, size_t n)
void zap(std::vector< T, Alloc > &vec)
std::string fmt(std::string_view format, const T &... args)
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)
constexpr auto store_be(ParamTs &&... params)
constexpr auto load_be(ParamTs &&... params)