Botan 3.0.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#include <botan/internal/ffi_util.h>
9#include <botan/aead.h>
10
11extern "C" {
12
13using namespace Botan_FFI;
14
15struct botan_cipher_struct final : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C>
16 {
17 public:
18 explicit botan_cipher_struct(std::unique_ptr<Botan::Cipher_Mode> x, size_t update_size) :
19 botan_struct(std::move(x)),
20 m_update_size(update_size)
21 {
22 m_buf.reserve(m_update_size);
23 }
24
25 Botan::secure_vector<uint8_t>& buf() { return m_buf; }
26 size_t update_size() const { return m_update_size; }
27
28 private:
30 size_t m_update_size;
31 };
32
33namespace {
34
35size_t ffi_choose_update_size(Botan::Cipher_Mode& mode)
36 {
37 const size_t update_granularity = mode.update_granularity();
38 const size_t minimum_final_size = mode.minimum_final_size();
39
40 /*
41 * Return the minimum possible granularity given the FFI API constraints that
42 * we require the returned size be > minimum final size.
43 *
44 * If the minimum final size is zero, or the update_granularity is
45 * already greater, just use that.
46 *
47 * Otherwise scale the update_granularity to a sufficient size
48 * to be greater than the minimum.
49 */
50 if(minimum_final_size == 0 || update_granularity > minimum_final_size)
51 {
52 BOTAN_ASSERT_NOMSG(update_granularity > 0);
53 return update_granularity;
54 }
55
56 size_t buf_size = std::max(update_granularity, minimum_final_size + 1);
57 if(buf_size % update_granularity != 0)
58 buf_size += update_granularity - (buf_size % update_granularity);
59
60 return buf_size;
61 }
62
63}
64
65int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags)
66 {
67 return ffi_guard_thunk(__func__, [=]() -> int {
69 const Botan::Cipher_Dir dir = encrypt_p ?
71
72 std::unique_ptr<Botan::Cipher_Mode> mode(Botan::Cipher_Mode::create(cipher_name, dir));
73 if(!mode)
75
76 const size_t update_size = ffi_choose_update_size(*mode);
77
78 *cipher = new botan_cipher_struct(std::move(mode), update_size);
79 return BOTAN_FFI_SUCCESS;
80 });
81 }
82
84 {
85 return BOTAN_FFI_CHECKED_DELETE(cipher);
86 }
87
89 {
90 return BOTAN_FFI_VISIT(cipher, [](auto &c) { c.clear(); });
91 }
92
94 {
95 return BOTAN_FFI_VISIT(cipher, [](auto &c) { c.reset(); });
96 }
97
98int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t* out_len)
99 {
100 if(out_len == nullptr)
102
103 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *out_len = c.output_length(in_len); });
104 }
105
107 size_t* out_minimum_keylength,
108 size_t* out_maximum_keylength)
109 {
110 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
111 *out_minimum_keylength = c.key_spec().minimum_keylength();
112 *out_maximum_keylength = c.key_spec().maximum_keylength();
113 });
114 }
115
117 size_t* out_minimum_keylength,
118 size_t* out_maximum_keylength,
119 size_t* out_keylength_modulo)
120 {
121 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
122 if(out_minimum_keylength)
123 *out_minimum_keylength = c.key_spec().minimum_keylength();
124 if(out_maximum_keylength)
125 *out_maximum_keylength = c.key_spec().maximum_keylength();
126 if(out_keylength_modulo)
127 *out_keylength_modulo = c.key_spec().keylength_multiple();
128 });
129 }
130
132 const uint8_t* key, size_t key_len)
133 {
134 return BOTAN_FFI_VISIT(cipher, [=](auto& c) { c.set_key(key, key_len); });
135 }
136
138 const uint8_t* nonce, size_t nonce_len)
139 {
140 return ffi_guard_thunk(__func__, [=]() -> int {
141 Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
142 cipher.start(nonce, nonce_len);
143 return BOTAN_FFI_SUCCESS;
144 });
145 }
146
148 uint32_t flags,
149 uint8_t output_ptr[],
150 size_t orig_output_size,
151 size_t* output_written,
152 const uint8_t input_ptr[],
153 size_t orig_input_size,
154 size_t* input_consumed)
155 {
156 return ffi_guard_thunk(__func__, [=]() -> int {
157
158 size_t input_size = orig_input_size;
159 size_t output_size = orig_output_size;
160 const uint8_t* input = input_ptr;
161 uint8_t* output = output_ptr;
162
163 using namespace Botan;
164 Cipher_Mode& cipher = safe_get(cipher_obj);
165 secure_vector<uint8_t>& mbuf = cipher_obj->buf();
166
167 const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL);
168
169 if(final_input)
170 {
171 mbuf.assign(input, input + input_size);
172 *input_consumed = input_size;
173 *output_written = 0;
174
175 try
176 {
177 cipher.finish(mbuf);
178 }
180 {
182 }
183
184 *output_written = mbuf.size();
185
186 if(mbuf.size() <= output_size)
187 {
188 copy_mem(output, mbuf.data(), mbuf.size());
189 mbuf.clear();
190 return BOTAN_FFI_SUCCESS;
191 }
192
193 return -1;
194 }
195
196 if(input_size == 0)
197 {
198 // Currently must take entire buffer in this case
199 *output_written = mbuf.size();
200 if(output_size >= mbuf.size())
201 {
202 copy_mem(output, mbuf.data(), mbuf.size());
203 mbuf.clear();
204 return BOTAN_FFI_SUCCESS;
205 }
206
207 return -1;
208 }
209
210 const size_t ud = cipher_obj->update_size();
211
212 mbuf.resize(ud);
213 size_t taken = 0, written = 0;
214
215 while(input_size >= ud && output_size >= ud)
216 {
217 // FIXME we can use process here and avoid the copy
218 copy_mem(mbuf.data(), input, ud);
219 cipher.update(mbuf);
220
221 input_size -= ud;
222 copy_mem(output, mbuf.data(), ud);
223 input += ud;
224 taken += ud;
225
226 output_size -= ud;
227 output += ud;
228 written += ud;
229 }
230
231 *output_written = written;
232 *input_consumed = taken;
233
234 return BOTAN_FFI_SUCCESS;
235 });
236 }
237
239 const uint8_t* ad,
240 size_t ad_len)
241 {
242 return BOTAN_FFI_VISIT(cipher, [=](auto& c) {
243 if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c))
244 {
245 aead->set_associated_data(ad, ad_len);
246 return BOTAN_FFI_SUCCESS;
247 }
249 });
250 }
251
253 {
254 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
255 return c.valid_nonce_length(nl) ? 1 : 0;
256 });
257 }
258
260 {
261 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *nl = c.default_nonce_length(); });
262 }
263
265 {
266 return BOTAN_FFI_VISIT(cipher, [=](const auto& /*c*/) { *ug = cipher->update_size(); });
267 }
268
270 {
271 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *ug = c.ideal_granularity(); });
272 }
273
275 {
276 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *tl = c.tag_size(); });
277 }
278
279int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len)
280 {
281 return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
282 return write_str_output(name, name_len, c.name()); });
283 }
284
285}
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:67
static std::unique_ptr< Cipher_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition: cipher_mode.cpp:50
void start(std::span< const uint8_t > nonce)
Definition: cipher_mode.h:90
void finish(secure_vector< uint8_t > &final_block, size_t offset=0)
Definition: cipher_mode.h:158
void update(T &buffer, size_t offset=0)
Definition: cipher_mode.h:144
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:496
#define BOTAN_CIPHER_UPDATE_FLAG_FINAL
Definition: ffi.h:584
#define BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION
Definition: ffi.h:495
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
Definition: ffi.h:91
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition: ffi.h:85
@ BOTAN_FFI_SUCCESS
Definition: ffi.h:70
@ BOTAN_FFI_ERROR_BAD_MAC
Definition: ffi.h:74
@ BOTAN_FFI_ERROR_BAD_PARAMETER
Definition: ffi.h:86
struct botan_cipher_struct * botan_cipher_t
Definition: ffi.h:493
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)
Definition: ffi_cipher.cpp:147
int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
Definition: ffi_cipher.cpp:252
int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t *out_len)
Definition: ffi_cipher.cpp:98
int botan_cipher_reset(botan_cipher_t cipher)
Definition: ffi_cipher.cpp:93
int botan_cipher_destroy(botan_cipher_t cipher)
Definition: ffi_cipher.cpp:83
int botan_cipher_name(botan_cipher_t cipher, char *name, size_t *name_len)
Definition: ffi_cipher.cpp:279
int botan_cipher_set_associated_data(botan_cipher_t cipher, const uint8_t *ad, size_t ad_len)
Definition: ffi_cipher.cpp:238
int botan_cipher_start(botan_cipher_t cipher_obj, const uint8_t *nonce, size_t nonce_len)
Definition: ffi_cipher.cpp:137
int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t *tl)
Definition: ffi_cipher.cpp:274
int botan_cipher_get_keyspec(botan_cipher_t cipher, size_t *out_minimum_keylength, size_t *out_maximum_keylength, size_t *out_keylength_modulo)
Definition: ffi_cipher.cpp:116
int botan_cipher_set_key(botan_cipher_t cipher, const uint8_t *key, size_t key_len)
Definition: ffi_cipher.cpp:131
int botan_cipher_get_ideal_update_granularity(botan_cipher_t cipher, size_t *ug)
Definition: ffi_cipher.cpp:269
int botan_cipher_clear(botan_cipher_t cipher)
Definition: ffi_cipher.cpp:88
int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t *nl)
Definition: ffi_cipher.cpp:259
int botan_cipher_init(botan_cipher_t *cipher, const char *cipher_name, uint32_t flags)
Definition: ffi_cipher.cpp:65
int botan_cipher_query_keylen(botan_cipher_t cipher, size_t *out_minimum_keylength, size_t *out_maximum_keylength)
Definition: ffi_cipher.cpp:106
int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t *ug)
Definition: ffi_cipher.cpp:264
#define BOTAN_FFI_VISIT(obj, lambda)
Definition: ffi_util.h:126
#define BOTAN_FFI_CHECKED_DELETE(o)
Definition: ffi_util.h:145
int write_str_output(uint8_t out[], size_t *out_len, std::string_view str)
Definition: ffi_util.h:219
T & safe_get(botan_struct< T, M > *p)
Definition: ffi_util.h:69
int ffi_guard_thunk(const char *func_name, const std::function< int()> &thunk)
Definition: ffi.cpp:120
Definition: alg_id.cpp:12
Cipher_Dir
Definition: cipher_mode.h:26
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64
Definition: bigint.h:1092