Botan 3.13.0
Crypto and TLS for C&
ffi_spake2p.cpp
Go to the documentation of this file.
1/*
2* (C) 2026 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/ffi.h>
8
9#include <botan/assert.h>
10#include <botan/internal/ffi_rng.h>
11#include <botan/internal/ffi_util.h>
12
13#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
14 #include <botan/rng.h>
15 #include <botan/spake2p.h>
16 #include <botan/internal/ffi_ec.h>
17#endif
18
19#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
20
21namespace {
22
23Botan::SPAKE2p::SystemParameters spake2p_params_from_name(const char* ciphersuite) {
25
26 const std::string_view name(ciphersuite);
27
28 if(name == "P256-SHA256") {
29 return SystemParameters::rfc9383_p256_sha256();
30 } else if(name == "P256-SHA512") {
31 return SystemParameters::rfc9383_p256_sha512();
32 } else if(name == "P384-SHA256") {
33 return SystemParameters::rfc9383_p384_sha256();
34 } else if(name == "P384-SHA512") {
35 return SystemParameters::rfc9383_p384_sha512();
36 } else if(name == "P521-SHA512") {
37 return SystemParameters::rfc9383_p521_sha512();
38 } else {
39 throw Botan::Invalid_Argument("Unknown SPAKE2+ ciphersuite");
40 }
41}
42
43std::span<const uint8_t> spake2p_opt_span(const uint8_t* ptr, size_t len) {
44 if(ptr == nullptr && len > 0) {
45 throw Botan_FFI::FFI_Error("Null pointer with non-zero length", BOTAN_FFI_ERROR_NULL_POINTER);
46 }
47 return {ptr, len};
48}
49
50} // namespace
51
52#endif
53
54extern "C" {
55
56using namespace Botan_FFI;
57
58#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
59BOTAN_FFI_DECLARE_STRUCT(botan_spake2p_params_struct, Botan::SPAKE2p::SystemParameters, 0x2E1B4A96);
60BOTAN_FFI_DECLARE_STRUCT(botan_spake2p_prover_struct, Botan::SPAKE2p::ProverContext, 0x9F337C29);
61BOTAN_FFI_DECLARE_STRUCT(botan_spake2p_verifier_struct, Botan::SPAKE2p::VerifierContext, 0xD70A9E13);
62#else
63BOTAN_FFI_DECLARE_DUMMY_STRUCT(botan_spake2p_params_struct, 0x2E1B4A96);
64BOTAN_FFI_DECLARE_DUMMY_STRUCT(botan_spake2p_prover_struct, 0x9F337C29);
65BOTAN_FFI_DECLARE_DUMMY_STRUCT(botan_spake2p_verifier_struct, 0xD70A9E13);
66#endif
67
68int botan_spake2p_params_init(botan_spake2p_params_t* params, const char* ciphersuite) {
69 if(any_null_pointers(params, ciphersuite)) {
71 }
72
73#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
74 return ffi_guard_thunk(__func__, [=]() -> int {
75 *params = nullptr;
76 auto p = std::make_unique<Botan::SPAKE2p::SystemParameters>(spake2p_params_from_name(ciphersuite));
77 return ffi_new_object(params, std::move(p));
78 });
79#else
81#endif
82}
83
85 botan_spake2p_params_t* params, botan_ec_group_t group, const uint8_t seed[], size_t seed_len, const char* hash_fn) {
86 if(any_null_pointers(params, group, hash_fn)) {
88 }
89
90#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
91 return ffi_guard_thunk(__func__, [=]() -> int {
92 auto p = std::make_unique<Botan::SPAKE2p::SystemParameters>(
93 Botan::SPAKE2p::SystemParameters::custom(safe_get(group), spake2p_opt_span(seed, seed_len), hash_fn));
94 return ffi_new_object(params, std::move(p));
95 });
96#else
97 BOTAN_UNUSED(params, group, seed, seed_len, hash_fn);
99#endif
100}
101
105
107#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
108 return BOTAN_FFI_VISIT(params, [=](const auto& p) -> int {
109 if(share_size == nullptr) {
111 }
112 *share_size = p.share_size();
113 return BOTAN_FFI_SUCCESS;
114 });
115#else
116 BOTAN_UNUSED(params, share_size);
118#endif
119}
120
122 if(any_null_pointers(params, confirmation_size)) {
124 }
125
126#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
127 return BOTAN_FFI_VISIT(params, [=](const auto& p) -> int {
128 *confirmation_size = p.confirmation_size();
129 return BOTAN_FFI_SUCCESS;
130 });
131#else
132 BOTAN_UNUSED(params, confirmation_size);
134#endif
135}
136
138 const char* password,
139 const uint8_t prover_id[],
140 size_t prover_id_len,
141 const uint8_t verifier_id[],
142 size_t verifier_id_len,
143 const uint8_t salt[],
144 size_t salt_len,
145 botan_view_ctx ctx,
146 botan_view_bin_fn view) {
147 if(any_null_pointers(params, password)) {
149 }
150
151#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
152 return ffi_guard_thunk(__func__, [=]() -> int {
154 password,
155 spake2p_opt_span(prover_id, prover_id_len),
156 spake2p_opt_span(verifier_id, verifier_id_len),
157 spake2p_opt_span(salt, salt_len));
158 return invoke_view_callback(view, ctx, sec.serialize());
159 });
160#else
161 BOTAN_UNUSED(params, password, prover_id, prover_id_len, verifier_id, verifier_id_len);
162 BOTAN_UNUSED(salt, salt_len, ctx, view);
164#endif
165}
166
168 botan_rng_t rng,
169 const uint8_t secret[],
170 size_t secret_len,
171 botan_view_ctx ctx,
172 botan_view_bin_fn view) {
173#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
174 if(any_null_pointers(params, rng, secret)) {
176 }
177
178 return ffi_guard_thunk(__func__, [=]() -> int {
179 const auto sec = Botan::SPAKE2p::ProverSecret::deserialize(safe_get(params), {secret, secret_len});
180 return invoke_view_callback(view, ctx, sec.registration_record(safe_get(rng)).serialize());
181 });
182#else
183 BOTAN_UNUSED(params, rng, secret, secret_len, ctx, view);
185#endif
186}
187
190 const uint8_t secret[],
191 size_t secret_len,
192 const uint8_t prover_id[],
193 size_t prover_id_len,
194 const uint8_t verifier_id[],
195 size_t verifier_id_len,
196 const uint8_t context[],
197 size_t context_len) {
198#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
199 if(any_null_pointers(prover, params, secret)) {
201 }
202
203 return ffi_guard_thunk(__func__, [=]() -> int {
204 *prover = nullptr;
205 const auto& p = safe_get(params);
206 const auto sec = Botan::SPAKE2p::ProverSecret::deserialize(p, {secret, secret_len});
207 auto ctx = std::make_unique<Botan::SPAKE2p::ProverContext>(p,
208 sec,
209 spake2p_opt_span(prover_id, prover_id_len),
210 spake2p_opt_span(verifier_id, verifier_id_len),
211 spake2p_opt_span(context, context_len));
212 return ffi_new_object(prover, std::move(ctx));
213 });
214#else
215 BOTAN_UNUSED(prover, params, secret, secret_len, prover_id, prover_id_len);
216 BOTAN_UNUSED(verifier_id, verifier_id_len, context, context_len);
218#endif
219}
220
224
226 botan_rng_t rng,
227 botan_view_ctx ctx,
228 botan_view_bin_fn view) {
229#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
230 return BOTAN_FFI_VISIT(
231 prover, [=](auto& p) -> int { return invoke_view_callback(view, ctx, p.generate_message(safe_get(rng))); });
232#else
233 BOTAN_UNUSED(prover, rng, ctx, view);
235#endif
236}
237
239 botan_rng_t rng,
240 const uint8_t peer_message[],
241 size_t peer_message_len,
242 botan_view_ctx ctx,
243 botan_view_bin_fn view) {
244 if(any_null_pointers(peer_message)) {
246 }
247#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
248 return BOTAN_FFI_VISIT(prover, [=](auto& p) -> int {
249 return invoke_view_callback(view, ctx, p.process_message({peer_message, peer_message_len}, safe_get(rng)));
250 });
251#else
252 BOTAN_UNUSED(prover, rng, peer_message, peer_message_len, ctx, view);
254#endif
255}
256
258#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
259 return BOTAN_FFI_VISIT(prover, [=](auto& p) -> int { return invoke_view_callback(view, ctx, p.shared_secret()); });
260#else
261 BOTAN_UNUSED(prover, ctx, view);
263#endif
264}
265
268 const uint8_t record[],
269 size_t record_len,
270 const uint8_t prover_id[],
271 size_t prover_id_len,
272 const uint8_t verifier_id[],
273 size_t verifier_id_len,
274 const uint8_t context[],
275 size_t context_len) {
276 if(any_null_pointers(verifier, record)) {
278 }
279
280#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
281 return ffi_guard_thunk(__func__, [=]() -> int {
282 *verifier = nullptr;
283 const auto& p = safe_get(params);
284 const auto rec = Botan::SPAKE2p::RegistrationRecord::deserialize(p, {record, record_len});
285 auto ctx = std::make_unique<Botan::SPAKE2p::VerifierContext>(p,
286 rec,
287 spake2p_opt_span(prover_id, prover_id_len),
288 spake2p_opt_span(verifier_id, verifier_id_len),
289 spake2p_opt_span(context, context_len));
290 return ffi_new_object(verifier, std::move(ctx));
291 });
292#else
293 BOTAN_UNUSED(verifier, params, record, record_len, prover_id, prover_id_len);
294 BOTAN_UNUSED(verifier_id, verifier_id_len, context, context_len);
296#endif
297}
298
302
304 botan_rng_t rng,
305 const uint8_t peer_message[],
306 size_t peer_message_len,
307 botan_view_ctx ctx,
308 botan_view_bin_fn view) {
309 if(any_null_pointers(peer_message)) {
311 }
312
313#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
314 return BOTAN_FFI_VISIT(verifier, [=](auto& v) -> int {
315 return invoke_view_callback(view, ctx, v.process_message({peer_message, peer_message_len}, safe_get(rng)));
316 });
317#else
318 BOTAN_UNUSED(verifier, rng, peer_message, peer_message_len, ctx, view);
320#endif
321}
322
324 const uint8_t confirmation[],
325 size_t confirmation_len) {
326 if(confirmation == nullptr) {
328 }
329
330#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
331 return BOTAN_FFI_VISIT(verifier, [=](auto& v) -> int {
332 v.verify_confirmation({confirmation, confirmation_len});
333 return BOTAN_FFI_SUCCESS;
334 });
335#else
336 BOTAN_UNUSED(verifier, confirmation, confirmation_len);
338#endif
339}
340
342#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
343 return BOTAN_FFI_VISIT(verifier, [](auto& v) -> int {
344 v.skip_confirmation();
345 return BOTAN_FFI_SUCCESS;
346 });
347#else
348 BOTAN_UNUSED(verifier);
350#endif
351}
352
354 botan_view_ctx ctx,
355 botan_view_bin_fn view) {
356#if defined(BOTAN_HAS_PAKE_SPAKE2PLUS)
357 return BOTAN_FFI_VISIT(verifier, [=](auto& v) -> int { return invoke_view_callback(view, ctx, v.shared_secret()); });
358#else
359 BOTAN_UNUSED(verifier, ctx, view);
361#endif
362}
363}
#define BOTAN_UNUSED
Definition assert.h:144
static ProverSecret from_password(const SystemParameters &params, std::string_view password, std::span< const uint8_t > prover_id, std::span< const uint8_t > verifier_id, std::span< const uint8_t > salt)
Definition spake2p.cpp:283
static ProverSecret deserialize(const SystemParameters &params, std::span< const uint8_t > secret)
Definition spake2p.cpp:296
static RegistrationRecord deserialize(const SystemParameters &params, std::span< const uint8_t > record)
Definition spake2p.cpp:261
static SystemParameters custom(const EC_Group &group, std::span< const uint8_t > seed, std::string_view hash_fn)
Definition spake2p.cpp:221
struct botan_spake2p_prover_struct * botan_spake2p_prover_t
Definition ffi.h:4805
struct botan_ec_group_struct * botan_ec_group_t
Definition ffi.h:1472
int(* botan_view_bin_fn)(botan_view_ctx view_ctx, const uint8_t *data, size_t len)
Definition ffi.h:161
void * botan_view_ctx
Definition ffi.h:152
struct botan_rng_struct * botan_rng_t
Definition ffi.h:289
@ BOTAN_FFI_ERROR_NOT_IMPLEMENTED
Definition ffi.h:138
@ BOTAN_FFI_ERROR_NULL_POINTER
Definition ffi.h:131
@ BOTAN_FFI_SUCCESS
Definition ffi.h:114
struct botan_spake2p_verifier_struct * botan_spake2p_verifier_t
Definition ffi.h:4810
struct botan_spake2p_params_struct * botan_spake2p_params_t
Definition ffi.h:4690
int botan_spake2p_params_init(botan_spake2p_params_t *params, const char *ciphersuite)
int botan_spake2p_prover_init(botan_spake2p_prover_t *prover, botan_spake2p_params_t params, const uint8_t secret[], size_t secret_len, const uint8_t prover_id[], size_t prover_id_len, const uint8_t verifier_id[], size_t verifier_id_len, const uint8_t context[], size_t context_len)
int botan_spake2p_derive_secret(botan_spake2p_params_t params, const char *password, const uint8_t prover_id[], size_t prover_id_len, const uint8_t verifier_id[], size_t verifier_id_len, const uint8_t salt[], size_t salt_len, botan_view_ctx ctx, botan_view_bin_fn view)
int botan_spake2p_verifier_verify_confirmation(botan_spake2p_verifier_t verifier, const uint8_t confirmation[], size_t confirmation_len)
int botan_spake2p_verifier_process_message(botan_spake2p_verifier_t verifier, botan_rng_t rng, const uint8_t peer_message[], size_t peer_message_len, botan_view_ctx ctx, botan_view_bin_fn view)
int botan_spake2p_params_share_size(botan_spake2p_params_t params, size_t *share_size)
int botan_spake2p_prover_shared_secret(botan_spake2p_prover_t prover, botan_view_ctx ctx, botan_view_bin_fn view)
int botan_spake2p_params_confirmation_size(botan_spake2p_params_t params, size_t *confirmation_size)
int botan_spake2p_verifier_destroy(botan_spake2p_verifier_t verifier)
int botan_spake2p_verifier_skip_confirmation(botan_spake2p_verifier_t verifier)
int botan_spake2p_prover_process_message(botan_spake2p_prover_t prover, botan_rng_t rng, const uint8_t peer_message[], size_t peer_message_len, botan_view_ctx ctx, botan_view_bin_fn view)
int botan_spake2p_params_init_custom(botan_spake2p_params_t *params, botan_ec_group_t group, const uint8_t seed[], size_t seed_len, const char *hash_fn)
int botan_spake2p_verifier_init(botan_spake2p_verifier_t *verifier, botan_spake2p_params_t params, const uint8_t record[], size_t record_len, const uint8_t prover_id[], size_t prover_id_len, const uint8_t verifier_id[], size_t verifier_id_len, const uint8_t context[], size_t context_len)
int botan_spake2p_prover_destroy(botan_spake2p_prover_t prover)
int botan_spake2p_verifier_shared_secret(botan_spake2p_verifier_t verifier, botan_view_ctx ctx, botan_view_bin_fn view)
int botan_spake2p_params_destroy(botan_spake2p_params_t params)
int botan_spake2p_prover_generate_message(botan_spake2p_prover_t prover, botan_rng_t rng, botan_view_ctx ctx, botan_view_bin_fn view)
int botan_spake2p_registration_record(botan_spake2p_params_t params, botan_rng_t rng, const uint8_t secret[], size_t secret_len, botan_view_ctx ctx, botan_view_bin_fn view)
#define BOTAN_FFI_VISIT(obj, lambda)
Definition ffi_util.h:158
#define BOTAN_FFI_CHECKED_DELETE(o)
Definition ffi_util.h:188
#define BOTAN_FFI_DECLARE_DUMMY_STRUCT(NAME, MAGIC)
Definition ffi_util.h:66
#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC)
Definition ffi_util.h:61
int invoke_view_callback(botan_view_bin_fn view, botan_view_ctx ctx, std::span< const uint8_t > buf)
Definition ffi_util.h:190
T & safe_get(botan_struct< T, M > *p)
Definition ffi_util.h:79
BOTAN_FFI_ERROR ffi_new_object(T *obj, Args &&... args)
Definition ffi_util.h:178
int ffi_guard_thunk(const char *func_name, T thunk)
Definition ffi_util.h:95
bool any_null_pointers(Ptrs... ptr)
Definition mem_utils.h:54