Botan 3.12.0
Crypto and TLS for C&
ffi_cipher.cpp File Reference
#include <botan/ffi.h>
#include <botan/aead.h>
#include <botan/mem_ops.h>
#include <botan/internal/bit_ops.h>
#include <botan/internal/buffer_slicer.h>
#include <botan/internal/buffer_stuffer.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/scoped_cleanup.h>
#include <limits>

Go to the source code of this file.

Functions

int botan_cipher_clear (botan_cipher_t cipher)
int botan_cipher_destroy (botan_cipher_t cipher)
int botan_cipher_get_default_nonce_length (botan_cipher_t cipher, size_t *nl)
int botan_cipher_get_ideal_update_granularity (botan_cipher_t cipher, size_t *ug)
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_get_tag_length (botan_cipher_t cipher, size_t *tl)
int botan_cipher_get_update_granularity (botan_cipher_t cipher, size_t *ug)
int botan_cipher_init (botan_cipher_t *cipher, const char *cipher_name, uint32_t flags)
int botan_cipher_is_authenticated (botan_cipher_t cipher)
int botan_cipher_name (botan_cipher_t cipher, char *name, size_t *name_len)
int botan_cipher_output_length (botan_cipher_t cipher, size_t in_len, size_t *out_len)
int botan_cipher_query_keylen (botan_cipher_t cipher, size_t *out_minimum_keylength, size_t *out_maximum_keylength)
int botan_cipher_requires_entire_message (botan_cipher_t cipher)
int botan_cipher_reset (botan_cipher_t cipher)
int botan_cipher_set_associated_data (botan_cipher_t cipher, const uint8_t *ad, size_t ad_len)
int botan_cipher_set_key (botan_cipher_t cipher, const uint8_t *key, size_t key_len)
int botan_cipher_start (botan_cipher_t cipher_obj, const uint8_t *nonce, size_t nonce_len)
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_valid_nonce_length (botan_cipher_t cipher, size_t nl)

Function Documentation

◆ botan_cipher_clear()

int botan_cipher_clear ( botan_cipher_t hash)

Reset the key, nonce, AD and all other state on this cipher object

Definition at line 123 of file ffi_cipher.cpp.

123 {
124 return BOTAN_FFI_VISIT(cipher, [=](auto& c) {
125 cipher->buf().clear();
126 c.clear();
127 });
128}
#define BOTAN_FFI_VISIT(obj, lambda)
Definition ffi_util.h:158

References BOTAN_FFI_VISIT.

◆ botan_cipher_destroy()

int botan_cipher_destroy ( botan_cipher_t cipher)

Destroy the cipher object

Returns
0 if success, error if invalid object handle

Definition at line 119 of file ffi_cipher.cpp.

119 {
120 return BOTAN_FFI_CHECKED_DELETE(cipher);
121}
#define BOTAN_FFI_CHECKED_DELETE(o)
Definition ffi_util.h:188

References BOTAN_FFI_CHECKED_DELETE.

◆ botan_cipher_get_default_nonce_length()

int botan_cipher_get_default_nonce_length ( botan_cipher_t cipher,
size_t * nl )

Get the default nonce length of this cipher

Definition at line 324 of file ffi_cipher.cpp.

324 {
325 if(nl == nullptr) {
327 }
328 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *nl = c.default_nonce_length(); });
329}
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition ffi.h:133

References BOTAN_FFI_ERROR_NULL_POINTER, and BOTAN_FFI_VISIT.

◆ botan_cipher_get_ideal_update_granularity()

int botan_cipher_get_ideal_update_granularity ( botan_cipher_t cipher,
size_t * ug )

Return the ideal update granularity of the cipher. This is some multiple of the update granularity, reflecting possibilities for optimization.

Definition at line 338 of file ffi_cipher.cpp.

338 {
339 if(ug == nullptr) {
341 }
342 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *ug = c.ideal_granularity(); });
343}

References BOTAN_FFI_ERROR_NULL_POINTER, and BOTAN_FFI_VISIT.

◆ botan_cipher_get_keyspec()

int botan_cipher_get_keyspec ( botan_cipher_t cipher,
size_t * min_keylen,
size_t * max_keylen,
size_t * mod_keylen )

Get information about the supported key lengths.

Definition at line 156 of file ffi_cipher.cpp.

159 {
160 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
161 if(out_minimum_keylength) {
162 *out_minimum_keylength = c.key_spec().minimum_keylength();
163 }
164 if(out_maximum_keylength) {
165 *out_maximum_keylength = c.key_spec().maximum_keylength();
166 }
167 if(out_keylength_modulo) {
168 *out_keylength_modulo = c.key_spec().keylength_multiple();
169 }
170 });
171}

References BOTAN_FFI_VISIT.

◆ botan_cipher_get_tag_length()

int botan_cipher_get_tag_length ( botan_cipher_t cipher,
size_t * tag_size )

Get the tag length of the cipher (0 for non-AEAD modes)

Definition at line 345 of file ffi_cipher.cpp.

345 {
346 if(tl == nullptr) {
348 }
349 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *tl = c.tag_size(); });
350}

References BOTAN_FFI_ERROR_NULL_POINTER, and BOTAN_FFI_VISIT.

◆ botan_cipher_get_update_granularity()

int botan_cipher_get_update_granularity ( botan_cipher_t cipher,
size_t * ug )

Return the update granularity of the cipher; botan_cipher_update must be called with blocks of this size, except for the final.

Definition at line 331 of file ffi_cipher.cpp.

331 {
332 if(ug == nullptr) {
334 }
335 return BOTAN_FFI_VISIT(cipher, [=](const auto& /*c*/) { *ug = cipher->update_size(); });
336}

References BOTAN_FFI_ERROR_NULL_POINTER, and BOTAN_FFI_VISIT.

◆ botan_cipher_init()

int botan_cipher_init ( botan_cipher_t * cipher,
const char * name,
uint32_t flags )

Initialize a cipher object

Definition at line 99 of file ffi_cipher.cpp.

99 {
100 return ffi_guard_thunk(__func__, [=]() -> int {
101 if(any_null_pointers(cipher, cipher_name)) {
103 }
106
107 std::unique_ptr<Botan::Cipher_Mode> mode(Botan::Cipher_Mode::create(cipher_name, dir));
108 if(!mode) {
110 }
111
112 const size_t update_size = ffi_choose_update_size(*mode);
113 const size_t ideal_update_size = std::max(mode->ideal_granularity(), update_size);
114
115 return ffi_new_object(cipher, std::move(mode), update_size, ideal_update_size);
116 });
117}
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
#define BOTAN_CIPHER_INIT_FLAG_ENCRYPT
Definition ffi.h:669
#define BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
Definition ffi.h:668
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
Definition ffi.h:140
Flags flags(Flag flags)
Definition p11.h:1227
BOTAN_FFI_ERROR ffi_new_object(T *obj, Args &&... args)
Definition ffi_util.h:178
int ffi_guard_thunk(const char *func_name, T thunk)
Definition ffi_util.h:95
bool any_null_pointers(Ptrs... ptr)
Definition mem_utils.h:54

References Botan_FFI::any_null_pointers(), BOTAN_CIPHER_INIT_FLAG_ENCRYPT, BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION, BOTAN_FFI_ERROR_NOT_IMPLEMENTED, BOTAN_FFI_ERROR_NULL_POINTER, Botan::Cipher_Mode::create(), Botan::Decryption, Botan::Encryption, Botan_FFI::ffi_guard_thunk(), and Botan_FFI::ffi_new_object().

◆ botan_cipher_is_authenticated()

int botan_cipher_is_authenticated ( botan_cipher_t cipher)

Returns 1 iff the cipher provides authentication as well as confidentiality.

Definition at line 352 of file ffi_cipher.cpp.

352 {
353 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return c.authenticated() ? 1 : 0; });
354}

References BOTAN_FFI_VISIT.

◆ botan_cipher_name()

int botan_cipher_name ( botan_cipher_t cipher,
char * name,
size_t * name_len )

Return the name of the cipher object

Definition at line 360 of file ffi_cipher.cpp.

360 {
361 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return write_str_output(name, name_len, c.name()); });
362}
int write_str_output(char out[], size_t *out_len, const std::string &str)
Definition ffi_util.h:268

References BOTAN_FFI_VISIT, and Botan_FFI::write_str_output().

◆ botan_cipher_output_length()

int botan_cipher_output_length ( botan_cipher_t cipher,
size_t in_len,
size_t * out_len )

Return the output length of this cipher, for a particular input length.

Definition at line 137 of file ffi_cipher.cpp.

137 {
138 if(out_len == nullptr) {
140 }
141
142 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *out_len = c.output_length(in_len); });
143}

References BOTAN_FFI_ERROR_NULL_POINTER, and BOTAN_FFI_VISIT.

◆ botan_cipher_query_keylen()

int botan_cipher_query_keylen ( botan_cipher_t cipher,
size_t * out_minimum_keylength,
size_t * out_maximum_keylength )

Get information about the key lengths. Prefer botan_cipher_get_keyspec

Definition at line 145 of file ffi_cipher.cpp.

145 {
146 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
147 if(out_minimum_keylength) {
148 *out_minimum_keylength = c.key_spec().minimum_keylength();
149 }
150 if(out_maximum_keylength) {
151 *out_maximum_keylength = c.key_spec().maximum_keylength();
152 }
153 });
154}

References BOTAN_FFI_VISIT.

◆ botan_cipher_requires_entire_message()

int botan_cipher_requires_entire_message ( botan_cipher_t cipher)

Returns 1 iff the cipher requires the entire message before any encryption or decryption can be performed. No output data will be produced in botan_cipher_update() until the final flag is set.

Definition at line 356 of file ffi_cipher.cpp.

356 {
357 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return c.requires_entire_message() ? 1 : 0; });
358}

References BOTAN_FFI_VISIT.

◆ botan_cipher_reset()

int botan_cipher_reset ( botan_cipher_t cipher)

Reset the message specific state for this cipher. Without resetting the keys, this resets the nonce, and any state associated with any message bits that have been processed so far.

It is conceptually equivalent to calling botan_cipher_clear followed by botan_cipher_set_key with the original key.

Definition at line 130 of file ffi_cipher.cpp.

130 {
131 return BOTAN_FFI_VISIT(cipher, [=](auto& c) {
132 cipher->buf().clear();
133 c.reset();
134 });
135}

References BOTAN_FFI_VISIT.

◆ botan_cipher_set_associated_data()

int botan_cipher_set_associated_data ( botan_cipher_t cipher,
const uint8_t * ad,
size_t ad_len )

Set the associated data. Will fail if cipher is not an AEAD

Definition at line 310 of file ffi_cipher.cpp.

310 {
311 return BOTAN_FFI_VISIT(cipher, [=](auto& c) {
312 if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c)) {
313 aead->set_associated_data(ad, ad_len);
314 return BOTAN_FFI_SUCCESS;
315 }
317 });
318}
@ BOTAN_FFI_SUCCESS
Definition ffi.h:116
@ BOTAN_FFI_ERROR_BAD_PARAMETER
Definition ffi.h:134

References BOTAN_FFI_ERROR_BAD_PARAMETER, BOTAN_FFI_SUCCESS, and BOTAN_FFI_VISIT.

◆ botan_cipher_set_key()

int botan_cipher_set_key ( botan_cipher_t cipher,
const uint8_t * key,
size_t key_len )

Set the key for this cipher object

Definition at line 173 of file ffi_cipher.cpp.

173 {
174 if(key_len > 0 && key == nullptr) {
176 }
177 return BOTAN_FFI_VISIT(cipher, [=](auto& c) { c.set_key(key, key_len); });
178}

References BOTAN_FFI_ERROR_NULL_POINTER, and BOTAN_FFI_VISIT.

◆ botan_cipher_start()

int botan_cipher_start ( botan_cipher_t cipher,
const uint8_t * nonce,
size_t nonce_len )

Begin processing a new message using the provided nonce

Definition at line 180 of file ffi_cipher.cpp.

180 {
181 return ffi_guard_thunk(__func__, [=]() -> int {
182 Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
183 cipher.start(nonce, nonce_len);
184 return BOTAN_FFI_SUCCESS;
185 });
186}
void start(std::span< const uint8_t > nonce)
Definition cipher_mode.h:97
T & safe_get(botan_struct< T, M > *p)
Definition ffi_util.h:79

References BOTAN_FFI_SUCCESS, Botan_FFI::ffi_guard_thunk(), Botan_FFI::safe_get(), and Botan::Cipher_Mode::start().

◆ botan_cipher_update()

int botan_cipher_update ( botan_cipher_t cipher,
uint32_t flags,
uint8_t output[],
size_t output_size,
size_t * output_written,
const uint8_t input_bytes[],
size_t input_size,
size_t * input_consumed )

Encrypt/Decrypt some data and/or finalize the encryption/decryption.

This encrypts as many bytes from input_bytes into output_bytes as possible. Unless BOTAN_CIPHER_UPDATE_FLAG_FINAL is set, this function will consume bytes in multiples of botan_cipher_get_update_granularity(). input_consumed and output_written will be set accordingly and it is the caller's responsibility to adapt their buffers accordingly before calling this function again. Note that, unless BOTAN_CIPHER_UPDATE_FLAG_FINAL is set, the cipher will at most generate input_size output bytes.

Eventually, the caller must set the BOTAN_CIPHER_UPDATE_FLAG_FINAL flag to indicate that no more input will be provided. This will cause the cipher to consume all given input bytes and produce the final output; or return a BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE error if the given output buffer was too small. In the latter case, output_written will be set to the required buffer size. Calling again with BOTAN_CIPHER_UPDATE_FLAG_FINAL, a big enough buffer and no further input will then produce the final output.

Note that some ciphers require the entire message to be provided before any output is produced.

See also
botan_cipher_requires_entire_message().

Definition at line 188 of file ffi_cipher.cpp.

195 {
196 if(any_null_pointers(output_written, input_consumed)) {
198 }
199
200 return ffi_guard_thunk(__func__, [=]() -> int {
201 using namespace Botan;
202 Cipher_Mode& cipher = safe_get(cipher_obj);
203 secure_vector<uint8_t>& mbuf = cipher_obj->buf();
204
205 // If the cipher object's internal buffer contains residual data from
206 // a previous invocation, we can be sure that botan_cipher_update() was
207 // called with the final flag set but not enough buffer space was provided
208 // to accommodate the final output.
209 const bool was_finished_before = !mbuf.empty();
210 const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL) != 0;
211
212 // Bring the output variables into a defined state.
213 *output_written = 0;
214 *input_consumed = 0;
215
216 // Once the final flag was set once, it must always be set for
217 // consecutive invocations.
218 if(was_finished_before && !final_input) {
220 }
221
222 // If the final flag was set in a previous invocation, no more input
223 // data can be processed.
224 if(was_finished_before && input_size > 0) {
226 }
227
228 // Make sure that we always clear the internal buffer before returning
229 // or aborting this invocation due to an exception.
230 auto clean_buffer = scoped_cleanup([&mbuf] { mbuf.clear(); });
231
232 if(final_input) {
233 // If the final flag is set for the first time, we need to process the
234 // remaining input data and then finalize the cipher object.
235 if(!was_finished_before) {
236 *input_consumed = input_size;
237 mbuf.resize(input_size);
238 copy_mem(mbuf, std::span(input, input_size));
239
240 try {
241 cipher.finish(mbuf);
244 }
245 }
246
247 // At this point, the cipher object is finalized (potentially in a
248 // previous invocation) and we can copy the final output to the caller.
249 *output_written = mbuf.size();
250
251 // Not enough space to copy the final output out to the caller.
252 // Inform them how much space we need for a successful operation.
253 if(output_size < mbuf.size()) {
254 // This is the only place where mbuf is not cleared before returning.
255 clean_buffer.disengage();
257 }
258
259 // Copy the final output to the caller, mbuf is cleared afterwards.
260 copy_mem(std::span(output, mbuf.size()), mbuf);
261 } else {
262 // Process data in a streamed fashion without finalizing. No data is
263 // ever retained in the cipher object's internal buffer. If we run out
264 // of either input data or output capacity, we stop and report that not
265 // all bytes were processed via *output_written and *input_consumed.
266
267 BufferSlicer in({input, input_size});
268 BufferStuffer out({output, output_size});
269
270 // Helper function to do blockwise processing of data.
271 auto blockwise_update = [&](const size_t granularity) {
272 if(granularity == 0) {
273 return;
274 }
275
276 const size_t expected_output_per_iteration = cipher.requires_entire_message() ? 0 : granularity;
277 mbuf.resize(granularity);
278
279 while(in.remaining() >= granularity && out.remaining_capacity() >= expected_output_per_iteration) {
280 copy_mem(mbuf, in.take(granularity));
281 const auto written_bytes = cipher.process(mbuf);
282 BOTAN_DEBUG_ASSERT(written_bytes == expected_output_per_iteration);
283 if(written_bytes > 0) {
284 BOTAN_ASSERT_NOMSG(written_bytes <= granularity);
285 copy_mem(out.next(written_bytes), std::span(mbuf).first(written_bytes));
286 }
287 }
288 };
289
290 // First, process as much data as possible in chunks of ideal granularity
291 blockwise_update(cipher_obj->ideal_update_size());
292
293 // Then process the remaining bytes in chunks of update_size() or, in one go
294 // if update_size() is equal to 1 --> i.e. likely a stream cipher.
295 const bool is_stream_cipher = (cipher_obj->update_size() == 1);
296 const size_t tail_granularity =
297 is_stream_cipher ? std::min(in.remaining(), out.remaining_capacity()) : cipher_obj->update_size();
298 BOTAN_DEBUG_ASSERT(tail_granularity < cipher_obj->ideal_update_size());
299 blockwise_update(tail_granularity);
300
301 // Inform the caller about the amount of data processed.
302 *output_written = output_size - out.remaining_capacity();
303 *input_consumed = input_size - in.remaining();
304 }
305
306 return BOTAN_FFI_SUCCESS;
307 });
308}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
Helper class to ease in-place marshalling of concatenated fixed-length values.
void finish(secure_vector< uint8_t > &final_block, size_t offset=0)
virtual bool requires_entire_message() const
size_t process(std::span< uint8_t > msg)
Helper class to create a RAII-style cleanup callback.
#define BOTAN_CIPHER_UPDATE_FLAG_FINAL
Definition ffi.h:763
@ BOTAN_FFI_ERROR_INVALID_OBJECT_STATE
Definition ffi.h:137
@ BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE
Definition ffi.h:124
@ BOTAN_FFI_ERROR_BAD_MAC
Definition ffi.h:121
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68

References Botan_FFI::any_null_pointers(), BOTAN_ASSERT_NOMSG, BOTAN_CIPHER_UPDATE_FLAG_FINAL, BOTAN_DEBUG_ASSERT, BOTAN_FFI_ERROR_BAD_MAC, BOTAN_FFI_ERROR_BAD_PARAMETER, BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, BOTAN_FFI_ERROR_NULL_POINTER, BOTAN_FFI_SUCCESS, Botan::copy_mem(), Botan_FFI::ffi_guard_thunk(), Botan::Cipher_Mode::finish(), Botan::Cipher_Mode::process(), Botan::Cipher_Mode::requires_entire_message(), and Botan_FFI::safe_get().

◆ botan_cipher_valid_nonce_length()

int botan_cipher_valid_nonce_length ( botan_cipher_t cipher,
size_t nl )

Return if the specified nonce length is valid for this cipher

Definition at line 320 of file ffi_cipher.cpp.

320 {
321 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return c.valid_nonce_length(nl) ? 1 : 0; });
322}

References BOTAN_FFI_VISIT.