refactor: migrate Botan backend crypto-refresh/PQC code to FFI - #2448
refactor: migrate Botan backend crypto-refresh/PQC code to FFI#2448ronaldtse wants to merge 2 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2448 +/- ##
==========================================
- Coverage 85.40% 85.39% -0.01%
==========================================
Files 126 126
Lines 22924 23008 +84
==========================================
+ Hits 19578 19648 +70
- Misses 3346 3360 +14 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
86b9c18 to
2d52db3
Compare
|
@randombit Botan remains to be RNP's primary cryptographic library, and we're grateful for your support and commitment! Since the PQC merge, which used a number of functions from Botan's internal API, we are trying to migrate to Botan's official FFI so RNP can use the same code across Botan 2.x/3.x without per-version Most needs map cleanly to FFI functions except for It seems that FFI exposes only the streaming What we observe (Botan 3.12.0,
So for CBC decrypt we'd need to buffer on our side (hold ≥2 blocks before we can emit the first plaintext block) to preserve RNP's immediate-output streaming contract. A few questions:
If the answer is "no raw path exists, please buffer," that's a perfectly good answer and will do it. If there's ever appetite to expose something like Thanks again for any pointers. Really appreciated. |
7625eb0 to
4f0debb
Compare
… crypto) Removes the Botan C++ API from the Botan backend everywhere except cipher_botan (see below). The migrated files contain zero Botan:: references. Crypto-refresh / PQC: - ec.cpp, eddsa.cpp, ed25519_ed448.cpp, x25519_x448.cpp, exdsa_ecdhkem.cpp - dilithium.cpp (ML-DSA), kyber.cpp (ML-KEM), sphincsplus.cpp (SLH-DSA) - kyber_ecdh_composite.cpp (RFC 3394 keywrap -> botan_nist_kw_*) - botan_utils.hpp (view callback, KEM op RAII wrappers) Core crypto: - hash.cpp/hash_botan.hpp: hashing incl. CRC24 -> botan_hash_* - hkdf_botan.cpp: HKDF -> botan_kdf - s2k.cpp: Argon2id -> botan_pwdhash - elgamal.cpp: BigInt/power_mod -> botan_mp_* / botan_mp_powmod - backend_version.cpp: -> botan_version_* - rng.cpp/rng.h: drop the Botan::RandomNumberGenerator exposure; RNG is now an opaque botan_rng_t handle - mem.h: replace Botan::secure_vector with rnp::secure_allocator (calloc + botan_scrub_mem via the FFI) Deferred: - cipher_botan.cpp/.hpp remain on the Botan C++ API. The FFI exposes only the streaming botan_cipher_update (no equivalent of Cipher_Mode::process()), and CBC decrypt must buffer a block, so a correct migration needs a 1-block-delay buffering rewrite on rnp side. Not done here to avoid shipping subtly-wrong symmetric crypto. Validated against Botan 3.12.0 and HEAD: no FFI gaps except the cipher process() asymmetry above. Full rnp_tests passes 296/296 with ENABLE_CRYPTO_REFRESH + ENABLE_PQC, including all PQC tests; this also fixes two PQC tests that failed against 3.12 on the native API.
85407d6 to
125a334
Compare
|
@ronaldtse good question and indeed right now we only support streaming via FFI. I am planning some extensions to cipher mode API in the relatively near future to make them easier to use, I will keep this use case in mind during the design process. But for now (and of course for all versions before this updated API lands), yes you'll have to buffer internally to handle this. In general you'll want to make inputs as large as possible (say ~~ 128 bytes to 4 Kb range) since there are many optimizations [SIMD implementations, interleaving, etc] that trigger when multiple blocks are processed at once. |
ec.cpp uses the rnp::botan FFI wrappers and the BOTAN_VERSION_CODE macros, both defined via botan_utils.hpp; without it every Botan-backend compile of the migrated file fails at the version #if and the rnp::botan namespace. Also apply clang-format to exdsa_ecdhkem.cpp.
|
@randombit thanks — that matches what we see in practice. Our FFI layer passes the caller's buffer sizes straight to |
Summary
Migrates the Botan backend off Botan's C++ API and onto the stable C FFI (
botan_*), matching rnp's existing FFI discipline (which is what keeps rnp working across Botan 2.x/3.x). Stacks on #2392 (pqc-openssl). Fixes the Botan 3.12 build breakage on that branch (native include-hygiene errors + deprecations).All migrated files contain zero
Botan::references:ec.cpp(ec_generate_generic_native),ed25519_ed448.cpp,x25519_x448.cpp,exdsa_ecdhkem.cpp,dilithium.cpp(ML-DSA),kyber.cpp(ML-KEM),sphincsplus.cpp(SLH-DSA),kyber_ecdh_composite.cpp(RFC 3394 keywrap →botan_nist_kw_*),botan_utils.hpp(view callback + KEM op RAII wrappers)hash.cpp/hash_botan.hpp(incl. CRC24 →botan_hash_*),hkdf_botan.cpp(botan_kdf),s2k.cpp(Argon2id →botan_pwdhash),elgamal.cpp(botan_mp_*/botan_mp_powmod),backend_version.cpp(botan_version_*),rng.cpp/rng.h(dropped theBotan::RandomNumberGeneratorexposure; opaquebotan_rng_thandle),mem.h(rnp::secure_allocatorreplacingBotan::secure_vector), and the always-compiledec.cpp/eddsa.cppkeygen paths →botan_*_view_rawOpenSSL-side
*_ossl.cppfiles are untouched.Version compatibility
rnp supports Botan 2.14 → 3.x, so any FFI symbol added after 2.14 is behind a version gate with an older-Botan fallback — the same pattern rnp already uses (e.g.
ecdh.cppforbotan_nist_kw_*):ec.cppKey::generate_x25519andeddsa.cppgenerate:#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(3,6,0)→botan_*_view_raw;#else→ the legacybotan_*_get_*getters (2.x-safe).botan_utils.hpp: view callback guarded>= 3.6.0; KEM op wrappers guarded#if defined(ENABLE_PQC).ENABLE_CRYPTO_REFRESH/ENABLE_PQC(which require 3.6+).cipher_botanis intentionally left native (NOT a blocker)cipher_botan.cpp/.hppstays onBotan::Cipher_Mode. The Botan FFI exposes only the streamingbotan_cipher_update— there is no equivalent ofBotan::Cipher_Mode::process()(raw per-block, immediate output) which rnp's cipher streaming is built on, and CBC-decrypt inherently buffers a block. A correct FFI cipher therefore needs a 1-block-delay buffering rewrite on rnp's side.This does not block the PR. The native cipher compiles and works correctly everywhere; everything else in the Botan backend is now FFI-only. The cipher migration is a self-contained follow-up — and, like every other FFI symbol, it will be version-gated regardless of what upstream does, so waiting on Botan to expose a
process-equivalent wouldn't change rnp's gating architecture. (Filed as a question to @randombit in a separate comment, out of genuine curiosity — not a merge dependency.)Test plan
cmake -DCRYPTO_BACKEND=botan3 -DENABLE_CRYPTO_REFRESH=ON -DENABLE_PQC=ONbuilds clean on Botan 3.12.rnp_tests: 296/296 pass locally (no regressions); all PQC tests pass — this also fixes two PQC tests that failed against 3.12 on the native API (kyber_ecdh_roundtrip,test_ffi_pqc_gen_enc_sign).Botan::references (cipher_botan excepted, by design).clang-format(v11) clean on all changed files.Notes
pqc-opensslatoriginis a staging copy of kaie's fork branch, created only so this PR can target Add an automatically generated OpenSSL backend for the Crypto Refresh and PQC code #2392. It can be deleted once Add an automatically generated OpenSSL backend for the Crypto Refresh and PQC code #2392 and this PR are handled.