10#include <botan/internal/bit_ops.h>
11#include <botan/internal/ffi_util.h>
12#include <botan/internal/stl_util.h>
20struct botan_cipher_struct final :
public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C> {
22 explicit botan_cipher_struct(std::unique_ptr<Botan::Cipher_Mode> x,
24 size_t ideal_update_size) :
25 botan_struct(std::move(x)), m_update_size(update_size), m_ideal_update_size(ideal_update_size) {
27 m_buf.reserve(m_ideal_update_size);
32 size_t update_size()
const {
return m_update_size; }
34 size_t ideal_update_size()
const {
return m_ideal_update_size; }
39 size_t m_ideal_update_size;
65 if(minimum_final_size == 0 || update_granularity > minimum_final_size) {
67 return update_granularity;
72 if(ideal_update_granularity % minimum_final_size == 0 && minimum_final_size * 2 <= ideal_update_granularity) {
73 return minimum_final_size * 2;
79 const size_t b1 = size_t(1) <<
Botan::ceil_log2(
static_cast<uint16_t
>(minimum_final_size));
80 if(ideal_update_granularity % b1 == 0) {
88 size_t b2 = minimum_final_size + 1;
89 for(; b2 < ideal_update_granularity && ideal_update_granularity % b2 != 0; ++b2) {}
106 const size_t update_size = ffi_choose_update_size(*mode);
107 const size_t ideal_update_size = std::max(mode->ideal_granularity(), update_size);
109 return ffi_new_object(cipher, std::move(mode), update_size, ideal_update_size);
126 if(out_len ==
nullptr) {
130 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) { *out_len = c.output_length(in_len); });
135 *out_minimum_keylength = c.key_spec().minimum_keylength();
136 *out_maximum_keylength = c.key_spec().maximum_keylength();
141 size_t* out_minimum_keylength,
142 size_t* out_maximum_keylength,
143 size_t* out_keylength_modulo) {
145 if(out_minimum_keylength) {
146 *out_minimum_keylength = c.key_spec().minimum_keylength();
148 if(out_maximum_keylength) {
149 *out_maximum_keylength = c.key_spec().maximum_keylength();
151 if(out_keylength_modulo) {
152 *out_keylength_modulo = c.key_spec().keylength_multiple();
158 return BOTAN_FFI_VISIT(cipher, [=](
auto& c) { c.set_key(key, key_len); });
164 cipher.
start(nonce, nonce_len);
173 size_t* output_written,
174 const uint8_t input[],
176 size_t* input_consumed) {
178 using namespace Botan;
186 const bool was_finished_before = !mbuf.empty();
195 if(was_finished_before && !final_input) {
201 if(was_finished_before && input_size > 0) {
212 if(!was_finished_before) {
213 *input_consumed = input_size;
214 mbuf.resize(input_size);
215 copy_mem(mbuf, std::span(input, input_size));
226 *output_written = mbuf.size();
230 if(output_size < mbuf.size()) {
232 clean_buffer.disengage();
237 copy_mem(std::span(output, mbuf.size()), mbuf);
248 auto blockwise_update = [&](
const size_t granularity) {
249 if(granularity == 0) {
254 mbuf.resize(granularity);
256 while(in.remaining() >= granularity && out.remaining_capacity() >= expected_output_per_iteration) {
257 copy_mem(mbuf, in.take(granularity));
258 const auto written_bytes = cipher.
process(mbuf);
260 if(written_bytes > 0) {
262 copy_mem(out.next(written_bytes), std::span(mbuf).first(written_bytes));
268 blockwise_update(cipher_obj->ideal_update_size());
272 const bool is_stream_cipher = (cipher_obj->update_size() == 1);
273 const size_t tail_granularity =
274 is_stream_cipher ? std::min(in.remaining(), out.remaining_capacity()) : cipher_obj->update_size();
276 blockwise_update(tail_granularity);
279 *output_written = output_size - out.remaining_capacity();
280 *input_consumed = input_size - in.remaining();
290 aead->set_associated_data(ad, ad_len);
298 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) {
return c.valid_nonce_length(nl) ? 1 : 0; });
302 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) { *nl = c.default_nonce_length(); });
306 return BOTAN_FFI_VISIT(cipher, [=](
const auto& ) { *ug = cipher->update_size(); });
310 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) { *ug = c.ideal_granularity(); });
314 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) { *tl = c.tag_size(); });
318 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) {
return c.authenticated() ? 1 : 0; });
322 return BOTAN_FFI_VISIT(cipher, [=](
const auto& c) {
return c.requires_entire_message() ? 1 : 0; });
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
Helper class to ease in-place marshalling of concatenated fixed-length values.
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
void start(std::span< const uint8_t > nonce)
void finish(secure_vector< uint8_t > &final_block, size_t offset=0)
virtual bool requires_entire_message() const
virtual size_t ideal_granularity() const =0
size_t process(std::span< uint8_t > msg)
virtual size_t minimum_final_size() const =0
virtual size_t update_granularity() const =0
Helper class to create a RAII-style cleanup callback.
#define BOTAN_CIPHER_INIT_FLAG_ENCRYPT
#define BOTAN_CIPHER_UPDATE_FLAG_FINAL
#define BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
@ BOTAN_FFI_ERROR_NULL_POINTER
@ BOTAN_FFI_ERROR_INVALID_OBJECT_STATE
@ BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE
@ BOTAN_FFI_ERROR_BAD_MAC
@ BOTAN_FFI_ERROR_BAD_PARAMETER
struct botan_cipher_struct * botan_cipher_t
int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
int botan_cipher_requires_entire_message(botan_cipher_t cipher)
int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t *out_len)
int botan_cipher_reset(botan_cipher_t cipher)
int botan_cipher_destroy(botan_cipher_t cipher)
int botan_cipher_name(botan_cipher_t cipher, char *name, size_t *name_len)
int botan_cipher_set_associated_data(botan_cipher_t cipher, const uint8_t *ad, size_t ad_len)
int botan_cipher_start(botan_cipher_t cipher_obj, const uint8_t *nonce, size_t nonce_len)
int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t *tl)
int botan_cipher_update(botan_cipher_t cipher_obj, uint32_t flags, uint8_t output[], size_t output_size, size_t *output_written, const uint8_t input[], size_t input_size, size_t *input_consumed)
Encrypt/Decrypt some data and/or finalize the encryption/decryption.
int botan_cipher_get_keyspec(botan_cipher_t cipher, size_t *out_minimum_keylength, size_t *out_maximum_keylength, size_t *out_keylength_modulo)
int botan_cipher_set_key(botan_cipher_t cipher, const uint8_t *key, size_t key_len)
int botan_cipher_get_ideal_update_granularity(botan_cipher_t cipher, size_t *ug)
int botan_cipher_is_authenticated(botan_cipher_t cipher)
int botan_cipher_clear(botan_cipher_t cipher)
int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t *nl)
int botan_cipher_init(botan_cipher_t *cipher, const char *cipher_name, uint32_t flags)
int botan_cipher_query_keylen(botan_cipher_t cipher, size_t *out_minimum_keylength, size_t *out_maximum_keylength)
int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t *ug)
#define BOTAN_FFI_VISIT(obj, lambda)
#define BOTAN_FFI_CHECKED_DELETE(o)
T & safe_get(botan_struct< T, M > *p)
BOTAN_FFI_ERROR ffi_new_object(T *obj, Args &&... args)
int ffi_guard_thunk(const char *func_name, T thunk)
int write_str_output(char out[], size_t *out_len, const std::string &str)
constexpr void copy_mem(T *out, const T *in, size_t n)
constexpr uint8_t ceil_log2(T x)
std::vector< T, secure_allocator< T > > secure_vector
botan_struct(std::unique_ptr< Botan::Cipher_Mode > obj)