10#include <botan/internal/cbc.h>
12#include <botan/exceptn.h>
13#include <botan/mem_ops.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/int_utils.h>
16#include <botan/internal/mode_pad.h>
22 if(m_padding && !m_padding->valid_blocksize(m_block_size)) {
23 throw Invalid_Argument(fmt(
"Padding {} cannot be used with {} in CBC mode", m_padding->name(), m_cipher->name()));
65 return m_cipher->has_keying_material();
68void CBC_Mode::key_schedule(std::span<const uint8_t> key) {
69 m_cipher->set_key(key);
73void CBC_Mode::start_msg(
const uint8_t nonce[],
size_t nonce_len) {
75 throw Invalid_IV_Length(
name(), nonce_len);
84 m_state.assign(nonce, nonce + nonce_len);
85 }
else if(m_state.empty()) {
86 m_state.resize(m_cipher->block_size());
99size_t CBC_Encryption::process_msg(uint8_t buf[],
size_t sz) {
104 const size_t blocks = sz / BS;
110 for(
size_t i = 1; i != blocks; ++i) {
111 xor_buf(&buf[BS * i], &buf[BS * (i - 1)], BS);
115 state().assign(&buf[BS * (blocks - 1)], &buf[BS * blocks]);
127 const size_t output_bytes =
129 const size_t bytes_in_final_block = (buffer.size() - offset) % BS;
130 buffer.resize(output_bytes);
135 BOTAN_ARG_CHECK(buffer.size() % BS == offset % BS,
"CBC input is not full blocks (NoPadding)");
155 uint8_t* buf = buffer.data() + offset;
156 const size_t sz = buffer.size() - offset;
168 for(
size_t i = 0; i != BS; ++i) {
169 std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
172 const size_t full_blocks = ((sz / BS) - 1) * BS;
173 const size_t final_bytes = sz - full_blocks;
174 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS,
"Left over size in expected range");
177 buffer.resize(full_blocks + offset);
183 for(
size_t i = 0; i != final_bytes - BS; ++i) {
184 last[i] ^= last[i + BS];
185 last[i + BS] ^= last[i];
202size_t CBC_Decryption::process_msg(uint8_t buf[],
size_t sz) {
208 size_t blocks = sz / BS;
211 const size_t to_proc = std::min(BS * blocks, m_tempbuf.size());
216 xor_buf(&m_tempbuf[BS], buf, to_proc - BS);
219 copy_mem(buf, m_tempbuf.data(), to_proc);
222 blocks -= to_proc / BS;
231 const size_t sz = buffer.size() - offset;
235 if(sz == 0 || sz % BS != 0) {
236 throw Decoding_Error(
name() +
": Ciphertext not a multiple of block size");
241 const size_t pad_bytes = BS -
padding().
unpad(std::span{buffer}.last(BS));
242 buffer.resize(buffer.size() - pad_bytes);
243 if(pad_bytes == 0 &&
padding().
name() !=
"NoPadding") {
244 clear_mem(std::span{buffer}.subspan(offset));
245 throw Decoding_Error(
"Invalid CBC padding");
265 const size_t sz = buffer.size() - offset;
266 uint8_t* buf = buffer.data() + offset;
277 for(
size_t i = 0; i != BS; ++i) {
278 std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
283 const size_t full_blocks = ((sz / BS) - 1) * BS;
284 const size_t final_bytes = sz - full_blocks;
285 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS,
"Left over size in expected range");
288 buffer.resize(full_blocks + offset);
293 xor_buf(last.data(), &last[BS], final_bytes - BS);
295 for(
size_t i = 0; i != final_bytes - BS; ++i) {
296 std::swap(last[i], last[i + BS]);
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
virtual size_t output_length(size_t input_length, size_t block_size) const
size_t unpad(std::span< const uint8_t > last_block) const
virtual void add_padding(std::span< uint8_t > buffer, size_t final_block_bytes, size_t block_size) const
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
constexpr T add_or_throw(T a, T b, std::string_view msg)
void zeroise(std::vector< T, Alloc > &vec)
std::string fmt(std::string_view format, const T &... args)
constexpr void copy_mem(T *out, const T *in, size_t n)
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 clear_mem(T *ptr, size_t n)