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

randombit / botan / 17374212301

01 Sep 2025 09:01AM UTC coverage: 90.667% (-0.002%) from 90.669%
17374212301

push

github

web-flow
Merge pull request #5083 from Rohde-Schwarz/feature/load_compressed_ecc_key

Allow loading (compressed) SEC.1-encoded ECC keys via FFI and Python

100313 of 110639 relevant lines covered (90.67%)

12230325.25 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
template <class ECPublicKey_t>
143
int pubkey_load_ec_sec1(std::unique_ptr<ECPublicKey_t>& key,
14✔
144
                        std::span<const uint8_t> sec1,
145
                        std::string_view curve_name) {
146
   if(!Botan::EC_Group::supports_named_group(curve_name)) {
14✔
147
      return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
148
   }
149

150
   const auto group = Botan::EC_Group::from_name(curve_name);
14✔
151

152
   if(auto pt = Botan::EC_AffinePoint::deserialize(group, sec1)) {
14✔
153
      key.reset(new ECPublicKey_t(group, pt.value()));
14✔
154
      return BOTAN_FFI_SUCCESS;
14✔
155
   } else {
156
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
157
   }
158
}
14✔
159

160
#endif
161

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

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

181
Botan::BigInt privkey_get_field(const Botan::Private_Key& key, std::string_view field) {
35✔
182
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
183
   // Not currently handled by get_int_field
184
   if(const Botan::EC_PublicKey* ecc = dynamic_cast<const Botan::EC_PublicKey*>(&key)) {
35✔
185
      if(field == "public_x") {
16✔
186
         return Botan::BigInt::from_bytes(ecc->_public_ec_point().x_bytes());
4✔
187
      } else if(field == "public_y") {
14✔
188
         return Botan::BigInt::from_bytes(ecc->_public_ec_point().y_bytes());
8✔
189
      }
190
   }
191
#endif
192

193
   try {
29✔
194
      return key.get_int_field(field);
29✔
195
   } catch(Botan::Unknown_PK_Field_Name&) {
4✔
196
      throw Botan_FFI::FFI_Error("Unknown key field", BOTAN_FFI_ERROR_BAD_PARAMETER);
4✔
197
   }
4✔
198
}
199

200
}  // namespace
201

202
extern "C" {
203

204
using namespace Botan_FFI;
205

206
int botan_pubkey_get_field(botan_mp_t output, botan_pubkey_t key, const char* field_name_cstr) {
40✔
207
   if(field_name_cstr == nullptr) {
40✔
208
      return BOTAN_FFI_ERROR_NULL_POINTER;
209
   }
210

211
   const std::string field_name(field_name_cstr);
40✔
212

213
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { safe_get(output) = pubkey_get_field(k, field_name); });
158✔
214
}
40✔
215

216
int botan_privkey_get_field(botan_mp_t output, botan_privkey_t key, const char* field_name_cstr) {
35✔
217
   if(field_name_cstr == nullptr) {
35✔
218
      return BOTAN_FFI_ERROR_NULL_POINTER;
219
   }
220

221
   const std::string field_name(field_name_cstr);
35✔
222

223
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { safe_get(output) = privkey_get_field(k, field_name); });
136✔
224
}
35✔
225

226
/* RSA specific operations */
227

228
int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits) {
2✔
229
   if(n_bits < 1024 || n_bits > 16 * 1024) {
2✔
230
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
231
   }
232

233
   std::string n_str = std::to_string(n_bits);
2✔
234

235
   return botan_privkey_create(key_obj, "RSA", n_str.c_str(), rng_obj);
2✔
236
}
2✔
237

238
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✔
239
#if defined(BOTAN_HAS_RSA)
240
   if(key == nullptr) {
2✔
241
      return BOTAN_FFI_ERROR_NULL_POINTER;
242
   }
243
   *key = nullptr;
2✔
244

245
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
246
      auto rsa = std::make_unique<Botan::RSA_PrivateKey>(safe_get(rsa_p), safe_get(rsa_q), safe_get(rsa_e));
2✔
247
      return ffi_new_object(key, std::move(rsa));
4✔
248
   });
4✔
249
#else
250
   BOTAN_UNUSED(key, rsa_p, rsa_q, rsa_e);
251
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
252
#endif
253
}
254

255
int botan_privkey_load_rsa_pkcs1(botan_privkey_t* key, const uint8_t bits[], size_t len) {
1✔
256
#if defined(BOTAN_HAS_RSA)
257
   if(key == nullptr || bits == nullptr) {
1✔
258
      return BOTAN_FFI_ERROR_NULL_POINTER;
259
   }
260
   *key = nullptr;
1✔
261

262
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
263
      Botan::AlgorithmIdentifier alg_id("RSA", Botan::AlgorithmIdentifier::USE_NULL_PARAM);
1✔
264
      auto rsa = std::make_unique<Botan::RSA_PrivateKey>(alg_id, std::span{bits, len});
1✔
265
      return ffi_new_object(key, std::move(rsa));
2✔
266
   });
2✔
267
#else
268
   BOTAN_UNUSED(key, bits, len);
269
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
270
#endif
271
}
272

273
int botan_pubkey_load_rsa(botan_pubkey_t* key, botan_mp_t n, botan_mp_t e) {
4✔
274
#if defined(BOTAN_HAS_RSA)
275
   if(key == nullptr) {
4✔
276
      return BOTAN_FFI_ERROR_NULL_POINTER;
277
   }
278
   *key = nullptr;
4✔
279
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
280
      auto rsa = std::make_unique<Botan::RSA_PublicKey>(safe_get(n), safe_get(e));
4✔
281
      return ffi_new_object(key, std::move(rsa));
3✔
282
   });
7✔
283
#else
284
   BOTAN_UNUSED(key, n, e);
285
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
286
#endif
287
}
288

289
int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t key) {
1✔
290
   return botan_privkey_get_field(p, key, "p");
1✔
291
}
292

293
int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t key) {
1✔
294
   return botan_privkey_get_field(q, key, "q");
1✔
295
}
296

297
int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t key) {
1✔
298
   return botan_privkey_get_field(n, key, "n");
1✔
299
}
300

301
int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t key) {
1✔
302
   return botan_privkey_get_field(e, key, "e");
1✔
303
}
304

305
int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t key) {
1✔
306
   return botan_privkey_get_field(d, key, "d");
1✔
307
}
308

309
int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t key) {
1✔
310
   return botan_pubkey_get_field(e, key, "e");
1✔
311
}
312

313
int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t key) {
1✔
314
   return botan_pubkey_get_field(n, key, "n");
1✔
315
}
316

317
int botan_privkey_rsa_get_privkey(botan_privkey_t rsa_key, uint8_t out[], size_t* out_len, uint32_t flags) {
4✔
318
#if defined(BOTAN_HAS_RSA)
319
   return BOTAN_FFI_VISIT(rsa_key, [=](const auto& k) -> int {
14✔
320
      if(const Botan::RSA_PrivateKey* rsa = dynamic_cast<const Botan::RSA_PrivateKey*>(&k)) {
321
         if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
322
            return write_vec_output(out, out_len, rsa->private_key_bits());
323
         } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
324
            // TODO define new generic functions for this
325
            return write_str_output(reinterpret_cast<char*>(out),
326
                                    out_len,
327
                                    Botan::PEM_Code::encode(rsa->private_key_bits(), "RSA PRIVATE KEY"));
328
         } else {
329
            return BOTAN_FFI_ERROR_BAD_FLAG;
330
         }
331
      } else {
332
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
333
      }
334
   });
335
#else
336
   BOTAN_UNUSED(rsa_key, out, out_len, flags);
337
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
338
#endif
339
}
340

341
/* DSA specific operations */
342
int botan_privkey_create_dsa(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) {
1✔
343
#if defined(BOTAN_HAS_DSA)
344

345
   if((rng_obj == nullptr) || (key == nullptr)) {
1✔
346
      return BOTAN_FFI_ERROR_NULL_POINTER;
347
   }
348

349
   if((pbits % 64 != 0) || (qbits % 8 != 0) || (pbits < 1024) || (pbits > 3072) || (qbits < 160) || (qbits > 256)) {
1✔
350
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
351
   }
352

353
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
354
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
1✔
355
      Botan::DL_Group group(rng, Botan::DL_Group::Prime_Subgroup, pbits, qbits);
1✔
356
      auto dsa = std::make_unique<Botan::DSA_PrivateKey>(rng, group);
1✔
357
      return ffi_new_object(key, std::move(dsa));
1✔
358
   });
3✔
359
#else
360
   BOTAN_UNUSED(key, rng_obj, pbits, qbits);
361
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
362
#endif
363
}
364

365
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✔
366
#if defined(BOTAN_HAS_DSA)
367
   if(key == nullptr) {
2✔
368
      return BOTAN_FFI_ERROR_NULL_POINTER;
369
   }
370
   *key = nullptr;
2✔
371

372
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
373
      Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
2✔
374
      auto dsa = std::make_unique<Botan::DSA_PrivateKey>(group, safe_get(x));
2✔
375
      return ffi_new_object(key, std::move(dsa));
2✔
376
   });
6✔
377
#else
378
   BOTAN_UNUSED(key, p, q, g, x);
379
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
380
#endif
381
}
382

383
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✔
384
#if defined(BOTAN_HAS_DSA)
385
   if(key == nullptr) {
2✔
386
      return BOTAN_FFI_ERROR_NULL_POINTER;
387
   }
388
   *key = nullptr;
2✔
389

390
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
391
      Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
2✔
392
      auto dsa = std::make_unique<Botan::DSA_PublicKey>(group, safe_get(y));
2✔
393
      return ffi_new_object(key, std::move(dsa));
2✔
394
   });
6✔
395
#else
396
   BOTAN_UNUSED(key, p, q, g, y);
397
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
398
#endif
399
}
400

401
int botan_privkey_dsa_get_x(botan_mp_t x, botan_privkey_t key) {
2✔
402
   return botan_privkey_get_field(x, key, "x");
2✔
403
}
404

405
int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key) {
2✔
406
   return botan_pubkey_get_field(p, key, "p");
2✔
407
}
408

409
int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key) {
2✔
410
   return botan_pubkey_get_field(q, key, "q");
2✔
411
}
412

413
int botan_pubkey_dsa_get_g(botan_mp_t g, botan_pubkey_t key) {
2✔
414
   return botan_pubkey_get_field(g, key, "g");
2✔
415
}
416

417
int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key) {
2✔
418
   return botan_pubkey_get_field(y, key, "y");
2✔
419
}
420

421
int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) {
1✔
422
   return botan_privkey_create(key_obj, "ECDSA", param_str, rng_obj);
1✔
423
}
424

425
/* ECDSA specific operations */
426

427
int botan_pubkey_ecc_key_used_explicit_encoding(botan_pubkey_t key) {
1✔
428
#if defined(BOTAN_HAS_ECC_KEY)
429
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
430
      const Botan::Public_Key& pub_key = safe_get(key);
1✔
431
      const Botan::EC_PublicKey* ec_key = dynamic_cast<const Botan::EC_PublicKey*>(&pub_key);
1✔
432

433
      if(ec_key == nullptr) {
1✔
434
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
435
      }
436

437
      return ec_key->domain().used_explicit_encoding() ? 1 : 0;
1✔
438
   });
1✔
439
#else
440
   BOTAN_UNUSED(key);
441
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
442
#endif
443
}
444

445
// NOLINTBEGIN(misc-misplaced-const)
446

447
int botan_pubkey_load_ecdsa(botan_pubkey_t* key,
2✔
448
                            const botan_mp_t public_x,
449
                            const botan_mp_t public_y,
450
                            const char* curve_name) {
451
#if defined(BOTAN_HAS_ECDSA)
452
   if(key == nullptr || curve_name == nullptr) {
2✔
453
      return BOTAN_FFI_ERROR_NULL_POINTER;
454
   }
455
   *key = nullptr;
2✔
456

457
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
458
      std::unique_ptr<Botan::ECDSA_PublicKey> p_key;
2✔
459

460
      int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
2✔
461
      if(rc == BOTAN_FFI_SUCCESS) {
2✔
462
         ffi_new_object(key, std::move(p_key));
2✔
463
      }
464

465
      return rc;
2✔
466
   });
4✔
467
#else
468
   BOTAN_UNUSED(key, public_x, public_y, curve_name);
469
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
470
#endif
471
}
472

473
int botan_pubkey_load_ecdsa_sec1(botan_pubkey_t* key, const uint8_t sec1[], size_t sec1_len, const char* curve_name) {
3✔
474
#if defined(BOTAN_HAS_ECDSA)
475
   if(key == nullptr || sec1 == nullptr || curve_name == nullptr) {
3✔
476
      return BOTAN_FFI_ERROR_NULL_POINTER;
477
   }
478
   *key = nullptr;
3✔
479

480
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
481
      std::unique_ptr<Botan::ECDSA_PublicKey> p_key;
3✔
482

483
      int rc = pubkey_load_ec_sec1(p_key, {sec1, sec1_len}, curve_name);
3✔
484
      if(rc == BOTAN_FFI_SUCCESS) {
3✔
485
         ffi_new_object(key, std::move(p_key));
3✔
486
      }
487

488
      return rc;
3✔
489
   });
6✔
490
#else
491
   BOTAN_UNUSED(key, sec1, sec1_len, curve_name);
492
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
493
#endif
494
}
495

496
int botan_privkey_load_ecdsa(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
2✔
497
#if defined(BOTAN_HAS_ECDSA)
498
   if(key == nullptr || curve_name == nullptr) {
2✔
499
      return BOTAN_FFI_ERROR_NULL_POINTER;
500
   }
501
   *key = nullptr;
2✔
502

503
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
504
      std::unique_ptr<Botan::ECDSA_PrivateKey> p_key;
2✔
505
      int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
2✔
506
      if(rc == BOTAN_FFI_SUCCESS) {
2✔
507
         ffi_new_object(key, std::move(p_key));
4✔
508
      }
509
      return rc;
2✔
510
   });
4✔
511
#else
512
   BOTAN_UNUSED(key, scalar, curve_name);
513
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
514
#endif
515
}
516

517
/* ElGamal specific operations */
518
int botan_privkey_create_elgamal(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) {
1✔
519
#if defined(BOTAN_HAS_ELGAMAL)
520
   if(key == nullptr || rng_obj == nullptr) {
1✔
521
      return BOTAN_FFI_ERROR_NULL_POINTER;
522
   }
523
   *key = nullptr;
1✔
524

525
   if(pbits < 1024 || qbits < 160) {
1✔
526
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
527
   }
528

529
   Botan::DL_Group::PrimeType prime_type =
1✔
530
      ((pbits - 1) == qbits) ? Botan::DL_Group::Strong : Botan::DL_Group::Prime_Subgroup;
1✔
531

532
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
533
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
1✔
534
      Botan::DL_Group group(rng, prime_type, pbits, qbits);
1✔
535
      auto elg = std::make_unique<Botan::ElGamal_PrivateKey>(rng, group);
1✔
536
      return ffi_new_object(key, std::move(elg));
1✔
537
   });
3✔
538
#else
539
   BOTAN_UNUSED(key, rng_obj, pbits, qbits);
540
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
541
#endif
542
}
543

544
int botan_pubkey_load_elgamal(botan_pubkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t y) {
2✔
545
#if defined(BOTAN_HAS_ELGAMAL)
546
   if(key == nullptr) {
2✔
547
      return BOTAN_FFI_ERROR_NULL_POINTER;
548
   }
549
   *key = nullptr;
2✔
550
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
551
      Botan::DL_Group group(safe_get(p), safe_get(g));
2✔
552
      auto elg = std::make_unique<Botan::ElGamal_PublicKey>(group, safe_get(y));
2✔
553
      return ffi_new_object(key, std::move(elg));
2✔
554
   });
6✔
555
#else
556
   BOTAN_UNUSED(key, p, g, y);
557
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
558
#endif
559
}
560

561
int botan_privkey_load_elgamal(botan_privkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t x) {
2✔
562
#if defined(BOTAN_HAS_ELGAMAL)
563
   if(key == nullptr) {
2✔
564
      return BOTAN_FFI_ERROR_NULL_POINTER;
565
   }
566
   *key = nullptr;
2✔
567
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
568
      Botan::DL_Group group(safe_get(p), safe_get(g));
2✔
569
      auto elg = std::make_unique<Botan::ElGamal_PrivateKey>(group, safe_get(x));
2✔
570
      return ffi_new_object(key, std::move(elg));
2✔
571
   });
6✔
572
#else
573
   BOTAN_UNUSED(key, p, g, x);
574
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
575
#endif
576
}
577

578
/* Diffie Hellman specific operations */
579

580
int botan_privkey_create_dh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) {
2✔
581
   return botan_privkey_create(key_obj, "DH", param_str, rng_obj);
2✔
582
}
583

584
int botan_privkey_load_dh(botan_privkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t x) {
1✔
585
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
586
   if(key == nullptr) {
1✔
587
      return BOTAN_FFI_ERROR_NULL_POINTER;
588
   }
589
   *key = nullptr;
1✔
590
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
591
      Botan::DL_Group group(safe_get(p), safe_get(g));
1✔
592
      auto dh = std::make_unique<Botan::DH_PrivateKey>(group, safe_get(x));
1✔
593
      return ffi_new_object(key, std::move(dh));
1✔
594
   });
3✔
595
#else
596
   BOTAN_UNUSED(key, p, g, x);
597
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
598
#endif
599
}
600

601
int botan_pubkey_load_dh(botan_pubkey_t* key, botan_mp_t p, botan_mp_t g, botan_mp_t y) {
1✔
602
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
603
   if(key == nullptr) {
1✔
604
      return BOTAN_FFI_ERROR_NULL_POINTER;
605
   }
606
   *key = nullptr;
1✔
607
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
608
      Botan::DL_Group group(safe_get(p), safe_get(g));
1✔
609
      auto dh = std::make_unique<Botan::DH_PublicKey>(group, safe_get(y));
1✔
610
      return ffi_new_object(key, std::move(dh));
1✔
611
   });
3✔
612
#else
613
   BOTAN_UNUSED(key, p, g, y);
614
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
615
#endif
616
}
617

618
/* ECDH + x25519/x448 specific operations */
619

620
int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) {
2✔
621
   if(key_obj == nullptr || param_str == nullptr) {
2✔
622
      return BOTAN_FFI_ERROR_NULL_POINTER;
623
   }
624
   *key_obj = nullptr;
2✔
625

626
   const std::string params(param_str);
2✔
627

628
   if(params == "X25519" || params == "x25519" || params == "curve25519") {
2✔
629
      return botan_privkey_create(key_obj, "X25519", "", rng_obj);
×
630
   }
631

632
   if(params == "X448" || params == "x448") {
2✔
633
      return botan_privkey_create(key_obj, "X448", "", rng_obj);
×
634
   }
635

636
   return botan_privkey_create(key_obj, "ECDH", param_str, rng_obj);
2✔
637
}
2✔
638

639
int botan_pubkey_load_ecdh(botan_pubkey_t* key,
1✔
640
                           const botan_mp_t public_x,
641
                           const botan_mp_t public_y,
642
                           const char* curve_name) {
643
#if defined(BOTAN_HAS_ECDH)
644
   if(key == nullptr || curve_name == nullptr) {
1✔
645
      return BOTAN_FFI_ERROR_NULL_POINTER;
646
   }
647
   *key = nullptr;
1✔
648
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
649
      std::unique_ptr<Botan::ECDH_PublicKey> p_key;
1✔
650
      int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
1✔
651

652
      if(rc == BOTAN_FFI_SUCCESS) {
1✔
653
         ffi_new_object(key, std::move(p_key));
1✔
654
      }
655
      return rc;
1✔
656
   });
2✔
657
#else
658
   BOTAN_UNUSED(key, public_x, public_y, curve_name);
659
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
660
#endif
661
}
662

663
int botan_pubkey_load_ecdh_sec1(botan_pubkey_t* key, const uint8_t sec1[], size_t sec1_len, const char* curve_name) {
7✔
664
#if defined(BOTAN_HAS_ECDH)
665
   if(key == nullptr || sec1 == nullptr || curve_name == nullptr) {
7✔
666
      return BOTAN_FFI_ERROR_NULL_POINTER;
667
   }
668
   *key = nullptr;
7✔
669

670
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
671
      std::unique_ptr<Botan::ECDH_PublicKey> p_key;
7✔
672

673
      int rc = pubkey_load_ec_sec1(p_key, {sec1, sec1_len}, curve_name);
7✔
674
      if(rc == BOTAN_FFI_SUCCESS) {
7✔
675
         ffi_new_object(key, std::move(p_key));
7✔
676
      }
677

678
      return rc;
7✔
679
   });
14✔
680
#else
681
   BOTAN_UNUSED(key, sec1, sec1_len, curve_name);
682
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
683
#endif
684
}
685

686
int botan_privkey_load_ecdh(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
4✔
687
#if defined(BOTAN_HAS_ECDH)
688
   if(key == nullptr || curve_name == nullptr) {
4✔
689
      return BOTAN_FFI_ERROR_NULL_POINTER;
690
   }
691
   *key = nullptr;
4✔
692
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
693
      std::unique_ptr<Botan::ECDH_PrivateKey> p_key;
4✔
694
      int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
4✔
695
      if(rc == BOTAN_FFI_SUCCESS) {
4✔
696
         ffi_new_object(key, std::move(p_key));
8✔
697
      }
698
      return rc;
4✔
699
   });
8✔
700
#else
701
   BOTAN_UNUSED(key, scalar, curve_name);
702
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
703
#endif
704
}
705

706
/* SM2 specific operations */
707

708
int botan_pubkey_sm2_compute_za(
2✔
709
   uint8_t out[], size_t* out_len, const char* ident, const char* hash_algo, const botan_pubkey_t key) {
710
   if(out == nullptr || out_len == nullptr || ident == nullptr || hash_algo == nullptr || key == nullptr) {
2✔
711
      return BOTAN_FFI_ERROR_NULL_POINTER;
712
   }
713

714
#if defined(BOTAN_HAS_SM2)
715
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
716
      const Botan::Public_Key& pub_key = safe_get(key);
2✔
717
      const Botan::EC_PublicKey* ec_key = dynamic_cast<const Botan::EC_PublicKey*>(&pub_key);
2✔
718

719
      if(ec_key == nullptr) {
2✔
720
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
721
      }
722

723
      if(ec_key->algo_name() != "SM2") {
2✔
724
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
725
      }
726

727
      const std::string ident_str(ident);
2✔
728
      std::unique_ptr<Botan::HashFunction> hash = Botan::HashFunction::create_or_throw(hash_algo);
2✔
729

730
      const auto& pt = ec_key->_public_ec_point();
2✔
731

732
      const auto za = Botan::sm2_compute_za(*hash, ident_str, ec_key->domain(), pt);
2✔
733

734
      return write_vec_output(out, out_len, za);
2✔
735
   });
6✔
736
#else
737
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
738
#endif
739
}
740

741
int botan_pubkey_load_sm2(botan_pubkey_t* key,
3✔
742
                          const botan_mp_t public_x,
743
                          const botan_mp_t public_y,
744
                          const char* curve_name) {
745
#if defined(BOTAN_HAS_SM2)
746
   if(key == nullptr || curve_name == nullptr) {
3✔
747
      return BOTAN_FFI_ERROR_NULL_POINTER;
748
   }
749
   *key = nullptr;
3✔
750

751
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
752
      std::unique_ptr<Botan::SM2_PublicKey> p_key;
3✔
753
      if(pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name) == 0) {
3✔
754
         return ffi_new_object(key, std::move(p_key));
3✔
755
      } else {
756
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
757
      }
758
   });
6✔
759
#else
760
   BOTAN_UNUSED(key, public_x, public_y, curve_name);
761
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
762
#endif
763
}
764

765
int botan_pubkey_load_sm2_sec1(botan_pubkey_t* key, const uint8_t sec1[], size_t sec1_len, const char* curve_name) {
4✔
766
#if defined(BOTAN_HAS_SM2)
767
   if(key == nullptr || sec1 == nullptr || curve_name == nullptr) {
4✔
768
      return BOTAN_FFI_ERROR_NULL_POINTER;
769
   }
770
   *key = nullptr;
4✔
771

772
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
773
      std::unique_ptr<Botan::SM2_PublicKey> p_key;
4✔
774

775
      int rc = pubkey_load_ec_sec1(p_key, {sec1, sec1_len}, curve_name);
4✔
776
      if(rc == BOTAN_FFI_SUCCESS) {
4✔
777
         ffi_new_object(key, std::move(p_key));
4✔
778
      }
779

780
      return rc;
4✔
781
   });
8✔
782
#else
783
   BOTAN_UNUSED(key, sec1, sec1_len, curve_name);
784
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
785
#endif
786
}
787

788
int botan_privkey_load_sm2(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
3✔
789
#if defined(BOTAN_HAS_SM2)
790
   if(key == nullptr || curve_name == nullptr) {
3✔
791
      return BOTAN_FFI_ERROR_NULL_POINTER;
792
   }
793
   *key = nullptr;
3✔
794

795
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
796
      std::unique_ptr<Botan::SM2_PrivateKey> p_key;
3✔
797
      int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
3✔
798

799
      if(rc == BOTAN_FFI_SUCCESS) {
3✔
800
         ffi_new_object(key, std::move(p_key));
6✔
801
      }
802
      return rc;
3✔
803
   });
6✔
804
#else
805
   BOTAN_UNUSED(key, scalar, curve_name);
806
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
807
#endif
808
}
809

810
int botan_pubkey_load_sm2_enc(botan_pubkey_t* key,
1✔
811
                              const botan_mp_t public_x,
812
                              const botan_mp_t public_y,
813
                              const char* curve_name) {
814
   return botan_pubkey_load_sm2(key, public_x, public_y, curve_name);
1✔
815
}
816

817
int botan_privkey_load_sm2_enc(botan_privkey_t* key, const botan_mp_t scalar, const char* curve_name) {
1✔
818
   return botan_privkey_load_sm2(key, scalar, curve_name);
1✔
819
}
820

821
/* Ed25519 specific operations */
822

823
int botan_privkey_load_ed25519(botan_privkey_t* key, const uint8_t privkey[32]) {
1✔
824
#if defined(BOTAN_HAS_ED25519)
825
   if(key == nullptr) {
1✔
826
      return BOTAN_FFI_ERROR_NULL_POINTER;
827
   }
828
   *key = nullptr;
1✔
829
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
830
      auto ed25519 =
1✔
831
         std::make_unique<Botan::Ed25519_PrivateKey>(Botan::Ed25519_PrivateKey::from_seed(std::span{privkey, 32}));
2✔
832
      return ffi_new_object(key, std::move(ed25519));
2✔
833
   });
2✔
834
#else
835
   BOTAN_UNUSED(key, privkey);
836
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
837
#endif
838
}
839

840
int botan_pubkey_load_ed25519(botan_pubkey_t* key, const uint8_t pubkey[32]) {
1✔
841
#if defined(BOTAN_HAS_ED25519)
842
   if(key == nullptr) {
1✔
843
      return BOTAN_FFI_ERROR_NULL_POINTER;
844
   }
845
   *key = nullptr;
1✔
846
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
847
      const std::vector<uint8_t> pubkey_vec(pubkey, pubkey + 32);
1✔
848
      auto ed25519 = std::make_unique<Botan::Ed25519_PublicKey>(pubkey_vec);
1✔
849
      return ffi_new_object(key, std::move(ed25519));
1✔
850
   });
3✔
851
#else
852
   BOTAN_UNUSED(key, pubkey);
853
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
854
#endif
855
}
856

857
int botan_privkey_ed25519_get_privkey(botan_privkey_t key, uint8_t output[64]) {
1✔
858
#if defined(BOTAN_HAS_ED25519)
859
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
860
      if(auto ed = dynamic_cast<const Botan::Ed25519_PrivateKey*>(&k)) {
861
         const auto ed_key = ed->raw_private_key_bits();
862
         if(ed_key.size() != 64) {
863
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
864
         }
865
         Botan::copy_mem(output, ed_key.data(), ed_key.size());
866
         return BOTAN_FFI_SUCCESS;
867
      } else {
868
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
869
      }
870
   });
871
#else
872
   BOTAN_UNUSED(key, output);
873
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
874
#endif
875
}
876

877
int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key, uint8_t output[32]) {
1✔
878
#if defined(BOTAN_HAS_ED25519)
879
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
2✔
880
      if(auto ed = dynamic_cast<const Botan::Ed25519_PublicKey*>(&k)) {
881
         const std::vector<uint8_t>& ed_key = ed->get_public_key();
882
         if(ed_key.size() != 32) {
883
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
884
         }
885
         Botan::copy_mem(output, ed_key.data(), ed_key.size());
886
         return BOTAN_FFI_SUCCESS;
887
      } else {
888
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
889
      }
890
   });
891
#else
892
   BOTAN_UNUSED(key, output);
893
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
894
#endif
895
}
896

897
/* Ed448 specific operations */
898

899
int botan_privkey_load_ed448(botan_privkey_t* key, const uint8_t privkey[57]) {
1✔
900
#if defined(BOTAN_HAS_ED448)
901
   if(key == nullptr) {
1✔
902
      return BOTAN_FFI_ERROR_NULL_POINTER;
903
   }
904
   *key = nullptr;
1✔
905
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
906
      auto ed448 = std::make_unique<Botan::Ed448_PrivateKey>(std::span(privkey, 57));
1✔
907
      return ffi_new_object(key, std::move(ed448));
2✔
908
   });
2✔
909
#else
910
   BOTAN_UNUSED(key, privkey);
911
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
912
#endif
913
}
914

915
int botan_pubkey_load_ed448(botan_pubkey_t* key, const uint8_t pubkey[57]) {
1✔
916
#if defined(BOTAN_HAS_ED448)
917
   if(key == nullptr) {
1✔
918
      return BOTAN_FFI_ERROR_NULL_POINTER;
919
   }
920
   *key = nullptr;
1✔
921
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
922
      auto ed448 = std::make_unique<Botan::Ed448_PublicKey>(std::span(pubkey, 57));
1✔
923
      return ffi_new_object(key, std::move(ed448));
1✔
924
   });
2✔
925
#else
926
   BOTAN_UNUSED(key, pubkey);
927
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
928
#endif
929
}
930

931
int botan_privkey_ed448_get_privkey(botan_privkey_t key, uint8_t output[57]) {
1✔
932
#if defined(BOTAN_HAS_ED448)
933
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
934
      if(auto ed = dynamic_cast<const Botan::Ed448_PrivateKey*>(&k)) {
935
         const auto ed_key = ed->raw_private_key_bits();
936
         Botan::copy_mem(std::span(output, 57), ed_key);
937
         return BOTAN_FFI_SUCCESS;
938
      } else {
939
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
940
      }
941
   });
942
#else
943
   BOTAN_UNUSED(key, output);
944
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
945
#endif
946
}
947

948
int botan_pubkey_ed448_get_pubkey(botan_pubkey_t key, uint8_t output[57]) {
1✔
949
#if defined(BOTAN_HAS_ED448)
950
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
3✔
951
      if(auto ed = dynamic_cast<const Botan::Ed448_PublicKey*>(&k)) {
952
         const auto ed_key = ed->public_key_bits();
953
         Botan::copy_mem(std::span(output, 57), ed_key);
954
         return BOTAN_FFI_SUCCESS;
955
      } else {
956
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
957
      }
958
   });
959
#else
960
   BOTAN_UNUSED(key, output);
961
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
962
#endif
963
}
964

965
/* X25519 specific operations */
966

967
int botan_privkey_load_x25519(botan_privkey_t* key, const uint8_t privkey[32]) {
1✔
968
#if defined(BOTAN_HAS_X25519)
969
   if(key == nullptr) {
1✔
970
      return BOTAN_FFI_ERROR_NULL_POINTER;
971
   }
972
   *key = nullptr;
1✔
973
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
974
      auto x25519 = std::make_unique<Botan::X25519_PrivateKey>(std::span{privkey, 32});
1✔
975
      return ffi_new_object(key, std::move(x25519));
2✔
976
   });
2✔
977
#else
978
   BOTAN_UNUSED(key, privkey);
979
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
980
#endif
981
}
982

983
int botan_pubkey_load_x25519(botan_pubkey_t* key, const uint8_t pubkey[32]) {
1✔
984
#if defined(BOTAN_HAS_X25519)
985
   if(key == nullptr) {
1✔
986
      return BOTAN_FFI_ERROR_NULL_POINTER;
987
   }
988
   *key = nullptr;
1✔
989
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
990
      auto x25519 = std::make_unique<Botan::X25519_PublicKey>(std::span{pubkey, 32});
1✔
991
      return ffi_new_object(key, std::move(x25519));
1✔
992
   });
2✔
993
#else
994
   BOTAN_UNUSED(key, pubkey);
995
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
996
#endif
997
}
998

999
int botan_privkey_x25519_get_privkey(botan_privkey_t key, uint8_t output[32]) {
1✔
1000
#if defined(BOTAN_HAS_X25519)
1001
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
1002
      if(auto x25519 = dynamic_cast<const Botan::X25519_PrivateKey*>(&k)) {
1003
         const auto x25519_key = x25519->raw_private_key_bits();
1004
         if(x25519_key.size() != 32) {
1005
            return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
1006
         }
1007
         Botan::copy_mem(output, x25519_key.data(), x25519_key.size());
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_x25519_get_pubkey(botan_pubkey_t key, uint8_t output[32]) {
2✔
1020
#if defined(BOTAN_HAS_X25519)
1021
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
6✔
1022
      if(auto x25519 = dynamic_cast<const Botan::X25519_PublicKey*>(&k)) {
1023
         Botan::copy_mem(std::span{output, 32}, x25519->raw_public_key_bits());
1024
         return BOTAN_FFI_SUCCESS;
1025
      } else {
1026
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1027
      }
1028
   });
1029
#else
1030
   BOTAN_UNUSED(key, output);
1031
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1032
#endif
1033
}
1034

1035
/* X448 specific operations */
1036

1037
int botan_privkey_load_x448(botan_privkey_t* key, const uint8_t privkey[56]) {
1✔
1038
#if defined(BOTAN_HAS_X448)
1039
   if(key == nullptr) {
1✔
1040
      return BOTAN_FFI_ERROR_NULL_POINTER;
1041
   }
1042
   *key = nullptr;
1✔
1043
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1044
      auto x448 = std::make_unique<Botan::X448_PrivateKey>(std::span{privkey, 56});
1✔
1045
      return ffi_new_object(key, std::move(x448));
2✔
1046
   });
2✔
1047
#else
1048
   BOTAN_UNUSED(key, privkey);
1049
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1050
#endif
1051
}
1052

1053
int botan_pubkey_load_x448(botan_pubkey_t* key, const uint8_t pubkey[56]) {
1✔
1054
#if defined(BOTAN_HAS_X448)
1055
   if(key == nullptr) {
1✔
1056
      return BOTAN_FFI_ERROR_NULL_POINTER;
1057
   }
1058
   *key = nullptr;
1✔
1059
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1060
      auto x448 = std::make_unique<Botan::X448_PublicKey>(std::span{pubkey, 56});
1✔
1061
      return ffi_new_object(key, std::move(x448));
1✔
1062
   });
2✔
1063
#else
1064
   BOTAN_UNUSED(key, pubkey);
1065
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1066
#endif
1067
}
1068

1069
int botan_privkey_x448_get_privkey(botan_privkey_t key, uint8_t output[56]) {
1✔
1070
#if defined(BOTAN_HAS_X448)
1071
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
1072
      if(auto x448 = dynamic_cast<const Botan::X448_PrivateKey*>(&k)) {
1073
         const auto x448_key = x448->raw_private_key_bits();
1074
         Botan::copy_mem(std::span{output, 56}, x448_key);
1075
         return BOTAN_FFI_SUCCESS;
1076
      } else {
1077
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1078
      }
1079
   });
1080
#else
1081
   BOTAN_UNUSED(key, output);
1082
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1083
#endif
1084
}
1085

1086
int botan_pubkey_x448_get_pubkey(botan_pubkey_t key, uint8_t output[56]) {
2✔
1087
#if defined(BOTAN_HAS_X448)
1088
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
6✔
1089
      if(auto x448 = dynamic_cast<const Botan::X448_PublicKey*>(&k)) {
1090
         Botan::copy_mem(std::span{output, 56}, x448->raw_public_key_bits());
1091
         return BOTAN_FFI_SUCCESS;
1092
      } else {
1093
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1094
      }
1095
   });
1096
#else
1097
   BOTAN_UNUSED(key, output);
1098
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1099
#endif
1100
}
1101

1102
/*
1103
* Algorithm specific key operations: Kyber
1104
*/
1105

1106
int botan_privkey_load_kyber(botan_privkey_t* key, const uint8_t privkey[], size_t key_len) {
4✔
1107
#if defined(BOTAN_HAS_KYBER)
1108
   if(key == nullptr) {
4✔
1109
      return BOTAN_FFI_ERROR_NULL_POINTER;
1110
   }
1111
   *key = nullptr;
4✔
1112

1113
   const auto mode = [](size_t len) -> std::optional<Botan::KyberMode> {
12✔
1114
      if(len == 1632) {
4✔
1115
         return Botan::KyberMode::Kyber512_R3;
1✔
1116
      } else if(len == 2400) {
3✔
1117
         return Botan::KyberMode::Kyber768_R3;
2✔
1118
      } else if(len == 3168) {
1✔
1119
         return Botan::KyberMode::Kyber1024_R3;
1✔
1120
      } else {
1121
         return {};
×
1122
      }
1123
   }(key_len);
4✔
1124

1125
   if(mode.has_value()) {
4✔
1126
      return ffi_guard_thunk(__func__, [=]() -> int {
4✔
1127
         auto kyber = std::make_unique<Botan::Kyber_PrivateKey>(std::span{privkey, key_len}, *mode);
4✔
1128
         return ffi_new_object(key, std::move(kyber));
8✔
1129
      });
4✔
1130
   } else {
1131
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1132
   }
1133
#else
1134
   BOTAN_UNUSED(key, key_len, privkey);
1135
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1136
#endif
1137
}
1138

1139
int botan_pubkey_load_kyber(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len) {
4✔
1140
#if defined(BOTAN_HAS_KYBER)
1141
   if(key == nullptr) {
4✔
1142
      return BOTAN_FFI_ERROR_NULL_POINTER;
1143
   }
1144
   *key = nullptr;
4✔
1145

1146
   const auto mode = [](size_t len) -> std::optional<Botan::KyberMode> {
12✔
1147
      if(len == 800) {
4✔
1148
         return Botan::KyberMode::Kyber512_R3;
1✔
1149
      } else if(len == 1184) {
3✔
1150
         return Botan::KyberMode::Kyber768_R3;
2✔
1151
      } else if(len == 1568) {
1✔
1152
         return Botan::KyberMode::Kyber1024_R3;
1✔
1153
      } else {
1154
         return {};
×
1155
      }
1156
   }(key_len);
4✔
1157

1158
   if(mode.has_value()) {
4✔
1159
      auto kyber = std::make_unique<Botan::Kyber_PublicKey>(std::span{pubkey, key_len}, *mode);
4✔
1160
      return ffi_new_object(key, std::move(kyber));
4✔
1161
   } else {
4✔
1162
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1163
   }
1164
#else
1165
   BOTAN_UNUSED(key, pubkey, key_len);
1166
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1167
#endif
1168
}
1169

1170
int botan_privkey_view_kyber_raw_key(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
4✔
1171
#if defined(BOTAN_HAS_KYBER)
1172
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
16✔
1173
      if(auto kyber = dynamic_cast<const Botan::Kyber_PrivateKey*>(&k)) {
1174
         return invoke_view_callback(view, ctx, kyber->raw_private_key_bits());
1175
      } else {
1176
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1177
      }
1178
   });
1179
#else
1180
   BOTAN_UNUSED(key, ctx, view);
1181
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1182
#endif
1183
}
1184

1185
int botan_pubkey_view_kyber_raw_key(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
8✔
1186
#if defined(BOTAN_HAS_KYBER)
1187
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
32✔
1188
      if(auto kyber = dynamic_cast<const Botan::Kyber_PublicKey*>(&k)) {
1189
         return invoke_view_callback(view, ctx, kyber->public_key_bits());
1190
      } else {
1191
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1192
      }
1193
   });
1194
#else
1195
   BOTAN_UNUSED(key, ctx, view);
1196
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1197
#endif
1198
}
1199

1200
/*
1201
* Algorithm specific key operations: ML-KEM
1202
*/
1203

1204
int botan_privkey_load_ml_kem(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* mlkem_mode) {
4✔
1205
#if defined(BOTAN_HAS_ML_KEM)
1206
   if(key == nullptr || privkey == nullptr || mlkem_mode == nullptr) {
4✔
1207
      return BOTAN_FFI_ERROR_NULL_POINTER;
1208
   }
1209

1210
   *key = nullptr;
4✔
1211

1212
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
1213
      auto mode = Botan::ML_KEM_Mode(mlkem_mode);
4✔
1214
      if(!mode.is_ml_kem()) {
4✔
1215
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1216
      }
1217

1218
      auto mlkem_key = std::make_unique<Botan::ML_KEM_PrivateKey>(std::span{privkey, key_len}, mode);
4✔
1219
      return ffi_new_object(key, std::move(mlkem_key));
4✔
1220
   });
8✔
1221
#else
1222
   BOTAN_UNUSED(key, key_len, privkey, mlkem_mode);
1223
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1224
#endif
1225
}
1226

1227
int botan_pubkey_load_ml_kem(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* mlkem_mode) {
4✔
1228
#if defined(BOTAN_HAS_ML_KEM)
1229
   if(key == nullptr || pubkey == nullptr || mlkem_mode == nullptr) {
4✔
1230
      return BOTAN_FFI_ERROR_NULL_POINTER;
1231
   }
1232

1233
   *key = nullptr;
4✔
1234

1235
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
1236
      auto mode = Botan::ML_KEM_Mode(mlkem_mode);
4✔
1237
      if(!mode.is_ml_kem()) {
4✔
1238
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1239
      }
1240

1241
      auto mlkem_key = std::make_unique<Botan::ML_KEM_PublicKey>(std::span{pubkey, key_len}, mode.mode());
4✔
1242
      return ffi_new_object(key, std::move(mlkem_key));
4✔
1243
   });
8✔
1244
#else
1245
   BOTAN_UNUSED(key, key_len, pubkey, mlkem_mode);
1246
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1247
#endif
1248
}
1249

1250
/*
1251
* Algorithm specific key operations: ML-DSA
1252
*/
1253

1254
int botan_privkey_load_ml_dsa(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* mldsa_mode) {
4✔
1255
#if defined(BOTAN_HAS_ML_DSA)
1256
   if(key == nullptr || privkey == nullptr || mldsa_mode == nullptr) {
4✔
1257
      return BOTAN_FFI_ERROR_NULL_POINTER;
1258
   }
1259

1260
   *key = nullptr;
4✔
1261

1262
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
1263
      auto mode = Botan::ML_DSA_Mode(mldsa_mode);
4✔
1264
      if(!mode.is_ml_dsa()) {
4✔
1265
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1266
      }
1267

1268
      auto mldsa_key = std::make_unique<Botan::ML_DSA_PrivateKey>(std::span{privkey, key_len}, mode);
4✔
1269
      return ffi_new_object(key, std::move(mldsa_key));
4✔
1270
   });
8✔
1271
#else
1272
   BOTAN_UNUSED(key, key_len, privkey, mldsa_mode);
1273
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1274
#endif
1275
}
1276

1277
int botan_pubkey_load_ml_dsa(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* mldsa_mode) {
4✔
1278
#if defined(BOTAN_HAS_ML_DSA)
1279
   if(key == nullptr || pubkey == nullptr || mldsa_mode == nullptr) {
4✔
1280
      return BOTAN_FFI_ERROR_NULL_POINTER;
1281
   }
1282

1283
   *key = nullptr;
4✔
1284

1285
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
1286
      auto mode = Botan::ML_DSA_Mode(mldsa_mode);
4✔
1287
      if(!mode.is_ml_dsa()) {
4✔
1288
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1289
      }
1290

1291
      auto mldsa_key = std::make_unique<Botan::ML_DSA_PublicKey>(std::span{pubkey, key_len}, mode);
4✔
1292
      return ffi_new_object(key, std::move(mldsa_key));
4✔
1293
   });
8✔
1294
#else
1295
   BOTAN_UNUSED(key, key_len, pubkey, mldsa_mode);
1296
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1297
#endif
1298
}
1299

1300
/*
1301
* Algorithm specific key operations: SLH-DSA
1302
*/
1303

1304
int botan_privkey_load_slh_dsa(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* slhdsa_mode) {
13✔
1305
#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
1306
   if(key == nullptr || privkey == nullptr || slhdsa_mode == nullptr) {
13✔
1307
      return BOTAN_FFI_ERROR_NULL_POINTER;
1308
   }
1309

1310
   *key = nullptr;
13✔
1311

1312
   return ffi_guard_thunk(__func__, [=]() -> int {
13✔
1313
      auto mode = Botan::SLH_DSA_Parameters::create(slhdsa_mode);
13✔
1314
      if(!mode.is_slh_dsa()) {
13✔
1315
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1316
      }
1317

1318
      auto slhdsa_key = std::make_unique<Botan::SLH_DSA_PrivateKey>(std::span{privkey, key_len}, mode);
13✔
1319
      return ffi_new_object(key, std::move(slhdsa_key));
13✔
1320
   });
26✔
1321
#else
1322
   BOTAN_UNUSED(key, key_len, privkey, slhdsa_mode);
1323
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1324
#endif
1325
}
1326

1327
int botan_pubkey_load_slh_dsa(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* slhdsa_mode) {
13✔
1328
#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
1329
   if(key == nullptr || pubkey == nullptr || slhdsa_mode == nullptr) {
13✔
1330
      return BOTAN_FFI_ERROR_NULL_POINTER;
1331
   }
1332

1333
   *key = nullptr;
13✔
1334

1335
   return ffi_guard_thunk(__func__, [=]() -> int {
13✔
1336
      auto mode = Botan::SLH_DSA_Parameters::create(slhdsa_mode);
13✔
1337
      if(!mode.is_slh_dsa()) {
13✔
1338
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1339
      }
1340

1341
      auto mldsa_key = std::make_unique<Botan::SLH_DSA_PublicKey>(std::span{pubkey, key_len}, mode);
13✔
1342
      return ffi_new_object(key, std::move(mldsa_key));
13✔
1343
   });
26✔
1344
#else
1345
   BOTAN_UNUSED(key, key_len, pubkey, slhdsa_mode);
1346
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1347
#endif
1348
}
1349

1350
/*
1351
* Algorithm specific key operations: FrodoKEM
1352
*/
1353

1354
int botan_privkey_load_frodokem(botan_privkey_t* key, const uint8_t privkey[], size_t key_len, const char* frodo_mode) {
13✔
1355
#if defined(BOTAN_HAS_FRODOKEM)
1356
   if(key == nullptr || privkey == nullptr || frodo_mode == nullptr) {
13✔
1357
      return BOTAN_FFI_ERROR_NULL_POINTER;
1358
   }
1359

1360
   *key = nullptr;
13✔
1361

1362
   return ffi_guard_thunk(__func__, [=]() -> int {
13✔
1363
      const auto mode = Botan::FrodoKEMMode(frodo_mode);
13✔
1364
      auto frodo_key = std::make_unique<Botan::FrodoKEM_PrivateKey>(std::span{privkey, key_len}, mode);
13✔
1365
      return ffi_new_object(key, std::move(frodo_key));
26✔
1366
   });
26✔
1367
#else
1368
   BOTAN_UNUSED(key, privkey, key_len, frodo_mode);
1369
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1370
#endif
1371
}
1372

1373
int botan_pubkey_load_frodokem(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* frodo_mode) {
13✔
1374
#if defined(BOTAN_HAS_FRODOKEM)
1375
   if(key == nullptr || pubkey == nullptr || frodo_mode == nullptr) {
13✔
1376
      return BOTAN_FFI_ERROR_NULL_POINTER;
1377
   }
1378

1379
   *key = nullptr;
13✔
1380

1381
   return ffi_guard_thunk(__func__, [=]() -> int {
13✔
1382
      const auto mode = Botan::FrodoKEMMode(frodo_mode);
13✔
1383
      auto frodo_key = std::make_unique<Botan::FrodoKEM_PublicKey>(std::span{pubkey, key_len}, mode);
13✔
1384
      return ffi_new_object(key, std::move(frodo_key));
13✔
1385
   });
26✔
1386
#else
1387
   BOTAN_UNUSED(key, pubkey, key_len, frodo_mode);
1388
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1389
#endif
1390
}
1391

1392
/*
1393
* Algorithm specific key operations : Classic McEliece
1394
*/
1395

1396
int botan_privkey_load_classic_mceliece(botan_privkey_t* key,
17✔
1397
                                        const uint8_t privkey[],
1398
                                        size_t key_len,
1399
                                        const char* cmce_mode) {
1400
#if defined(BOTAN_HAS_CLASSICMCELIECE)
1401
   if(key == nullptr || privkey == nullptr || cmce_mode == nullptr) {
17✔
1402
      return BOTAN_FFI_ERROR_NULL_POINTER;
1403
   }
1404

1405
   *key = nullptr;
17✔
1406

1407
   return ffi_guard_thunk(__func__, [=]() -> int {
17✔
1408
      const auto mode = Botan::Classic_McEliece_Parameter_Set::from_string(cmce_mode);
17✔
1409
      auto cmce_key = std::make_unique<Botan::Classic_McEliece_PrivateKey>(std::span{privkey, key_len}, mode);
17✔
1410
      return ffi_new_object(key, std::move(cmce_key));
34✔
1411
   });
34✔
1412
#else
1413
   BOTAN_UNUSED(key, privkey, key_len, cmce_mode);
1414
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1415
#endif
1416
}
1417

1418
int botan_pubkey_load_classic_mceliece(botan_pubkey_t* key,
17✔
1419
                                       const uint8_t pubkey[],
1420
                                       size_t key_len,
1421
                                       const char* cmce_mode) {
1422
#if defined(BOTAN_HAS_CLASSICMCELIECE)
1423
   if(key == nullptr || pubkey == nullptr || cmce_mode == nullptr) {
17✔
1424
      return BOTAN_FFI_ERROR_NULL_POINTER;
1425
   }
1426

1427
   *key = nullptr;
17✔
1428

1429
   return ffi_guard_thunk(__func__, [=]() -> int {
17✔
1430
      const auto mode = Botan::Classic_McEliece_Parameter_Set::from_string(cmce_mode);
17✔
1431
      auto cmce_key = std::make_unique<Botan::Classic_McEliece_PublicKey>(std::span{pubkey, key_len}, mode);
17✔
1432
      return ffi_new_object(key, std::move(cmce_key));
17✔
1433
   });
34✔
1434
#else
1435
   BOTAN_UNUSED(key, pubkey, key_len, cmce_mode);
1436
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1437
#endif
1438
}
1439

1440
int botan_pubkey_view_ec_public_point(const botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
6✔
1441
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
1442
   return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
24✔
1443
      if(auto ecc = dynamic_cast<const Botan::EC_PublicKey*>(&k)) {
1444
         auto pt = ecc->_public_ec_point().serialize_uncompressed();
1445
         return invoke_view_callback(view, ctx, pt);
1446
      } else {
1447
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
1448
      }
1449
   });
1450
#else
1451
   BOTAN_UNUSED(key, view, ctx);
1452
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1453
#endif
1454
}
1455

1456
// NOLINTEND(misc-misplaced-const)
1457

1458
int botan_privkey_create_mceliece(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n, size_t t) {
1✔
1459
   const std::string mce_params = std::to_string(n) + "," + std::to_string(t);
3✔
1460
   return botan_privkey_create(key_obj, "McEliece", mce_params.c_str(), rng_obj);
1✔
1461
}
1✔
1462

1463
int botan_mceies_decrypt(botan_privkey_t mce_key_obj,
×
1464
                         const char* aead,
1465
                         const uint8_t ct[],
1466
                         size_t ct_len,
1467
                         const uint8_t ad[],
1468
                         size_t ad_len,
1469
                         uint8_t out[],
1470
                         size_t* out_len) {
1471
   BOTAN_UNUSED(mce_key_obj, aead, ct, ct_len, ad, ad_len, out, out_len);
×
1472
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
×
1473
}
1474

1475
int botan_mceies_encrypt(botan_pubkey_t mce_key_obj,
×
1476
                         botan_rng_t rng_obj,
1477
                         const char* aead,
1478
                         const uint8_t pt[],
1479
                         size_t pt_len,
1480
                         const uint8_t ad[],
1481
                         size_t ad_len,
1482
                         uint8_t out[],
1483
                         size_t* out_len) {
1484
   BOTAN_UNUSED(mce_key_obj, rng_obj, aead, pt, pt_len, ad, ad_len, out, out_len);
×
1485
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
×
1486
}
1487
}
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