• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13521694625

25 Feb 2025 12:53PM UTC coverage: 91.695% (+0.005%) from 91.69%
13521694625

Pull #4715

github

web-flow
Merge 0a106d03d into ba60477e1
Pull Request #4715: Check if an EC_Group exists before trying to create it in ffi

95828 of 104507 relevant lines covered (91.7%)

11311637.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.04
/src/lib/ffi/ffi_pkey_algs.cpp
1
/*
2
* (C) 2015,2017 Jack Lloyd
3
* (C) 2017 Ribose Inc
4
* (C) 2018 René Korthaus, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/ffi.h>
10

11
#include <botan/hash.h>
12
#include <botan/pem.h>
13
#include <botan/internal/ffi_mp.h>
14
#include <botan/internal/ffi_pkey.h>
15
#include <botan/internal/ffi_rng.h>
16
#include <botan/internal/ffi_util.h>
17

18
#if defined(BOTAN_HAS_DL_GROUP)
19
   #include <botan/dl_group.h>
20
#endif
21

22
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
23
   #include <botan/ecc_key.h>
24
#endif
25

26
#if defined(BOTAN_HAS_RSA)
27
   #include <botan/rsa.h>
28
#endif
29

30
#if defined(BOTAN_HAS_ELGAMAL)
31
   #include <botan/elgamal.h>
32
#endif
33

34
#if defined(BOTAN_HAS_DSA)
35
   #include <botan/dsa.h>
36
#endif
37

38
#if defined(BOTAN_HAS_ECDSA)
39
   #include <botan/ecdsa.h>
40
#endif
41

42
#if defined(BOTAN_HAS_SM2)
43
   #include <botan/sm2.h>
44
#endif
45

46
#if defined(BOTAN_HAS_ECDH)
47
   #include <botan/ecdh.h>
48
#endif
49

50
#if defined(BOTAN_HAS_X25519)
51
   #include <botan/x25519.h>
52
#endif
53

54
#if defined(BOTAN_HAS_X448)
55
   #include <botan/x448.h>
56
#endif
57

58
#if defined(BOTAN_HAS_ED25519)
59
   #include <botan/ed25519.h>
60
#endif
61

62
#if defined(BOTAN_HAS_ED448)
63
   #include <botan/ed448.h>
64
#endif
65

66
#if defined(BOTAN_HAS_MCELIECE)
67
   #include <botan/mceliece.h>
68
#endif
69

70
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
71
   #include <botan/dh.h>
72
#endif
73

74
#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
75
   #include <botan/kyber.h>
76
#endif
77

78
#if defined(BOTAN_HAS_ML_KEM)
79
   #include <botan/ml_kem.h>
80
#endif
81

82
#if defined(BOTAN_HAS_FRODOKEM)
83
   #include <botan/frodokem.h>
84
#endif
85

86
#if defined(BOTAN_HAS_ML_DSA)
87
   #include <botan/ml_dsa.h>
88
#endif
89

90
#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
91
   #include <botan/slh_dsa.h>
92
#endif
93

94
#if defined(BOTAN_HAS_CLASSICMCELIECE)
95
   #include <botan/cmce.h>
96
#endif
97

98
namespace {
99

100
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
101

102
// These are always called within an existing try/catch block
103

104
template <class ECPrivateKey_t>
105
int privkey_load_ec(std::unique_ptr<ECPrivateKey_t>& key, const Botan::BigInt& scalar, const char* curve_name) {
9✔
106
   if(curve_name == nullptr) {
9✔
107
      return BOTAN_FFI_ERROR_NULL_POINTER;
108
   }
109
   if(!Botan::EC_Group::supports_named_group(curve_name)) {
9✔
110
      return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
111
   }
112

113
   Botan::Null_RNG null_rng;
9✔
114
   const auto grp = Botan::EC_Group::from_name(curve_name);
9✔
115
   key.reset(new ECPrivateKey_t(null_rng, grp, scalar));
9✔
116
   return BOTAN_FFI_SUCCESS;
117
}
9✔
118

119
template <class ECPublicKey_t>
120
int pubkey_load_ec(std::unique_ptr<ECPublicKey_t>& key,
6✔
121
                   const Botan::BigInt& public_x,
122
                   const Botan::BigInt& public_y,
123
                   const char* curve_name) {
124
   if(curve_name == nullptr) {
6✔
125
      return BOTAN_FFI_ERROR_NULL_POINTER;
126
   }
127

128
   if(!Botan::EC_Group::supports_named_group(curve_name)) {
6✔
129
      return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
130
   }
131

132
   const auto group = Botan::EC_Group::from_name(curve_name);
6✔
133

134
   if(auto pt = Botan::EC_AffinePoint::from_bigint_xy(group, public_x, public_y)) {
6✔
135
      key.reset(new ECPublicKey_t(group, pt.value()));
6✔
136
      return BOTAN_FFI_SUCCESS;
6✔
137
   } else {
138
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
139
   }
140
}
6✔
141

142
#endif
143

144
Botan::BigInt pubkey_get_field(const Botan::Public_Key& key, std::string_view field) {
40✔
145
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
146
   // Not currently handled by get_int_field
147
   if(const Botan::EC_PublicKey* ecc = dynamic_cast<const Botan::EC_PublicKey*>(&key)) {
40✔
148
      if(field == "public_x") {
15✔
149
         return Botan::BigInt::from_bytes(ecc->_public_ec_point().x_bytes());
16✔
150
      } else if(field == "public_y") {
7✔
151
         return Botan::BigInt::from_bytes(ecc->_public_ec_point().y_bytes());
12✔
152
      }
153
   }
154
#endif
155

156
   try {
26✔
157
      return key.get_int_field(field);
26✔
158
   } catch(Botan::Unknown_PK_Field_Name&) {
2✔
159
      throw Botan_FFI::FFI_Error("Unknown key field", BOTAN_FFI_ERROR_BAD_PARAMETER);
2✔
160
   }
2✔
161
}
162

163
Botan::BigInt privkey_get_field(const Botan::Private_Key& key, std::string_view field) {
35✔
164
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
165
   // Not currently handled by get_int_field
166
   if(const Botan::EC_PublicKey* ecc = dynamic_cast<const Botan::EC_PublicKey*>(&key)) {
35✔
167
      if(field == "public_x") {
16✔
168
         return Botan::BigInt::from_bytes(ecc->_public_ec_point().x_bytes());
4✔
169
      } else if(field == "public_y") {
14✔
170
         return Botan::BigInt::from_bytes(ecc->_public_ec_point().y_bytes());
8✔
171
      }
172
   }
173
#endif
174

175
   try {
29✔
176
      return key.get_int_field(field);
29✔
177
   } catch(Botan::Unknown_PK_Field_Name&) {
4✔
178
      throw Botan_FFI::FFI_Error("Unknown key field", BOTAN_FFI_ERROR_BAD_PARAMETER);
4✔
179
   }
4✔
180
}
181

182
}  // namespace
183

184
extern "C" {
185

186
using namespace Botan_FFI;
187

188
int botan_pubkey_get_field(botan_mp_t output, botan_pubkey_t key, const char* field_name_cstr) {
40✔
189
   if(field_name_cstr == nullptr) {
40✔
190
      return BOTAN_FFI_ERROR_NULL_POINTER;
191
   }
192

193
   const std::string field_name(field_name_cstr);
40✔
194

195
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { safe_get(output) = pubkey_get_field(k, field_name); });
158✔
196
}
40✔
197

198
int botan_privkey_get_field(botan_mp_t output, botan_privkey_t key, const char* field_name_cstr) {
35✔
199
   if(field_name_cstr == nullptr) {
35✔
200
      return BOTAN_FFI_ERROR_NULL_POINTER;
201
   }
202

203
   const std::string field_name(field_name_cstr);
35✔
204

205
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { safe_get(output) = privkey_get_field(k, field_name); });
136✔
206
}
35✔
207

208
/* RSA specific operations */
209

210
int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits) {
1✔
211
   if(n_bits < 1024 || n_bits > 16 * 1024) {
1✔
212
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
213
   }
214

215
   std::string n_str = std::to_string(n_bits);
1✔
216

217
   return botan_privkey_create(key_obj, "RSA", n_str.c_str(), rng_obj);
1✔
218
}
1✔
219

220
int botan_privkey_load_rsa(botan_privkey_t* key, botan_mp_t rsa_p, botan_mp_t rsa_q, botan_mp_t rsa_e) {
2✔
221
#if defined(BOTAN_HAS_RSA)
222
   if(key == nullptr) {
2✔
223
      return BOTAN_FFI_ERROR_NULL_POINTER;
224
   }
225
   *key = nullptr;
2✔
226

227
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
228
      auto rsa = std::make_unique<Botan::RSA_PrivateKey>(safe_get(rsa_p), safe_get(rsa_q), safe_get(rsa_e));
2✔
229
      *key = new botan_privkey_struct(std::move(rsa));
2✔
230
      return BOTAN_FFI_SUCCESS;
2✔
231
   });
2✔
232
#else
233
   BOTAN_UNUSED(key, rsa_p, rsa_q, rsa_e);
234
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
235
#endif
236
}
237

238
int botan_privkey_load_rsa_pkcs1(botan_privkey_t* key, const uint8_t bits[], size_t len) {
1✔
239
#if defined(BOTAN_HAS_RSA)
240
   if(key == nullptr || bits == nullptr) {
1✔
241
      return BOTAN_FFI_ERROR_NULL_POINTER;
242
   }
243
   *key = nullptr;
1✔
244

245
   Botan::secure_vector<uint8_t> src(bits, bits + len);
1✔
246
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
247
      Botan::AlgorithmIdentifier alg_id("RSA", Botan::AlgorithmIdentifier::USE_NULL_PARAM);
1✔
248
      auto rsa = std::make_unique<Botan::RSA_PrivateKey>(alg_id, src);
1✔
249
      *key = new botan_privkey_struct(std::move(rsa));
1✔
250
      return BOTAN_FFI_SUCCESS;
1✔
251
   });
1✔
252
#else
253
   BOTAN_UNUSED(key, bits, len);
254
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
255
#endif
256
}
1✔
257

258
int botan_pubkey_load_rsa(botan_pubkey_t* key, botan_mp_t n, botan_mp_t e) {
4✔
259
#if defined(BOTAN_HAS_RSA)
260
   if(key == nullptr) {
4✔
261
      return BOTAN_FFI_ERROR_NULL_POINTER;
262
   }
263
   *key = nullptr;
4✔
264
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
265
      auto rsa = std::make_unique<Botan::RSA_PublicKey>(safe_get(n), safe_get(e));
4✔
266
      *key = new botan_pubkey_struct(std::move(rsa));
6✔
267
      return BOTAN_FFI_SUCCESS;
3✔
268
   });
3✔
269
#else
270
   BOTAN_UNUSED(key, n, e);
271
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
272
#endif
273
}
274

275
int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t key) {
1✔
276
   return botan_privkey_get_field(p, key, "p");
1✔
277
}
278

279
int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t key) {
1✔
280
   return botan_privkey_get_field(q, key, "q");
1✔
281
}
282

283
int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t key) {
1✔
284
   return botan_privkey_get_field(n, key, "n");
1✔
285
}
286

287
int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t key) {
1✔
288
   return botan_privkey_get_field(e, key, "e");
1✔
289
}
290

291
int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t key) {
1✔
292
   return botan_privkey_get_field(d, key, "d");
1✔
293
}
294

295
int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t key) {
1✔
296
   return botan_pubkey_get_field(e, key, "e");
1✔
297
}
298

299
int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t key) {
1✔
300
   return botan_pubkey_get_field(n, key, "n");
1✔
301
}
302

303
int botan_privkey_rsa_get_privkey(botan_privkey_t rsa_key, uint8_t out[], size_t* out_len, uint32_t flags) {
4✔
304
#if defined(BOTAN_HAS_RSA)
305
   return BOTAN_FFI_VISIT(rsa_key, [=](const auto& k) -> int {
14✔
306
      if(const Botan::RSA_PrivateKey* rsa = dynamic_cast<const Botan::RSA_PrivateKey*>(&k)) {
307
         if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
308
            return write_vec_output(out, out_len, rsa->private_key_bits());
309
         } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
310
            return write_str_output(out, out_len, Botan::PEM_Code::encode(rsa->private_key_bits(), "RSA PRIVATE KEY"));
311
         } else {
312
            return BOTAN_FFI_ERROR_BAD_FLAG;
313
         }
314
      } else {
315
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
316
      }
317
   });
318
#else
319
   BOTAN_UNUSED(rsa_key, out, out_len, flags);
320
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
321
#endif
322
}
323

324
/* DSA specific operations */
325
int botan_privkey_create_dsa(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) {
1✔
326
#if defined(BOTAN_HAS_DSA)
327

328
   if((rng_obj == nullptr) || (key == nullptr)) {
1✔
329
      return BOTAN_FFI_ERROR_NULL_POINTER;
330
   }
331

332
   if((pbits % 64) || (qbits % 8) || (pbits < 1024) || (pbits > 3072) || (qbits < 160) || (qbits > 256)) {
1✔
333
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
334
   }
335

336
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
337
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
1✔
338
      Botan::DL_Group group(rng, Botan::DL_Group::Prime_Subgroup, pbits, qbits);
1✔
339
      auto dsa = std::make_unique<Botan::DSA_PrivateKey>(rng, group);
1✔
340
      *key = new botan_privkey_struct(std::move(dsa));
2✔
341
      return BOTAN_FFI_SUCCESS;
2✔
342
   });
2✔
343
#else
344
   BOTAN_UNUSED(key, rng_obj, pbits, qbits);
345
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
346
#endif
347
}
348

349
int botan_privkey_load_dsa(botan_privkey_t* key, botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x) {
2✔
350
#if defined(BOTAN_HAS_DSA)
351
   if(key == nullptr) {
2✔
352
      return BOTAN_FFI_ERROR_NULL_POINTER;
353
   }
354
   *key = nullptr;
2✔
355

356
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
357
      Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
2✔
358
      auto dsa = std::make_unique<Botan::DSA_PrivateKey>(group, safe_get(x));
2✔
359
      *key = new botan_privkey_struct(std::move(dsa));
4✔
360
      return BOTAN_FFI_SUCCESS;
4✔
361
   });
4✔
362
#else
363
   BOTAN_UNUSED(key, p, q, g, x);
364
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
365
#endif
366
}
367

368
int botan_pubkey_load_dsa(botan_pubkey_t* key, botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y) {
2✔
369
#if defined(BOTAN_HAS_DSA)
370
   if(key == nullptr) {
2✔
371
      return BOTAN_FFI_ERROR_NULL_POINTER;
372
   }
373
   *key = nullptr;
2✔
374

375
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
376
      Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
2✔
377
      auto dsa = std::make_unique<Botan::DSA_PublicKey>(group, safe_get(y));
2✔
378
      *key = new botan_pubkey_struct(std::move(dsa));
4✔
379
      return BOTAN_FFI_SUCCESS;
2✔
380
   });
4✔
381
#else
382
   BOTAN_UNUSED(key, p, q, g, y);
383
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
384
#endif
385
}
386

387
int botan_privkey_dsa_get_x(botan_mp_t x, botan_privkey_t key) {
2✔
388
   return botan_privkey_get_field(x, key, "x");
2✔
389
}
390

391
int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key) {
2✔
392
   return botan_pubkey_get_field(p, key, "p");
2✔
393
}
394

395
int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key) {
2✔
396
   return botan_pubkey_get_field(q, key, "q");
2✔
397
}
398

399
int botan_pubkey_dsa_get_g(botan_mp_t g, botan_pubkey_t key) {
2✔
400
   return botan_pubkey_get_field(g, key, "g");
2✔
401
}
402

403
int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key) {
2✔
404
   return botan_pubkey_get_field(y, key, "y");
2✔
405
}
406

407
int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) {
1✔
408
   return botan_privkey_create(key_obj, "ECDSA", param_str, rng_obj);
1✔
409
}
410

411
/* ECDSA specific operations */
412

413
int botan_pubkey_ecc_key_used_explicit_encoding(botan_pubkey_t key) {
1✔
414
#if defined(BOTAN_HAS_ECC_KEY)
415
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
416
      const Botan::Public_Key& pub_key = safe_get(key);
1✔
417
      const Botan::EC_PublicKey* ec_key = dynamic_cast<const Botan::EC_PublicKey*>(&pub_key);
1✔
418

419
      if(ec_key == nullptr) {
1✔
420
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
421
      }
422

423
      return ec_key->domain().used_explicit_encoding() ? 1 : 0;
1✔
424
   });
1✔
425
#else
426
   BOTAN_UNUSED(key);
427
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
428
#endif
429
}
430

431
int botan_pubkey_load_ecdsa(botan_pubkey_t* key,
2✔
432
                            const botan_mp_t public_x,
433
                            const botan_mp_t public_y,
434
                            const char* curve_name) {
435
#if defined(BOTAN_HAS_ECDSA)
436
   if(key == nullptr || curve_name == nullptr) {
2✔
437
      return BOTAN_FFI_ERROR_NULL_POINTER;
438
   }
439
   *key = nullptr;
2✔
440

441
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
442
      std::unique_ptr<Botan::ECDSA_PublicKey> p_key;
2✔
443

444
      int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
2✔
445
      if(rc == BOTAN_FFI_SUCCESS) {
2✔
446
         *key = new botan_pubkey_struct(std::move(p_key));
4✔
447
      }
448

449
      return rc;
2✔
450
   });
2✔
451
#else
452
   BOTAN_UNUSED(key, public_x, public_y, curve_name);
453
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
454
#endif
455
}
456

457
int botan_privkey_load_ecdsa(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
2✔
458
#if defined(BOTAN_HAS_ECDSA)
459
   if(key == nullptr || curve_name == nullptr) {
2✔
460
      return BOTAN_FFI_ERROR_NULL_POINTER;
461
   }
462
   *key = nullptr;
2✔
463

464
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
465
      std::unique_ptr<Botan::ECDSA_PrivateKey> p_key;
2✔
466
      int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
2✔
467
      if(rc == BOTAN_FFI_SUCCESS) {
2✔
468
         *key = new botan_privkey_struct(std::move(p_key));
4✔
469
      }
470
      return rc;
2✔
471
   });
2✔
472
#else
473
   BOTAN_UNUSED(key, scalar, curve_name);
474
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
475
#endif
476
}
477

478
/* ElGamal specific operations */
479
int botan_privkey_create_elgamal(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) {
1✔
480
#if defined(BOTAN_HAS_ELGAMAL)
481
   if(key == nullptr || rng_obj == nullptr) {
1✔
482
      return BOTAN_FFI_ERROR_NULL_POINTER;
483
   }
484
   *key = nullptr;
1✔
485

486
   if(pbits < 1024 || qbits < 160) {
1✔
487
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
488
   }
489

490
   Botan::DL_Group::PrimeType prime_type =
1✔
491
      ((pbits - 1) == qbits) ? Botan::DL_Group::Strong : Botan::DL_Group::Prime_Subgroup;
1✔
492

493
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
494
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
1✔
495
      Botan::DL_Group group(rng, prime_type, pbits, qbits);
1✔
496
      auto elg = std::make_unique<Botan::ElGamal_PrivateKey>(rng, group);
1✔
497
      *key = new botan_privkey_struct(std::move(elg));
2✔
498
      return BOTAN_FFI_SUCCESS;
2✔
499
   });
2✔
500
#else
501
   BOTAN_UNUSED(key, rng_obj, pbits, qbits);
502
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
503
#endif
504
}
505

506
int botan_pubkey_load_elgamal(botan_pubkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t y) {
2✔
507
#if defined(BOTAN_HAS_ELGAMAL)
508
   if(key == nullptr) {
2✔
509
      return BOTAN_FFI_ERROR_NULL_POINTER;
510
   }
511
   *key = nullptr;
2✔
512
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
513
      Botan::DL_Group group(safe_get(p), safe_get(g));
2✔
514
      auto elg = std::make_unique<Botan::ElGamal_PublicKey>(group, safe_get(y));
2✔
515
      *key = new botan_pubkey_struct(std::move(elg));
4✔
516
      return BOTAN_FFI_SUCCESS;
2✔
517
   });
4✔
518
#else
519
   BOTAN_UNUSED(key, p, g, y);
520
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
521
#endif
522
}
523

524
int botan_privkey_load_elgamal(botan_privkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t x) {
2✔
525
#if defined(BOTAN_HAS_ELGAMAL)
526
   if(key == nullptr) {
2✔
527
      return BOTAN_FFI_ERROR_NULL_POINTER;
528
   }
529
   *key = nullptr;
2✔
530
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
531
      Botan::DL_Group group(safe_get(p), safe_get(g));
2✔
532
      auto elg = std::make_unique<Botan::ElGamal_PrivateKey>(group, safe_get(x));
2✔
533
      *key = new botan_privkey_struct(std::move(elg));
4✔
534
      return BOTAN_FFI_SUCCESS;
4✔
535
   });
4✔
536
#else
537
   BOTAN_UNUSED(key, p, g, x);
538
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
539
#endif
540
}
541

542
/* Diffie Hellman specific operations */
543

544
int botan_privkey_create_dh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) {
2✔
545
   return botan_privkey_create(key_obj, "DH", param_str, rng_obj);
2✔
546
}
547

548
int botan_privkey_load_dh(botan_privkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t x) {
1✔
549
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
550
   if(key == nullptr) {
1✔
551
      return BOTAN_FFI_ERROR_NULL_POINTER;
552
   }
553
   *key = nullptr;
1✔
554
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
555
      Botan::DL_Group group(safe_get(p), safe_get(g));
1✔
556
      auto dh = std::make_unique<Botan::DH_PrivateKey>(group, safe_get(x));
1✔
557
      *key = new botan_privkey_struct(std::move(dh));
2✔
558
      return BOTAN_FFI_SUCCESS;
2✔
559
   });
2✔
560
#else
561
   BOTAN_UNUSED(key, p, g, x);
562
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
563
#endif
564
}
565

566
int botan_pubkey_load_dh(botan_pubkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t y) {
1✔
567
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
568
   if(key == nullptr) {
1✔
569
      return BOTAN_FFI_ERROR_NULL_POINTER;
570
   }
571
   *key = nullptr;
1✔
572
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
573
      Botan::DL_Group group(safe_get(p), safe_get(g));
1✔
574
      auto dh = std::make_unique<Botan::DH_PublicKey>(group, safe_get(y));
1✔
575
      *key = new botan_pubkey_struct(std::move(dh));
2✔
576
      return BOTAN_FFI_SUCCESS;
1✔
577
   });
2✔
578
#else
579
   BOTAN_UNUSED(key, p, g, y);
580
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
581
#endif
582
}
583

584
/* ECDH + x25519/x448 specific operations */
585

586
int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) {
2✔
587
   if(key_obj == nullptr || param_str == nullptr) {
2✔
588
      return BOTAN_FFI_ERROR_NULL_POINTER;
589
   }
590
   *key_obj = nullptr;
2✔
591

592
   const std::string params(param_str);
2✔
593

594
   if(params == "X25519" || params == "x25519" || params == "curve25519") {
2✔
595
      return botan_privkey_create(key_obj, "X25519", "", rng_obj);
×
596
   }
597

598
   if(params == "X448" || params == "x448") {
2✔
599
      return botan_privkey_create(key_obj, "X448", "", rng_obj);
×
600
   }
601

602
   return botan_privkey_create(key_obj, "ECDH", param_str, rng_obj);
2✔
603
}
2✔
604

605
int botan_pubkey_load_ecdh(botan_pubkey_t* key,
1✔
606
                           const botan_mp_t public_x,
607
                           const botan_mp_t public_y,
608
                           const char* curve_name) {
609
#if defined(BOTAN_HAS_ECDH)
610
   if(key == nullptr || curve_name == nullptr) {
1✔
611
      return BOTAN_FFI_ERROR_NULL_POINTER;
612
   }
613
   *key = nullptr;
1✔
614
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
615
      std::unique_ptr<Botan::ECDH_PublicKey> p_key;
1✔
616
      int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
1✔
617

618
      if(rc == BOTAN_FFI_SUCCESS) {
1✔
619
         *key = new botan_pubkey_struct(std::move(p_key));
2✔
620
      }
621
      return rc;
1✔
622
   });
1✔
623
#else
624
   BOTAN_UNUSED(key, public_x, public_y, curve_name);
625
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
626
#endif
627
}
628

629
int botan_privkey_load_ecdh(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
4✔
630
#if defined(BOTAN_HAS_ECDH)
631
   if(key == nullptr || curve_name == nullptr) {
4✔
632
      return BOTAN_FFI_ERROR_NULL_POINTER;
633
   }
634
   *key = nullptr;
4✔
635
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
636
      std::unique_ptr<Botan::ECDH_PrivateKey> p_key;
4✔
637
      int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
4✔
638
      if(rc == BOTAN_FFI_SUCCESS) {
4✔
639
         *key = new botan_privkey_struct(std::move(p_key));
8✔
640
      }
641
      return rc;
4✔
642
   });
4✔
643
#else
644
   BOTAN_UNUSED(key, scalar, curve_name);
645
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
646
#endif
647
}
648

649
/* SM2 specific operations */
650

651
int botan_pubkey_sm2_compute_za(
2✔
652
   uint8_t out[], size_t* out_len, const char* ident, const char* hash_algo, const botan_pubkey_t key) {
653
   if(out == nullptr || out_len == nullptr || ident == nullptr || hash_algo == nullptr || key == nullptr) {
2✔
654
      return BOTAN_FFI_ERROR_NULL_POINTER;
655
   }
656

657
#if defined(BOTAN_HAS_SM2)
658
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
659
      const Botan::Public_Key& pub_key = safe_get(key);
2✔
660
      const Botan::EC_PublicKey* ec_key = dynamic_cast<const Botan::EC_PublicKey*>(&pub_key);
2✔
661

662
      if(ec_key == nullptr) {
2✔
663
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
664
      }
665

666
      if(ec_key->algo_name() != "SM2") {
2✔
667
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
668
      }
669

670
      const std::string ident_str(ident);
2✔
671
      std::unique_ptr<Botan::HashFunction> hash = Botan::HashFunction::create_or_throw(hash_algo);
2✔
672

673
      const std::vector<uint8_t> za =
2✔
674
         Botan::sm2_compute_za(*hash, ident_str, ec_key->domain(), ec_key->_public_ec_point());
2✔
675

676
      return write_vec_output(out, out_len, za);
2✔
677
   });
4✔
678
#else
679
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
680
#endif
681
}
682

683
int botan_pubkey_load_sm2(botan_pubkey_t* key,
3✔
684
                          const botan_mp_t public_x,
685
                          const botan_mp_t public_y,
686
                          const char* curve_name) {
687
#if defined(BOTAN_HAS_SM2)
688
   if(key == nullptr || curve_name == nullptr) {
3✔
689
      return BOTAN_FFI_ERROR_NULL_POINTER;
690
   }
691
   *key = nullptr;
3✔
692

693
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
694
      std::unique_ptr<Botan::SM2_PublicKey> p_key;
3✔
695
      if(!pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name)) {
3✔
696
         *key = new botan_pubkey_struct(std::move(p_key));
6✔
697
         return BOTAN_FFI_SUCCESS;
3✔
698
      }
699
      return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
700
   });
3✔
701
#else
702
   BOTAN_UNUSED(key, public_x, public_y, curve_name);
703
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
704
#endif
705
}
706

707
int botan_privkey_load_sm2(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
3✔
708
#if defined(BOTAN_HAS_SM2)
709
   if(key == nullptr || curve_name == nullptr) {
3✔
710
      return BOTAN_FFI_ERROR_NULL_POINTER;
711
   }
712
   *key = nullptr;
3✔
713

714
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
715
      std::unique_ptr<Botan::SM2_PrivateKey> p_key;
3✔
716
      int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
3✔
717

718
      if(rc == BOTAN_FFI_SUCCESS) {
3✔
719
         *key = new botan_privkey_struct(std::move(p_key));
6✔
720
      }
721
      return rc;
3✔
722
   });
3✔
723
#else
724
   BOTAN_UNUSED(key, scalar, curve_name);
725
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
726
#endif
727
}
728

729
int botan_pubkey_load_sm2_enc(botan_pubkey_t* key,
1✔
730
                              const botan_mp_t public_x,
731
                              const botan_mp_t public_y,
732
                              const char* curve_name) {
733
   return botan_pubkey_load_sm2(key, public_x, public_y, curve_name);
1✔
734
}
735

736
int botan_privkey_load_sm2_enc(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
1✔
737
   return botan_privkey_load_sm2(key, scalar, curve_name);
1✔
738
}
739

740
/* Ed25519 specific operations */
741

742
int botan_privkey_load_ed25519(botan_privkey_t* key, const uint8_t privkey[32]) {
1✔
743
#if defined(BOTAN_HAS_ED25519)
744
   if(key == nullptr) {
1✔
745
      return BOTAN_FFI_ERROR_NULL_POINTER;
746
   }
747
   *key = nullptr;
1✔
748
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
749
      auto ed25519 =
1✔
750
         std::make_unique<Botan::Ed25519_PrivateKey>(Botan::Ed25519_PrivateKey::from_seed(std::span{privkey, 32}));
2✔
751
      *key = new botan_privkey_struct(std::move(ed25519));
1✔
752
      return BOTAN_FFI_SUCCESS;
1✔
753
   });
1✔
754
#else
755
   BOTAN_UNUSED(key, privkey);
756
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
757
#endif
758
}
759

760
int botan_pubkey_load_ed25519(botan_pubkey_t* key, const uint8_t pubkey[32]) {
1✔
761
#if defined(BOTAN_HAS_ED25519)
762
   if(key == nullptr) {
1✔
763
      return BOTAN_FFI_ERROR_NULL_POINTER;
764
   }
765
   *key = nullptr;
1✔
766
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
767
      const std::vector<uint8_t> pubkey_vec(pubkey, pubkey + 32);
1✔
768
      auto ed25519 = std::make_unique<Botan::Ed25519_PublicKey>(pubkey_vec);
1✔
769
      *key = new botan_pubkey_struct(std::move(ed25519));
2✔
770
      return BOTAN_FFI_SUCCESS;
1✔
771
   });
2✔
772
#else
773
   BOTAN_UNUSED(key, pubkey);
774
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
775
#endif
776
}
777

778
int botan_privkey_ed25519_get_privkey(botan_privkey_t key, uint8_t output[64]) {
1✔
779
#if defined(BOTAN_HAS_ED25519)
780
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
781
      if(auto ed = dynamic_cast<const Botan::Ed25519_PrivateKey*>(&k)) {
782
         const auto ed_key = ed->raw_private_key_bits();
783
         if(ed_key.size() != 64) {
784
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
785
         }
786
         Botan::copy_mem(output, ed_key.data(), ed_key.size());
787
         return BOTAN_FFI_SUCCESS;
788
      } else {
789
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
790
      }
791
   });
792
#else
793
   BOTAN_UNUSED(key, output);
794
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
795
#endif
796
}
797

798
int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key, uint8_t output[32]) {
1✔
799
#if defined(BOTAN_HAS_ED25519)
800
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
2✔
801
      if(auto ed = dynamic_cast<const Botan::Ed25519_PublicKey*>(&k)) {
802
         const std::vector<uint8_t>& ed_key = ed->get_public_key();
803
         if(ed_key.size() != 32) {
804
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
805
         }
806
         Botan::copy_mem(output, ed_key.data(), ed_key.size());
807
         return BOTAN_FFI_SUCCESS;
808
      } else {
809
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
810
      }
811
   });
812
#else
813
   BOTAN_UNUSED(key, output);
814
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
815
#endif
816
}
817

818
/* Ed448 specific operations */
819

820
int botan_privkey_load_ed448(botan_privkey_t* key, const uint8_t privkey[57]) {
1✔
821
#if defined(BOTAN_HAS_ED448)
822
   if(key == nullptr) {
1✔
823
      return BOTAN_FFI_ERROR_NULL_POINTER;
824
   }
825
   *key = nullptr;
1✔
826
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
827
      auto ed448 = std::make_unique<Botan::Ed448_PrivateKey>(std::span(privkey, 57));
1✔
828
      *key = new botan_privkey_struct(std::move(ed448));
2✔
829
      return BOTAN_FFI_SUCCESS;
1✔
830
   });
1✔
831
#else
832
   BOTAN_UNUSED(key, privkey);
833
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
834
#endif
835
}
836

837
int botan_pubkey_load_ed448(botan_pubkey_t* key, const uint8_t pubkey[57]) {
1✔
838
#if defined(BOTAN_HAS_ED448)
839
   if(key == nullptr) {
1✔
840
      return BOTAN_FFI_ERROR_NULL_POINTER;
841
   }
842
   *key = nullptr;
1✔
843
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
844
      auto ed448 = std::make_unique<Botan::Ed448_PublicKey>(std::span(pubkey, 57));
1✔
845
      *key = new botan_pubkey_struct(std::move(ed448));
2✔
846
      return BOTAN_FFI_SUCCESS;
1✔
847
   });
1✔
848
#else
849
   BOTAN_UNUSED(key, pubkey);
850
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
851
#endif
852
}
853

854
int botan_privkey_ed448_get_privkey(botan_privkey_t key, uint8_t output[57]) {
1✔
855
#if defined(BOTAN_HAS_ED448)
856
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
857
      if(auto ed = dynamic_cast<const Botan::Ed448_PrivateKey*>(&k)) {
858
         const auto ed_key = ed->raw_private_key_bits();
859
         Botan::copy_mem(std::span(output, 57), ed_key);
860
         return BOTAN_FFI_SUCCESS;
861
      } else {
862
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
863
      }
864
   });
865
#else
866
   BOTAN_UNUSED(key, output);
867
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
868
#endif
869
}
870

871
int botan_pubkey_ed448_get_pubkey(botan_pubkey_t key, uint8_t output[57]) {
1✔
872
#if defined(BOTAN_HAS_ED448)
873
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
3✔
874
      if(auto ed = dynamic_cast<const Botan::Ed448_PublicKey*>(&k)) {
875
         const auto ed_key = ed->public_key_bits();
876
         Botan::copy_mem(std::span(output, 57), ed_key);
877
         return BOTAN_FFI_SUCCESS;
878
      } else {
879
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
880
      }
881
   });
882
#else
883
   BOTAN_UNUSED(key, output);
884
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
885
#endif
886
}
887

888
/* X25519 specific operations */
889

890
int botan_privkey_load_x25519(botan_privkey_t* key, const uint8_t privkey[32]) {
1✔
891
#if defined(BOTAN_HAS_X25519)
892
   if(key == nullptr) {
1✔
893
      return BOTAN_FFI_ERROR_NULL_POINTER;
894
   }
895
   *key = nullptr;
1✔
896
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
897
      const Botan::secure_vector<uint8_t> privkey_vec(privkey, privkey + 32);
1✔
898
      auto x25519 = std::make_unique<Botan::X25519_PrivateKey>(privkey_vec);
1✔
899
      *key = new botan_privkey_struct(std::move(x25519));
2✔
900
      return BOTAN_FFI_SUCCESS;
2✔
901
   });
2✔
902
#else
903
   BOTAN_UNUSED(key, privkey);
904
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
905
#endif
906
}
907

908
int botan_pubkey_load_x25519(botan_pubkey_t* key, const uint8_t pubkey[32]) {
1✔
909
#if defined(BOTAN_HAS_X25519)
910
   if(key == nullptr) {
1✔
911
      return BOTAN_FFI_ERROR_NULL_POINTER;
912
   }
913
   *key = nullptr;
1✔
914
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
915
      const std::vector<uint8_t> pubkey_vec(pubkey, pubkey + 32);
1✔
916
      auto x25519 = std::make_unique<Botan::X25519_PublicKey>(pubkey_vec);
1✔
917
      *key = new botan_pubkey_struct(std::move(x25519));
2✔
918
      return BOTAN_FFI_SUCCESS;
1✔
919
   });
2✔
920
#else
921
   BOTAN_UNUSED(key, pubkey);
922
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
923
#endif
924
}
925

926
int botan_privkey_x25519_get_privkey(botan_privkey_t key, uint8_t output[32]) {
1✔
927
#if defined(BOTAN_HAS_X25519)
928
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
929
      if(auto x25519 = dynamic_cast<const Botan::X25519_PrivateKey*>(&k)) {
930
         const auto x25519_key = x25519->raw_private_key_bits();
931
         if(x25519_key.size() != 32) {
932
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
933
         }
934
         Botan::copy_mem(output, x25519_key.data(), x25519_key.size());
935
         return BOTAN_FFI_SUCCESS;
936
      } else {
937
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
938
      }
939
   });
940
#else
941
   BOTAN_UNUSED(key, output);
942
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
943
#endif
944
}
945

946
int botan_pubkey_x25519_get_pubkey(botan_pubkey_t key, uint8_t output[32]) {
2✔
947
#if defined(BOTAN_HAS_X25519)
948
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
8✔
949
      if(auto x25519 = dynamic_cast<const Botan::X25519_PublicKey*>(&k)) {
950
         const std::vector<uint8_t>& x25519_key = x25519->public_value();
951
         if(x25519_key.size() != 32) {
952
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
953
         }
954
         Botan::copy_mem(output, x25519_key.data(), x25519_key.size());
955
         return BOTAN_FFI_SUCCESS;
956
      } else {
957
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
958
      }
959
   });
960
#else
961
   BOTAN_UNUSED(key, output);
962
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
963
#endif
964
}
965

966
/* X448 specific operations */
967

968
int botan_privkey_load_x448(botan_privkey_t* key, const uint8_t privkey[56]) {
1✔
969
#if defined(BOTAN_HAS_X448)
970
   if(key == nullptr) {
1✔
971
      return BOTAN_FFI_ERROR_NULL_POINTER;
972
   }
973
   *key = nullptr;
1✔
974
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
975
      auto x448 = std::make_unique<Botan::X448_PrivateKey>(std::span(privkey, 56));
1✔
976
      *key = new botan_privkey_struct(std::move(x448));
2✔
977
      return BOTAN_FFI_SUCCESS;
1✔
978
   });
1✔
979
#else
980
   BOTAN_UNUSED(key, privkey);
981
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
982
#endif
983
}
984

985
int botan_pubkey_load_x448(botan_pubkey_t* key, const uint8_t pubkey[56]) {
1✔
986
#if defined(BOTAN_HAS_X448)
987
   if(key == nullptr) {
1✔
988
      return BOTAN_FFI_ERROR_NULL_POINTER;
989
   }
990
   *key = nullptr;
1✔
991
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
992
      auto x448 = std::make_unique<Botan::X448_PublicKey>(std::span(pubkey, 56));
1✔
993
      *key = new botan_pubkey_struct(std::move(x448));
2✔
994
      return BOTAN_FFI_SUCCESS;
1✔
995
   });
1✔
996
#else
997
   BOTAN_UNUSED(key, pubkey);
998
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
999
#endif
1000
}
1001

1002
int botan_privkey_x448_get_privkey(botan_privkey_t key, uint8_t output[56]) {
1✔
1003
#if defined(BOTAN_HAS_X448)
1004
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
1005
      if(auto x448 = dynamic_cast<const Botan::X448_PrivateKey*>(&k)) {
1006
         const auto x448_key = x448->raw_private_key_bits();
1007
         Botan::copy_mem(std::span(output, 56), x448_key);
1008
         return BOTAN_FFI_SUCCESS;
1009
      } else {
1010
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1011
      }
1012
   });
1013
#else
1014
   BOTAN_UNUSED(key, output);
1015
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1016
#endif
1017
}
1018

1019
int botan_pubkey_x448_get_pubkey(botan_pubkey_t key, uint8_t output[56]) {
2✔
1020
#if defined(BOTAN_HAS_X448)
1021
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
8✔
1022
      if(auto x448 = dynamic_cast<const Botan::X448_PublicKey*>(&k)) {
1023
         const std::vector<uint8_t>& x448_key = x448->public_value();
1024
         Botan::copy_mem(std::span(output, 56), x448_key);
1025
         return BOTAN_FFI_SUCCESS;
1026
      } else {
1027
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1028
      }
1029
   });
1030
#else
1031
   BOTAN_UNUSED(key, output);
1032
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1033
#endif
1034
}
1035

1036
/*
1037
* Algorithm specific key operations: Kyber
1038
*/
1039

1040
int botan_privkey_load_kyber(botan_privkey_t* key, const uint8_t privkey[], size_t key_len) {
4✔
1041
#if defined(BOTAN_HAS_KYBER)
1042
   if(key == nullptr) {
4✔
1043
      return BOTAN_FFI_ERROR_NULL_POINTER;
1044
   }
1045
   *key = nullptr;
4✔
1046

1047
   const auto mode = [](size_t len) -> std::optional<Botan::KyberMode> {
12✔
1048
      if(len == 1632) {
4✔
1049
         return Botan::KyberMode::Kyber512_R3;
1✔
1050
      } else if(len == 2400) {
3✔
1051
         return Botan::KyberMode::Kyber768_R3;
2✔
1052
      } else if(len == 3168) {
1✔
1053
         return Botan::KyberMode::Kyber1024_R3;
1✔
1054
      } else {
1055
         return {};
×
1056
      }
1057
   }(key_len);
4✔
1058

1059
   if(mode.has_value()) {
4✔
1060
      return ffi_guard_thunk(__func__, [=]() -> int {
8✔
1061
         auto kyber = std::make_unique<Botan::Kyber_PrivateKey>(std::span{privkey, key_len}, *mode);
4✔
1062
         *key = new botan_privkey_struct(std::move(kyber));
4✔
1063
         return BOTAN_FFI_SUCCESS;
4✔
1064
      });
4✔
1065
   } else {
1066
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1067
   }
1068
#else
1069
   BOTAN_UNUSED(key, key_len, privkey);
1070
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1071
#endif
1072
}
1073

1074
int botan_pubkey_load_kyber(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len) {
4✔
1075
#if defined(BOTAN_HAS_KYBER)
1076
   if(key == nullptr) {
4✔
1077
      return BOTAN_FFI_ERROR_NULL_POINTER;
1078
   }
1079
   *key = nullptr;
4✔
1080

1081
   const auto mode = [](size_t len) -> std::optional<Botan::KyberMode> {
12✔
1082
      if(len == 800) {
4✔
1083
         return Botan::KyberMode::Kyber512_R3;
1✔
1084
      } else if(len == 1184) {
3✔
1085
         return Botan::KyberMode::Kyber768_R3;
2✔
1086
      } else if(len == 1568) {
1✔
1087
         return Botan::KyberMode::Kyber1024_R3;
1✔
1088
      } else {
1089
         return {};
×
1090
      }
1091
   }(key_len);
4✔
1092

1093
   if(mode.has_value()) {
4✔
1094
      auto kyber = std::make_unique<Botan::Kyber_PublicKey>(std::span{pubkey, key_len}, *mode);
4✔
1095
      *key = new botan_pubkey_struct(std::move(kyber));
8✔
1096
      return BOTAN_FFI_SUCCESS;
4✔
1097
   } else {
4✔
1098
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1099
   }
1100
#else
1101
   BOTAN_UNUSED(key, pubkey, key_len);
1102
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1103
#endif
1104
}
1105

1106
int botan_privkey_view_kyber_raw_key(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
4✔
1107
#if defined(BOTAN_HAS_KYBER)
1108
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
16✔
1109
      if(auto kyber = dynamic_cast<const Botan::Kyber_PrivateKey*>(&k)) {
1110
         return invoke_view_callback(view, ctx, kyber->raw_private_key_bits());
1111
      } else {
1112
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1113
      }
1114
   });
1115
#else
1116
   BOTAN_UNUSED(key, ctx, view);
1117
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1118
#endif
1119
}
1120

1121
int botan_pubkey_view_kyber_raw_key(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
8✔
1122
#if defined(BOTAN_HAS_KYBER)
1123
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
32✔
1124
      if(auto kyber = dynamic_cast<const Botan::Kyber_PublicKey*>(&k)) {
1125
         return invoke_view_callback(view, ctx, kyber->public_key_bits());
1126
      } else {
1127
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1128
      }
1129
   });
1130
#else
1131
   BOTAN_UNUSED(key, ctx, view);
1132
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1133
#endif
1134
}
1135

1136
/*
1137
* Algorithm specific key operations: ML-KEM
1138
*/
1139

1140
int botan_privkey_load_ml_kem(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* mlkem_mode) {
4✔
1141
#if defined(BOTAN_HAS_ML_KEM)
1142
   if(key == nullptr || privkey == nullptr || mlkem_mode == nullptr) {
4✔
1143
      return BOTAN_FFI_ERROR_NULL_POINTER;
1144
   }
1145

1146
   *key = nullptr;
4✔
1147

1148
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
1149
      auto mode = Botan::ML_KEM_Mode(mlkem_mode);
4✔
1150
      if(!mode.is_ml_kem()) {
4✔
1151
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1152
      }
1153

1154
      auto mlkem_key = std::make_unique<Botan::ML_KEM_PrivateKey>(std::span{privkey, key_len}, mode);
4✔
1155
      *key = new botan_privkey_struct(std::move(mlkem_key));
4✔
1156
      return BOTAN_FFI_SUCCESS;
4✔
1157
   });
4✔
1158
#else
1159
   BOTAN_UNUSED(key, key_len, privkey, mlkem_mode);
1160
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1161
#endif
1162
}
1163

1164
int botan_pubkey_load_ml_kem(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* mlkem_mode) {
4✔
1165
#if defined(BOTAN_HAS_ML_KEM)
1166
   if(key == nullptr || pubkey == nullptr || mlkem_mode == nullptr) {
4✔
1167
      return BOTAN_FFI_ERROR_NULL_POINTER;
1168
   }
1169

1170
   *key = nullptr;
4✔
1171

1172
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
1173
      auto mode = Botan::ML_KEM_Mode(mlkem_mode);
4✔
1174
      if(!mode.is_ml_kem()) {
4✔
1175
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1176
      }
1177

1178
      auto mlkem_key = std::make_unique<Botan::ML_KEM_PublicKey>(std::span{pubkey, key_len}, mode.mode());
4✔
1179
      *key = new botan_pubkey_struct(std::move(mlkem_key));
8✔
1180
      return BOTAN_FFI_SUCCESS;
4✔
1181
   });
4✔
1182
#else
1183
   BOTAN_UNUSED(key, key_len, pubkey, mlkem_mode);
1184
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1185
#endif
1186
}
1187

1188
/*
1189
* Algorithm specific key operations: ML-DSA
1190
*/
1191

1192
int botan_privkey_load_ml_dsa(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* mldsa_mode) {
4✔
1193
#if defined(BOTAN_HAS_ML_DSA)
1194
   if(key == nullptr || privkey == nullptr || mldsa_mode == nullptr) {
4✔
1195
      return BOTAN_FFI_ERROR_NULL_POINTER;
1196
   }
1197

1198
   *key = nullptr;
4✔
1199

1200
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
1201
      auto mode = Botan::ML_DSA_Mode(mldsa_mode);
4✔
1202
      if(!mode.is_ml_dsa()) {
4✔
1203
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1204
      }
1205

1206
      auto mldsa_key = std::make_unique<Botan::ML_DSA_PrivateKey>(std::span{privkey, key_len}, mode);
4✔
1207
      *key = new botan_privkey_struct(std::move(mldsa_key));
4✔
1208
      return BOTAN_FFI_SUCCESS;
4✔
1209
   });
4✔
1210
#else
1211
   BOTAN_UNUSED(key, key_len, privkey, mldsa_mode);
1212
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1213
#endif
1214
}
1215

1216
int botan_pubkey_load_ml_dsa(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* mldsa_mode) {
4✔
1217
#if defined(BOTAN_HAS_ML_DSA)
1218
   if(key == nullptr || pubkey == nullptr || mldsa_mode == nullptr) {
4✔
1219
      return BOTAN_FFI_ERROR_NULL_POINTER;
1220
   }
1221

1222
   *key = nullptr;
4✔
1223

1224
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
1225
      auto mode = Botan::ML_DSA_Mode(mldsa_mode);
4✔
1226
      if(!mode.is_ml_dsa()) {
4✔
1227
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1228
      }
1229

1230
      auto mldsa_key = std::make_unique<Botan::ML_DSA_PublicKey>(std::span{pubkey, key_len}, mode);
4✔
1231
      *key = new botan_pubkey_struct(std::move(mldsa_key));
8✔
1232
      return BOTAN_FFI_SUCCESS;
4✔
1233
   });
4✔
1234
#else
1235
   BOTAN_UNUSED(key, key_len, pubkey, mldsa_mode);
1236
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1237
#endif
1238
}
1239

1240
/*
1241
* Algorithm specific key operations: SLH-DSA
1242
*/
1243

1244
int botan_privkey_load_slh_dsa(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* slhdsa_mode) {
13✔
1245
#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
1246
   if(key == nullptr || privkey == nullptr || slhdsa_mode == nullptr) {
13✔
1247
      return BOTAN_FFI_ERROR_NULL_POINTER;
1248
   }
1249

1250
   *key = nullptr;
13✔
1251

1252
   return ffi_guard_thunk(__func__, [=]() -> int {
26✔
1253
      auto mode = Botan::SLH_DSA_Parameters::create(slhdsa_mode);
13✔
1254
      if(!mode.is_slh_dsa()) {
13✔
1255
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1256
      }
1257

1258
      auto slhdsa_key = std::make_unique<Botan::SLH_DSA_PrivateKey>(std::span{privkey, key_len}, mode);
13✔
1259
      *key = new botan_privkey_struct(std::move(slhdsa_key));
13✔
1260
      return BOTAN_FFI_SUCCESS;
13✔
1261
   });
13✔
1262
#else
1263
   BOTAN_UNUSED(key, key_len, privkey, slhdsa_mode);
1264
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1265
#endif
1266
}
1267

1268
int botan_pubkey_load_slh_dsa(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* slhdsa_mode) {
13✔
1269
#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
1270
   if(key == nullptr || pubkey == nullptr || slhdsa_mode == nullptr) {
13✔
1271
      return BOTAN_FFI_ERROR_NULL_POINTER;
1272
   }
1273

1274
   *key = nullptr;
13✔
1275

1276
   return ffi_guard_thunk(__func__, [=]() -> int {
26✔
1277
      auto mode = Botan::SLH_DSA_Parameters::create(slhdsa_mode);
13✔
1278
      if(!mode.is_slh_dsa()) {
13✔
1279
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1280
      }
1281

1282
      auto mldsa_key = std::make_unique<Botan::SLH_DSA_PublicKey>(std::span{pubkey, key_len}, mode);
13✔
1283
      *key = new botan_pubkey_struct(std::move(mldsa_key));
26✔
1284
      return BOTAN_FFI_SUCCESS;
13✔
1285
   });
13✔
1286
#else
1287
   BOTAN_UNUSED(key, key_len, pubkey, slhdsa_mode);
1288
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1289
#endif
1290
}
1291

1292
/*
1293
* Algorithm specific key operations: FrodoKEM
1294
*/
1295

1296
int botan_privkey_load_frodokem(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* frodo_mode) {
13✔
1297
#if defined(BOTAN_HAS_FRODOKEM)
1298
   if(key == nullptr || privkey == nullptr || frodo_mode == nullptr) {
13✔
1299
      return BOTAN_FFI_ERROR_NULL_POINTER;
1300
   }
1301

1302
   *key = nullptr;
13✔
1303

1304
   return ffi_guard_thunk(__func__, [=]() -> int {
26✔
1305
      const auto mode = Botan::FrodoKEMMode(frodo_mode);
13✔
1306
      auto frodo_key = std::make_unique<Botan::FrodoKEM_PrivateKey>(std::span{privkey, key_len}, mode);
13✔
1307
      *key = new botan_privkey_struct(std::move(frodo_key));
13✔
1308
      return BOTAN_FFI_SUCCESS;
13✔
1309
   });
13✔
1310
#else
1311
   BOTAN_UNUSED(key, privkey, key_len, frodo_mode);
1312
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1313
#endif
1314
}
1315

1316
int botan_pubkey_load_frodokem(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* frodo_mode) {
13✔
1317
#if defined(BOTAN_HAS_FRODOKEM)
1318
   if(key == nullptr || pubkey == nullptr || frodo_mode == nullptr) {
13✔
1319
      return BOTAN_FFI_ERROR_NULL_POINTER;
1320
   }
1321

1322
   *key = nullptr;
13✔
1323

1324
   return ffi_guard_thunk(__func__, [=]() -> int {
26✔
1325
      const auto mode = Botan::FrodoKEMMode(frodo_mode);
13✔
1326
      auto frodo_key = std::make_unique<Botan::FrodoKEM_PublicKey>(std::span{pubkey, key_len}, mode);
13✔
1327
      *key = new botan_pubkey_struct(std::move(frodo_key));
26✔
1328
      return BOTAN_FFI_SUCCESS;
13✔
1329
   });
13✔
1330
#else
1331
   BOTAN_UNUSED(key, pubkey, key_len, frodo_mode);
1332
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1333
#endif
1334
}
1335

1336
/*
1337
* Algorithm specific key operations : Classic McEliece
1338
*/
1339

1340
int botan_privkey_load_classic_mceliece(botan_privkey_t* key,
17✔
1341
                                        const uint8_t privkey[],
1342
                                        size_t key_len,
1343
                                        const char* cmce_mode) {
1344
#if defined(BOTAN_HAS_CLASSICMCELIECE)
1345
   if(key == nullptr || privkey == nullptr || cmce_mode == nullptr) {
17✔
1346
      return BOTAN_FFI_ERROR_NULL_POINTER;
1347
   }
1348

1349
   *key = nullptr;
17✔
1350

1351
   return ffi_guard_thunk(__func__, [=]() -> int {
34✔
1352
      const auto mode = Botan::Classic_McEliece_Parameter_Set::from_string(cmce_mode);
17✔
1353
      auto cmce_key = std::make_unique<Botan::Classic_McEliece_PrivateKey>(std::span{privkey, key_len}, mode);
17✔
1354
      *key = new botan_privkey_struct(std::move(cmce_key));
17✔
1355
      return BOTAN_FFI_SUCCESS;
17✔
1356
   });
17✔
1357
#else
1358
   BOTAN_UNUSED(key, privkey, key_len, cmce_mode);
1359
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1360
#endif
1361
}
1362

1363
int botan_pubkey_load_classic_mceliece(botan_pubkey_t* key,
17✔
1364
                                       const uint8_t pubkey[],
1365
                                       size_t key_len,
1366
                                       const char* cmce_mode) {
1367
#if defined(BOTAN_HAS_CLASSICMCELIECE)
1368
   if(key == nullptr || pubkey == nullptr || cmce_mode == nullptr) {
17✔
1369
      return BOTAN_FFI_ERROR_NULL_POINTER;
1370
   }
1371

1372
   *key = nullptr;
17✔
1373

1374
   return ffi_guard_thunk(__func__, [=]() -> int {
34✔
1375
      const auto mode = Botan::Classic_McEliece_Parameter_Set::from_string(cmce_mode);
17✔
1376
      auto cmce_key = std::make_unique<Botan::Classic_McEliece_PublicKey>(std::span{pubkey, key_len}, mode);
17✔
1377
      *key = new botan_pubkey_struct(std::move(cmce_key));
34✔
1378
      return BOTAN_FFI_SUCCESS;
17✔
1379
   });
17✔
1380
#else
1381
   BOTAN_UNUSED(key, pubkey, key_len, cmce_mode);
1382
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1383
#endif
1384
}
1385

1386
int botan_pubkey_view_ec_public_point(const botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
6✔
1387
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
1388
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
24✔
1389
      if(auto ecc = dynamic_cast<const Botan::EC_PublicKey*>(&k)) {
1390
         auto pt = ecc->_public_ec_point().serialize_uncompressed();
1391
         return invoke_view_callback(view, ctx, pt);
1392
      } else {
1393
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1394
      }
1395
   });
1396
#else
1397
   BOTAN_UNUSED(key, view, ctx);
1398
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1399
#endif
1400
}
1401

1402
int botan_privkey_create_mceliece(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n, size_t t) {
1✔
1403
   const std::string mce_params = std::to_string(n) + "," + std::to_string(t);
3✔
1404
   return botan_privkey_create(key_obj, "McEliece", mce_params.c_str(), rng_obj);
1✔
1405
}
1✔
1406

1407
int botan_mceies_decrypt(botan_privkey_t mce_key_obj,
×
1408
                         const char* aead,
1409
                         const uint8_t ct[],
1410
                         size_t ct_len,
1411
                         const uint8_t ad[],
1412
                         size_t ad_len,
1413
                         uint8_t out[],
1414
                         size_t* out_len) {
1415
   BOTAN_UNUSED(mce_key_obj, aead, ct, ct_len, ad, ad_len, out, out_len);
×
1416
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
×
1417
}
1418

1419
int botan_mceies_encrypt(botan_pubkey_t mce_key_obj,
×
1420
                         botan_rng_t rng_obj,
1421
                         const char* aead,
1422
                         const uint8_t pt[],
1423
                         size_t pt_len,
1424
                         const uint8_t ad[],
1425
                         size_t ad_len,
1426
                         uint8_t out[],
1427
                         size_t* out_len) {
1428
   BOTAN_UNUSED(mce_key_obj, rng_obj, aead, pt, pt_len, ad, ad_len, out, out_len);
×
1429
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
×
1430
}
1431
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc