Coverage Report

Created: 2025-07-18 06:20

/src/Botan-3.4.0/src/lib/ffi/ffi_pk_op.cpp
Line
Count
Source (jump to first uncovered line)
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/pubkey.h>
10
#include <botan/system_rng.h>
11
#include <botan/internal/ffi_pkey.h>
12
#include <botan/internal/ffi_rng.h>
13
#include <botan/internal/ffi_util.h>
14
15
extern "C" {
16
17
using namespace Botan_FFI;
18
19
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3);
20
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37);
21
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F);
22
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936);
23
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1);
24
25
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_kem_encrypt_struct, Botan::PK_KEM_Encryptor, 0x1D13A446);
26
BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_kem_decrypt_struct, Botan::PK_KEM_Decryptor, 0x1743D8E6);
27
28
0
int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, botan_pubkey_t key_obj, const char* padding, uint32_t flags) {
29
0
   if(op == nullptr) {
30
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
31
0
   }
32
33
0
   if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) {
34
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
35
0
   }
36
37
0
   return ffi_guard_thunk(__func__, [=]() -> int {
38
0
      *op = nullptr;
39
40
0
      auto pk = std::make_unique<Botan::PK_Encryptor_EME>(safe_get(key_obj), Botan::system_rng(), padding);
41
0
      *op = new botan_pk_op_encrypt_struct(std::move(pk));
42
0
      return BOTAN_FFI_SUCCESS;
43
0
   });
44
0
}
45
46
0
int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op) {
47
0
   return BOTAN_FFI_CHECKED_DELETE(op);
48
0
}
49
50
0
int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, size_t ptext_len, size_t* ctext_len) {
51
0
   if(ctext_len == nullptr) {
52
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
53
0
   }
54
0
   return BOTAN_FFI_VISIT(op, [=](const auto& o) { *ctext_len = o.ciphertext_length(ptext_len); });
55
0
}
56
57
int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
58
                        botan_rng_t rng_obj,
59
                        uint8_t out[],
60
                        size_t* out_len,
61
                        const uint8_t plaintext[],
62
0
                        size_t plaintext_len) {
63
0
   return BOTAN_FFI_VISIT(op, [=](const auto& o) {
64
0
      return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj)));
65
0
   });
66
0
}
67
68
/*
69
* Public Key Decryption
70
*/
71
int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
72
                               botan_privkey_t key_obj,
73
                               const char* padding,
74
0
                               uint32_t flags) {
75
0
   if(op == nullptr) {
76
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
77
0
   }
78
79
0
   if(flags != 0) {
80
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
81
0
   }
82
83
0
   return ffi_guard_thunk(__func__, [=]() -> int {
84
0
      *op = nullptr;
85
86
0
      auto pk = std::make_unique<Botan::PK_Decryptor_EME>(safe_get(key_obj), Botan::system_rng(), padding);
87
0
      *op = new botan_pk_op_decrypt_struct(std::move(pk));
88
0
      return BOTAN_FFI_SUCCESS;
89
0
   });
90
0
}
91
92
0
int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op) {
93
0
   return BOTAN_FFI_CHECKED_DELETE(op);
94
0
}
95
96
0
int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, size_t ctext_len, size_t* ptext_len) {
97
0
   if(ptext_len == nullptr) {
98
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
99
0
   }
100
0
   return BOTAN_FFI_VISIT(op, [=](const auto& o) { *ptext_len = o.plaintext_length(ctext_len); });
101
0
}
102
103
int botan_pk_op_decrypt(
104
0
   botan_pk_op_decrypt_t op, uint8_t out[], size_t* out_len, const uint8_t ciphertext[], size_t ciphertext_len) {
105
0
   return BOTAN_FFI_VISIT(
106
0
      op, [=](const auto& o) { return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len)); });
107
0
}
108
109
/*
110
* Signature Generation
111
*/
112
0
int botan_pk_op_sign_create(botan_pk_op_sign_t* op, botan_privkey_t key_obj, const char* hash, uint32_t flags) {
113
0
   if(op == nullptr) {
114
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
115
0
   }
116
117
0
   if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) {
118
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
119
0
   }
120
121
0
   return ffi_guard_thunk(__func__, [=]() -> int {
122
0
      *op = nullptr;
123
124
0
      auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::Signature_Format::DerSequence
125
0
                                                                : Botan::Signature_Format::Standard;
126
127
0
      auto pk = std::make_unique<Botan::PK_Signer>(safe_get(key_obj), Botan::system_rng(), hash, format);
128
0
      *op = new botan_pk_op_sign_struct(std::move(pk));
129
0
      return BOTAN_FFI_SUCCESS;
130
0
   });
131
0
}
132
133
0
int botan_pk_op_sign_destroy(botan_pk_op_sign_t op) {
134
0
   return BOTAN_FFI_CHECKED_DELETE(op);
135
0
}
136
137
0
int botan_pk_op_sign_output_length(botan_pk_op_sign_t op, size_t* sig_len) {
138
0
   if(sig_len == nullptr) {
139
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
140
0
   }
141
142
0
   return BOTAN_FFI_VISIT(op, [=](const auto& o) { *sig_len = o.signature_length(); });
143
0
}
144
145
0
int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len) {
146
0
   return BOTAN_FFI_VISIT(op, [=](auto& o) { o.update(in, in_len); });
147
0
}
148
149
0
int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len) {
150
0
   return BOTAN_FFI_VISIT(op, [=](auto& o) { return write_vec_output(out, out_len, o.signature(safe_get(rng_obj))); });
151
0
}
152
153
204k
int botan_pk_op_verify_create(botan_pk_op_verify_t* op, botan_pubkey_t key_obj, const char* hash, uint32_t flags) {
154
204k
   if(op == nullptr) {
155
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
156
0
   }
157
158
204k
   if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) {
159
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
160
0
   }
161
162
204k
   return ffi_guard_thunk(__func__, [=]() -> int {
163
204k
      *op = nullptr;
164
204k
      auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::Signature_Format::DerSequence
165
204k
                                                                : Botan::Signature_Format::Standard;
166
204k
      auto pk = std::make_unique<Botan::PK_Verifier>(safe_get(key_obj), hash, format);
167
204k
      *op = new botan_pk_op_verify_struct(std::move(pk));
168
204k
      return BOTAN_FFI_SUCCESS;
169
204k
   });
170
204k
}
171
172
204k
int botan_pk_op_verify_destroy(botan_pk_op_verify_t op) {
173
204k
   return BOTAN_FFI_CHECKED_DELETE(op);
174
204k
}
175
176
204k
int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len) {
177
204k
   return BOTAN_FFI_VISIT(op, [=](auto& o) { o.update(in, in_len); });
178
204k
}
179
180
204k
int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len) {
181
204k
   return BOTAN_FFI_VISIT(op, [=](auto& o) {
182
204k
      const bool legit = o.check_signature(sig, sig_len);
183
184
204k
      if(legit)
185
204k
         return BOTAN_FFI_SUCCESS;
186
204k
      else
187
204k
         return BOTAN_FFI_INVALID_VERIFIER;
188
204k
   });
189
204k
}
190
191
0
int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, botan_privkey_t key_obj, const char* kdf, uint32_t flags) {
192
0
   if(op == nullptr) {
193
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
194
0
   }
195
196
0
   if(flags != 0) {
197
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
198
0
   }
199
200
0
   return ffi_guard_thunk(__func__, [=]() -> int {
201
0
      *op = nullptr;
202
0
      auto pk = std::make_unique<Botan::PK_Key_Agreement>(safe_get(key_obj), Botan::system_rng(), kdf);
203
0
      *op = new botan_pk_op_ka_struct(std::move(pk));
204
0
      return BOTAN_FFI_SUCCESS;
205
0
   });
206
0
}
207
208
0
int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op) {
209
0
   return BOTAN_FFI_CHECKED_DELETE(op);
210
0
}
211
212
0
int botan_pk_op_key_agreement_export_public(botan_privkey_t key, uint8_t out[], size_t* out_len) {
213
0
   return copy_view_bin(out, out_len, botan_pk_op_key_agreement_view_public, key);
214
0
}
215
216
0
int botan_pk_op_key_agreement_view_public(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
217
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
218
0
      if(auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&k))
219
0
         return invoke_view_callback(view, ctx, kak->public_value());
220
0
      else
221
0
         return BOTAN_FFI_ERROR_INVALID_INPUT;
222
0
   });
223
0
}
224
225
0
int botan_pk_op_key_agreement_size(botan_pk_op_ka_t op, size_t* out_len) {
226
0
   return BOTAN_FFI_VISIT(op, [=](const auto& o) {
227
0
      if(out_len == nullptr)
228
0
         return BOTAN_FFI_ERROR_NULL_POINTER;
229
0
      *out_len = o.agreed_value_size();
230
0
      return BOTAN_FFI_SUCCESS;
231
0
   });
232
0
}
233
234
int botan_pk_op_key_agreement(botan_pk_op_ka_t op,
235
                              uint8_t out[],
236
                              size_t* out_len,
237
                              const uint8_t other_key[],
238
                              size_t other_key_len,
239
                              const uint8_t salt[],
240
0
                              size_t salt_len) {
241
0
   return BOTAN_FFI_VISIT(op, [=](const auto& o) {
242
0
      auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of();
243
0
      return write_vec_output(out, out_len, k);
244
0
   });
245
0
}
246
247
0
int botan_pk_op_kem_encrypt_create(botan_pk_op_kem_encrypt_t* op, botan_pubkey_t key_obj, const char* padding) {
248
0
   if(op == nullptr || padding == nullptr) {
249
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
250
0
   }
251
252
0
   return ffi_guard_thunk(__func__, [=]() -> int {
253
0
      auto pk = std::make_unique<Botan::PK_KEM_Encryptor>(safe_get(key_obj), padding);
254
0
      *op = new botan_pk_op_kem_encrypt_struct(std::move(pk));
255
0
      return BOTAN_FFI_SUCCESS;
256
0
   });
257
0
}
258
259
0
int botan_pk_op_kem_encrypt_destroy(botan_pk_op_kem_encrypt_t op) {
260
0
   return BOTAN_FFI_CHECKED_DELETE(op);
261
0
}
262
263
int botan_pk_op_kem_encrypt_shared_key_length(botan_pk_op_kem_encrypt_t op,
264
                                              size_t desired_shared_key_length,
265
0
                                              size_t* output_shared_key_length) {
266
0
   if(output_shared_key_length == nullptr) {
267
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
268
0
   }
269
270
0
   return BOTAN_FFI_VISIT(op, [=](auto& kem) {
271
0
      *output_shared_key_length = kem.shared_key_length(desired_shared_key_length);
272
0
      return BOTAN_FFI_SUCCESS;
273
0
   });
274
0
}
275
276
int botan_pk_op_kem_encrypt_encapsulated_key_length(botan_pk_op_kem_encrypt_t op,
277
0
                                                    size_t* output_encapsulated_key_length) {
278
0
   if(output_encapsulated_key_length == nullptr) {
279
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
280
0
   }
281
282
0
   return BOTAN_FFI_VISIT(op, [=](auto& kem) {
283
0
      *output_encapsulated_key_length = kem.encapsulated_key_length();
284
0
      return BOTAN_FFI_SUCCESS;
285
0
   });
286
0
}
287
288
int botan_pk_op_kem_encrypt_create_shared_key(botan_pk_op_kem_encrypt_t op,
289
                                              botan_rng_t rng,
290
                                              const uint8_t salt[],
291
                                              size_t salt_len,
292
                                              size_t desired_shared_key_len,
293
                                              uint8_t shared_key_out[],
294
                                              size_t* shared_key_len,
295
                                              uint8_t encapsulated_key_out[],
296
0
                                              size_t* encapsulated_key_len) {
297
0
   return BOTAN_FFI_VISIT(op, [=](auto& kem) {
298
0
      const auto result = kem.encrypt(safe_get(rng), desired_shared_key_len, {salt, salt_len});
299
300
0
      int rc = write_vec_output(encapsulated_key_out, encapsulated_key_len, result.encapsulated_shared_key());
301
302
0
      if(rc != 0)
303
0
         return rc;
304
305
0
      return write_vec_output(shared_key_out, shared_key_len, result.shared_key());
306
0
   });
307
0
}
308
309
0
int botan_pk_op_kem_decrypt_create(botan_pk_op_kem_decrypt_t* op, botan_privkey_t key_obj, const char* padding) {
310
0
   if(op == nullptr || padding == nullptr) {
311
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
312
0
   }
313
314
0
   return ffi_guard_thunk(__func__, [=]() -> int {
315
0
      auto pk = std::make_unique<Botan::PK_KEM_Decryptor>(safe_get(key_obj), Botan::system_rng(), padding);
316
0
      *op = new botan_pk_op_kem_decrypt_struct(std::move(pk));
317
0
      return BOTAN_FFI_SUCCESS;
318
0
   });
319
0
}
320
321
int botan_pk_op_kem_decrypt_shared_key_length(botan_pk_op_kem_decrypt_t op,
322
                                              size_t desired_shared_key_length,
323
0
                                              size_t* output_shared_key_length) {
324
0
   if(output_shared_key_length == nullptr) {
325
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
326
0
   }
327
328
0
   return BOTAN_FFI_VISIT(op, [=](auto& kem) {
329
0
      *output_shared_key_length = kem.shared_key_length(desired_shared_key_length);
330
0
      return BOTAN_FFI_SUCCESS;
331
0
   });
332
0
}
333
334
int botan_pk_op_kem_decrypt_shared_key(botan_pk_op_kem_decrypt_t op,
335
                                       const uint8_t salt[],
336
                                       size_t salt_len,
337
                                       const uint8_t encapsulated_key[],
338
                                       size_t encapsulated_key_len,
339
                                       size_t desired_shared_key_len,
340
                                       uint8_t shared_key_out[],
341
0
                                       size_t* shared_key_len) {
342
0
   return BOTAN_FFI_VISIT(op, [=](auto& kem) {
343
0
      const auto shared_key =
344
0
         kem.decrypt(encapsulated_key, encapsulated_key_len, desired_shared_key_len, salt, salt_len);
345
346
0
      write_vec_output(shared_key_out, shared_key_len, shared_key);
347
0
   });
348
0
}
349
350
0
int botan_pk_op_kem_decrypt_destroy(botan_pk_op_kem_decrypt_t op) {
351
0
   return BOTAN_FFI_CHECKED_DELETE(op);
352
0
}
353
}