Botan 3.3.0
Crypto and TLS for C&
ffi_cipher.cpp
Go to the documentation of this file.
1/*
2* (C) 2015,2017 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/ffi.h>
8
9#include <botan/aead.h>
10#include <botan/internal/ffi_util.h>
11
12extern "C" {
13
14using namespace Botan_FFI;
15
16struct botan_cipher_struct final : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C> {
17 public:
18 explicit botan_cipher_struct(std::unique_ptr<Botan::Cipher_Mode> x, size_t update_size) :
19 botan_struct(std::move(x)), m_update_size(update_size) {
20 m_buf.reserve(m_update_size);
21 }
22
23 Botan::secure_vector<uint8_t>& buf() { return m_buf; }
24
25 size_t update_size() const { return m_update_size; }
26
27 private:
29 size_t m_update_size;
30};
31
32namespace {
33
34size_t ffi_choose_update_size(Botan::Cipher_Mode& mode) {
35 const size_t update_granularity = mode.update_granularity();
36 const size_t minimum_final_size = mode.minimum_final_size();
37
38 /*
39 * Return the minimum possible granularity given the FFI API constraints that
40 * we require the returned size be > minimum final size.
41 *
42 * If the minimum final size is zero, or the update_granularity is
43 * already greater, just use that.
44 *
45 * Otherwise scale the update_granularity to a sufficient size
46 * to be greater than the minimum.
47 */
48 if(minimum_final_size == 0 || update_granularity > minimum_final_size) {
49 BOTAN_ASSERT_NOMSG(update_granularity > 0);
50 return update_granularity;
51 }
52
53 size_t buf_size = std::max(update_granularity, minimum_final_size + 1);
54 if(buf_size % update_granularity != 0) {
55 buf_size += update_granularity - (buf_size % update_granularity);
56 }
57
58 return buf_size;
59}
60
61} // namespace
62
63int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags) {
64 return ffi_guard_thunk(__func__, [=]() -> int {
67
68 std::unique_ptr<Botan::Cipher_Mode> mode(Botan::Cipher_Mode::create(cipher_name, dir));
69 if(!mode) {
71 }
72
73 const size_t update_size = ffi_choose_update_size(*mode);
74
75 *cipher = new botan_cipher_struct(std::move(mode), update_size);
76 return BOTAN_FFI_SUCCESS;
77 });
78}
79
83
85 return BOTAN_FFI_VISIT(cipher, [](auto& c) { c.clear(); });
86}
87
89 return BOTAN_FFI_VISIT(cipher, [](auto& c) { c.reset(); });
90}
91
92int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t* out_len) {
93 if(out_len == nullptr) {
95 }
96
97 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *out_len = c.output_length(in_len); });
98}
99
100int botan_cipher_query_keylen(botan_cipher_t cipher, size_t* out_minimum_keylength, size_t* out_maximum_keylength) {
101 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
102 *out_minimum_keylength = c.key_spec().minimum_keylength();
103 *out_maximum_keylength = c.key_spec().maximum_keylength();
104 });
105}
106
108 size_t* out_minimum_keylength,
109 size_t* out_maximum_keylength,
110 size_t* out_keylength_modulo) {
111 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
112 if(out_minimum_keylength)
113 *out_minimum_keylength = c.key_spec().minimum_keylength();
114 if(out_maximum_keylength)
115 *out_maximum_keylength = c.key_spec().maximum_keylength();
116 if(out_keylength_modulo)
117 *out_keylength_modulo = c.key_spec().keylength_multiple();
118 });
119}
120
121int botan_cipher_set_key(botan_cipher_t cipher, const uint8_t* key, size_t key_len) {
122 return BOTAN_FFI_VISIT(cipher, [=](auto& c) { c.set_key(key, key_len); });
123}
124
125int botan_cipher_start(botan_cipher_t cipher_obj, const uint8_t* nonce, size_t nonce_len) {
126 return ffi_guard_thunk(__func__, [=]() -> int {
127 Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
128 cipher.start(nonce, nonce_len);
129 return BOTAN_FFI_SUCCESS;
130 });
131}
132
134 uint32_t flags,
135 uint8_t output_ptr[],
136 size_t orig_output_size,
137 size_t* output_written,
138 const uint8_t input_ptr[],
139 size_t orig_input_size,
140 size_t* input_consumed) {
141 return ffi_guard_thunk(__func__, [=]() -> int {
142 size_t input_size = orig_input_size;
143 size_t output_size = orig_output_size;
144 const uint8_t* input = input_ptr;
145 uint8_t* output = output_ptr;
146
147 using namespace Botan;
148 Cipher_Mode& cipher = safe_get(cipher_obj);
149 secure_vector<uint8_t>& mbuf = cipher_obj->buf();
150
151 const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL);
152
153 if(final_input) {
154 mbuf.assign(input, input + input_size);
155 *input_consumed = input_size;
156 *output_written = 0;
157
158 try {
159 cipher.finish(mbuf);
162 }
163
164 *output_written = mbuf.size();
165
166 if(mbuf.size() <= output_size) {
167 copy_mem(output, mbuf.data(), mbuf.size());
168 mbuf.clear();
169 return BOTAN_FFI_SUCCESS;
170 }
171
172 return -1;
173 }
174
175 if(input_size == 0) {
176 // Currently must take entire buffer in this case
177 *output_written = mbuf.size();
178 if(output_size >= mbuf.size()) {
179 copy_mem(output, mbuf.data(), mbuf.size());
180 mbuf.clear();
181 return BOTAN_FFI_SUCCESS;
182 }
183
184 return -1;
185 }
186
187 const size_t ud = cipher_obj->update_size();
188
189 mbuf.resize(ud);
190 size_t taken = 0, written = 0;
191
192 while(input_size >= ud && output_size >= ud) {
193 // FIXME we can use process here and avoid the copy
194 copy_mem(mbuf.data(), input, ud);
195 cipher.update(mbuf);
196
197 input_size -= ud;
198 copy_mem(output, mbuf.data(), ud);
199 input += ud;
200 taken += ud;
201
202 output_size -= ud;
203 output += ud;
204 written += ud;
205 }
206
207 *output_written = written;
208 *input_consumed = taken;
209
210 return BOTAN_FFI_SUCCESS;
211 });
212}
213
214int botan_cipher_set_associated_data(botan_cipher_t cipher, const uint8_t* ad, size_t ad_len) {
215 return BOTAN_FFI_VISIT(cipher, [=](auto& c) {
216 if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c)) {
217 aead->set_associated_data(ad, ad_len);
218 return BOTAN_FFI_SUCCESS;
219 }
221 });
222}
223
225 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return c.valid_nonce_length(nl) ? 1 : 0; });
226}
227
229 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *nl = c.default_nonce_length(); });
230}
231
233 return BOTAN_FFI_VISIT(cipher, [=](const auto& /*c*/) { *ug = cipher->update_size(); });
234}
235
237 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *ug = c.ideal_granularity(); });
238}
239
241 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *tl = c.tag_size(); });
242}
243
245 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return c.authenticated() ? 1 : 0; });
246}
247
248int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len) {
249 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return write_str_output(name, name_len, c.name()); });
250}
251}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
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)
Definition cipher_mode.h:89
void finish(secure_vector< uint8_t > &final_block, size_t offset=0)
void update(T &buffer, size_t offset=0)
virtual size_t minimum_final_size() const =0
virtual size_t update_granularity() const =0
std::string name
int(* final)(unsigned char *, CTX *)
#define BOTAN_CIPHER_INIT_FLAG_ENCRYPT
Definition ffi.h:513
#define BOTAN_CIPHER_UPDATE_FLAG_FINAL
Definition ffi.h:600
#define BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
Definition ffi.h:512
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
Definition ffi.h:110
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition ffi.h:104
@ BOTAN_FFI_SUCCESS
Definition ffi.h:89
@ BOTAN_FFI_ERROR_BAD_MAC
Definition ffi.h:93
@ BOTAN_FFI_ERROR_BAD_PARAMETER
Definition ffi.h:105
struct botan_cipher_struct * botan_cipher_t
Definition ffi.h:510
int botan_cipher_update(botan_cipher_t cipher_obj, uint32_t flags, uint8_t output_ptr[], size_t orig_output_size, size_t *output_written, const uint8_t input_ptr[], size_t orig_input_size, size_t *input_consumed)
int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
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_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)
Definition ffi_util.h:124
#define BOTAN_FFI_CHECKED_DELETE(o)
Definition ffi_util.h:143
int write_str_output(uint8_t out[], size_t *out_len, std::string_view str)
Definition ffi_util.h:205
T & safe_get(botan_struct< T, M > *p)
Definition ffi_util.h:63
int ffi_guard_thunk(const char *func_name, const std::function< int()> &thunk)
Definition ffi.cpp:116
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61