10#include <botan/internal/cbc.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/mode_pad.h>
14#include <botan/internal/rounding.h>
18CBC_Mode::CBC_Mode(std::unique_ptr<BlockCipher> cipher, std::unique_ptr<BlockCipherModePaddingMethod> padding) :
19 m_cipher(std::move(cipher)), m_padding(std::move(padding)), m_block_size(m_cipher->block_size()) {
20 if(m_padding && !m_padding->valid_blocksize(m_block_size)) {
21 throw Invalid_Argument(
fmt(
"Padding {} cannot be used with {} in CBC mode", m_padding->name(), m_cipher->name()));
63 return m_cipher->has_keying_material();
66void CBC_Mode::key_schedule(std::span<const uint8_t> key) {
67 m_cipher->set_key(key);
71void CBC_Mode::start_msg(
const uint8_t nonce[],
size_t nonce_len) {
73 throw Invalid_IV_Length(
name(), nonce_len);
82 m_state.assign(nonce, nonce + nonce_len);
83 }
else if(m_state.empty()) {
84 m_state.resize(m_cipher->block_size());
94 if(input_length == 0) {
101size_t CBC_Encryption::process_msg(uint8_t buf[],
size_t sz) {
106 const size_t blocks = sz / BS;
112 for(
size_t i = 1; i != blocks; ++i) {
113 xor_buf(&buf[BS * i], &buf[BS * (i - 1)], BS);
117 state().assign(&buf[BS * (blocks - 1)], &buf[BS * blocks]);
129 const size_t bytes_in_final_block = (buffer.size() - offset) % BS;
153 uint8_t* buf = buffer.data() + offset;
154 const size_t sz = buffer.size() - offset;
166 for(
size_t i = 0; i != BS; ++i) {
167 std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
170 const size_t full_blocks = ((sz / BS) - 1) * BS;
171 const size_t final_bytes = sz - full_blocks;
172 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS,
"Left over size in expected range");
175 buffer.resize(full_blocks + offset);
181 for(
size_t i = 0; i != final_bytes - BS; ++i) {
182 last[i] ^= last[i + BS];
183 last[i + BS] ^= last[i];
200size_t CBC_Decryption::process_msg(uint8_t buf[],
size_t sz) {
206 size_t blocks = sz / BS;
209 const size_t to_proc = std::min(BS * blocks, m_tempbuf.size());
214 xor_buf(&m_tempbuf[BS], buf, to_proc - BS);
217 copy_mem(buf, m_tempbuf.data(), to_proc);
220 blocks -= to_proc / BS;
229 const size_t sz = buffer.size() - offset;
233 if(sz == 0 || sz % BS) {
234 throw Decoding_Error(
name() +
": Ciphertext not a multiple of block size");
239 const size_t pad_bytes = BS -
padding().
unpad(&buffer[buffer.size() - BS], BS);
240 buffer.resize(buffer.size() - pad_bytes);
241 if(pad_bytes == 0 &&
padding().
name() !=
"NoPadding") {
242 throw Decoding_Error(
"Invalid CBC padding");
262 const size_t sz = buffer.size() - offset;
263 uint8_t* buf = buffer.data() + offset;
274 for(
size_t i = 0; i != BS; ++i) {
275 std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
280 const size_t full_blocks = ((sz / BS) - 1) * BS;
281 const size_t final_bytes = sz - full_blocks;
282 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS,
"Left over size in expected range");
285 buffer.resize(full_blocks + offset);
290 xor_buf(last.data(), &last[BS], final_bytes - BS);
292 for(
size_t i = 0; i != final_bytes - BS; ++i) {
293 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
virtual Key_Length_Specification key_spec() const =0
int(* update)(CTX *, const void *, CC_LONG len)
void zeroise(std::vector< T, Alloc > &vec)
std::string fmt(std::string_view format, const T &... args)
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)
size_t round_up(size_t n, size_t align_to)