10#include <botan/internal/cbc.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/mode_pad.h>
15#include <botan/internal/rounding.h>
21 if(m_padding && !m_padding->valid_blocksize(m_block_size)) {
22 throw Invalid_Argument(fmt(
"Padding {} cannot be used with {} in CBC mode", m_padding->name(), m_cipher->name()));
64 return m_cipher->has_keying_material();
67void CBC_Mode::key_schedule(std::span<const uint8_t> key) {
68 m_cipher->set_key(key);
72void CBC_Mode::start_msg(
const uint8_t nonce[],
size_t nonce_len) {
74 throw Invalid_IV_Length(
name(), nonce_len);
83 m_state.assign(nonce, nonce + nonce_len);
84 }
else if(m_state.empty()) {
85 m_state.resize(m_cipher->block_size());
95 if(input_length == 0) {
102size_t CBC_Encryption::process_msg(uint8_t buf[],
size_t sz) {
107 const size_t blocks = sz / BS;
113 for(
size_t i = 1; i != blocks; ++i) {
114 xor_buf(&buf[BS * i], &buf[BS * (i - 1)], BS);
118 state().assign(&buf[BS * (blocks - 1)], &buf[BS * blocks]);
130 const size_t bytes_in_final_block = (buffer.size() - offset) % BS;
154 uint8_t* buf = buffer.data() + offset;
155 const size_t sz = buffer.size() - offset;
167 for(
size_t i = 0; i != BS; ++i) {
168 std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
171 const size_t full_blocks = ((sz / BS) - 1) * BS;
172 const size_t final_bytes = sz - full_blocks;
173 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS,
"Left over size in expected range");
176 buffer.resize(full_blocks + offset);
182 for(
size_t i = 0; i != final_bytes - BS; ++i) {
183 last[i] ^= last[i + BS];
184 last[i + BS] ^= last[i];
201size_t CBC_Decryption::process_msg(uint8_t buf[],
size_t sz) {
207 size_t blocks = sz / BS;
210 const size_t to_proc = std::min(BS * blocks, m_tempbuf.size());
215 xor_buf(&m_tempbuf[BS], buf, to_proc - BS);
218 copy_mem(buf, m_tempbuf.data(), to_proc);
221 blocks -= to_proc / BS;
230 const size_t sz = buffer.size() - offset;
234 if(sz == 0 || sz % BS) {
235 throw Decoding_Error(
name() +
": Ciphertext not a multiple of block size");
240 const size_t pad_bytes = BS -
padding().
unpad(&buffer[buffer.size() - BS], BS);
241 buffer.resize(buffer.size() - pad_bytes);
242 if(pad_bytes == 0 &&
padding().
name() !=
"NoPadding") {
243 throw Decoding_Error(
"Invalid CBC padding");
263 const size_t sz = buffer.size() - offset;
264 uint8_t* buf = buffer.data() + offset;
275 for(
size_t i = 0; i != BS; ++i) {
276 std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
281 const size_t full_blocks = ((sz / BS) - 1) * BS;
282 const size_t final_bytes = sz - full_blocks;
283 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS,
"Left over size in expected range");
286 buffer.resize(full_blocks + offset);
291 xor_buf(last.data(), &last[BS], final_bytes - BS);
293 for(
size_t i = 0; i != final_bytes - BS; ++i) {
294 std::swap(last[i], last[i + BS]);
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
virtual size_t unpad(const uint8_t block[], size_t len) const =0
virtual void add_padding(secure_vector< uint8_t > &buffer, size_t final_block_bytes, size_t block_size) const =0
void encrypt(const uint8_t in[], uint8_t out[]) const
void decrypt(const uint8_t in[], uint8_t out[]) const
virtual void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const =0
virtual size_t block_size() const =0
size_t parallel_bytes() const
size_t minimum_final_size() const override
size_t output_length(size_t input_length) const override
size_t minimum_final_size() const override
size_t output_length(size_t input_length) const override
std::string name() const final
size_t update_granularity() const final
size_t ideal_granularity() const final
const BlockCipherModePaddingMethod & padding() const
size_t block_size() const
bool valid_nonce_length(size_t n) const override
CBC_Mode(std::unique_ptr< BlockCipher > cipher, std::unique_ptr< BlockCipherModePaddingMethod > padding)
size_t default_nonce_length() const final
const BlockCipher & cipher() const
secure_vector< uint8_t > & state()
Key_Length_Specification key_spec() const final
bool has_keying_material() const final
bool valid_nonce_length(size_t n) const override
size_t minimum_final_size() const override
size_t output_length(size_t input_length) const override
size_t minimum_final_size() const override
bool valid_nonce_length(size_t n) const override
void update(T &buffer, size_t offset=0)
virtual Key_Length_Specification key_spec() const =0
void zeroise(std::vector< T, Alloc > &vec)
std::string fmt(std::string_view format, const T &... args)
constexpr size_t round_up(size_t n, size_t align_to)
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
std::vector< T, secure_allocator< T > > secure_vector
constexpr void copy_mem(T *out, const T *in, size_t n)