209 lines
7.9 KiB
Rust
209 lines
7.9 KiB
Rust
// Bridge API — thin wrappers that delegate to ccc_rust providers.
|
|
//
|
|
// No cryptographic logic here; only type conversions and registry lookups.
|
|
|
|
use ccc_crypto_core::{KemProvider, ProviderRegistry};
|
|
use ccc_crypto_wolfssl::WolfSslProvider;
|
|
|
|
use crate::api::dto::*;
|
|
|
|
/// Trace-level bridge logging. Visible only when `RUST_LOG=trace` (or
|
|
/// equivalent) is set; compiled out in release builds when the `log` crate's
|
|
/// `release_max_level_off` feature is enabled.
|
|
macro_rules! dbg_bridge {
|
|
($($arg:tt)*) => {
|
|
log::trace!("[ccc-bridge] {}", format!($($arg)*));
|
|
};
|
|
}
|
|
|
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
/// Default provider name used when the caller doesn't specify one.
|
|
const DEFAULT_PROVIDER: &str = "wolfssl";
|
|
|
|
/// Get the default provider from the registry or return an error.
|
|
fn default_provider(
|
|
) -> Result<std::sync::Arc<dyn ccc_crypto_core::provider::CryptoProvider>, CccCryptoError> {
|
|
ProviderRegistry::global()
|
|
.get(DEFAULT_PROVIDER)
|
|
.ok_or_else(|| {
|
|
CccCryptoError::InternalError(format!(
|
|
"provider '{DEFAULT_PROVIDER}' not registered — call ccc_init() first"
|
|
))
|
|
})
|
|
}
|
|
|
|
/// A lazily-initialised KemProvider instance.
|
|
///
|
|
/// `KemProvider` is not part of the `CryptoProvider` supertrait, so we keep
|
|
/// a standalone `WolfSslProvider` for KEM operations.
|
|
fn kem_provider() -> &'static WolfSslProvider {
|
|
use std::sync::OnceLock;
|
|
static KEM: OnceLock<WolfSslProvider> = OnceLock::new();
|
|
KEM.get_or_init(WolfSslProvider::new)
|
|
}
|
|
|
|
// ── Init ─────────────────────────────────────────────────────────────────────
|
|
|
|
/// Initialise the CCC cryptographic subsystem.
|
|
///
|
|
/// Registers the wolfSSL provider in the global registry.
|
|
/// Safe to call multiple times (idempotent).
|
|
pub fn ccc_init() {
|
|
dbg_bridge!("ccc_init: enter");
|
|
flutter_rust_bridge::setup_default_user_utils();
|
|
if !ProviderRegistry::global().contains(DEFAULT_PROVIDER) {
|
|
ccc_crypto_wolfssl::init();
|
|
}
|
|
dbg_bridge!("ccc_init: exit");
|
|
}
|
|
|
|
// ── Provider info ────────────────────────────────────────────────────────────
|
|
|
|
/// List all registered provider names.
|
|
#[flutter_rust_bridge::frb(sync)]
|
|
pub fn ccc_list_providers() -> Vec<String> {
|
|
dbg_bridge!("ccc_list_providers");
|
|
ProviderRegistry::global().list()
|
|
}
|
|
|
|
/// Return the capabilities of the default provider.
|
|
pub fn ccc_capabilities() -> Result<CccCapabilities, CccCryptoError> {
|
|
dbg_bridge!("ccc_capabilities");
|
|
let provider = default_provider()?;
|
|
Ok(CccCapabilities::from(provider.capabilities()))
|
|
}
|
|
|
|
// ── AEAD ─────────────────────────────────────────────────────────────────────
|
|
|
|
/// Encrypt with an AEAD algorithm.
|
|
///
|
|
/// Returns ciphertext‖tag.
|
|
pub fn ccc_aead_encrypt(
|
|
algorithm: CccAeadAlgorithm,
|
|
key: Vec<u8>,
|
|
nonce: Vec<u8>,
|
|
plaintext: Vec<u8>,
|
|
aad: Vec<u8>,
|
|
) -> Result<Vec<u8>, CccCryptoError> {
|
|
dbg_bridge!("ccc_aead_encrypt: pt_len={}", plaintext.len());
|
|
let provider = default_provider()?;
|
|
Ok(provider.encrypt_aead(algorithm.to_core(), &key, &nonce, &plaintext, &aad)?)
|
|
}
|
|
|
|
/// Decrypt with an AEAD algorithm.
|
|
///
|
|
/// Expects ciphertext‖tag as `ciphertext`.
|
|
pub fn ccc_aead_decrypt(
|
|
algorithm: CccAeadAlgorithm,
|
|
key: Vec<u8>,
|
|
nonce: Vec<u8>,
|
|
ciphertext: Vec<u8>,
|
|
aad: Vec<u8>,
|
|
) -> Result<Vec<u8>, CccCryptoError> {
|
|
dbg_bridge!("ccc_aead_decrypt: ct_len={}", ciphertext.len());
|
|
let provider = default_provider()?;
|
|
Ok(provider.decrypt_aead(algorithm.to_core(), &key, &nonce, &ciphertext, &aad)?)
|
|
}
|
|
|
|
// ── KDF ──────────────────────────────────────────────────────────────────────
|
|
|
|
/// Derive key material using a KDF.
|
|
pub fn ccc_kdf_derive(
|
|
algorithm: CccKdfAlgorithm,
|
|
ikm: Vec<u8>,
|
|
salt: Vec<u8>,
|
|
info: Vec<u8>,
|
|
length: u32,
|
|
) -> Result<Vec<u8>, CccCryptoError> {
|
|
dbg_bridge!("ccc_kdf_derive: length={}", length);
|
|
let provider = default_provider()?;
|
|
let derived = provider.derive_key(
|
|
algorithm.to_core(),
|
|
&ikm,
|
|
&salt,
|
|
&info,
|
|
length as usize,
|
|
)?;
|
|
// Move out of Zeroizing wrapper — FRB will copy to Dart.
|
|
Ok(derived.to_vec())
|
|
}
|
|
|
|
// ── MAC ──────────────────────────────────────────────────────────────────────
|
|
|
|
/// Compute a MAC tag.
|
|
pub fn ccc_mac_compute(
|
|
algorithm: CccMacAlgorithm,
|
|
key: Vec<u8>,
|
|
data: Vec<u8>,
|
|
) -> Result<Vec<u8>, CccCryptoError> {
|
|
dbg_bridge!("ccc_mac_compute: data_len={}", data.len());
|
|
let provider = default_provider()?;
|
|
Ok(provider.compute_mac(algorithm.to_core(), &key, &data)?)
|
|
}
|
|
|
|
/// Verify a MAC tag. Returns `true` if valid.
|
|
pub fn ccc_mac_verify(
|
|
algorithm: CccMacAlgorithm,
|
|
key: Vec<u8>,
|
|
data: Vec<u8>,
|
|
mac: Vec<u8>,
|
|
) -> Result<bool, CccCryptoError> {
|
|
dbg_bridge!("ccc_mac_verify: data_len={}", data.len());
|
|
let provider = default_provider()?;
|
|
Ok(provider.verify_mac(algorithm.to_core(), &key, &data, &mac)?)
|
|
}
|
|
|
|
// ── Hash ─────────────────────────────────────────────────────────────────────
|
|
|
|
/// Compute a cryptographic hash.
|
|
pub fn ccc_hash(
|
|
algorithm: CccHashAlgorithm,
|
|
data: Vec<u8>,
|
|
) -> Result<Vec<u8>, CccCryptoError> {
|
|
dbg_bridge!("ccc_hash: data_len={}", data.len());
|
|
let provider = default_provider()?;
|
|
Ok(provider.hash(algorithm.to_core(), &data)?)
|
|
}
|
|
|
|
// ── KEM ──────────────────────────────────────────────────────────────────────
|
|
|
|
/// Generate a KEM key pair.
|
|
pub fn ccc_kem_generate_keypair(
|
|
algorithm: CccKemAlgorithm,
|
|
) -> Result<CccKemKeyPair, CccCryptoError> {
|
|
dbg_bridge!("ccc_kem_generate_keypair");
|
|
let kp = kem_provider().generate_keypair(algorithm.to_core())?;
|
|
Ok(CccKemKeyPair::from(kp))
|
|
}
|
|
|
|
/// KEM encapsulation — produce ciphertext + shared secret from a public key.
|
|
pub fn ccc_kem_encapsulate(
|
|
algorithm: CccKemAlgorithm,
|
|
public_key: Vec<u8>,
|
|
) -> Result<CccKemEncapResult, CccCryptoError> {
|
|
dbg_bridge!("ccc_kem_encapsulate");
|
|
let result = kem_provider().encapsulate(algorithm.to_core(), &public_key)?;
|
|
Ok(CccKemEncapResult::from(result))
|
|
}
|
|
|
|
/// KEM decapsulation — recover shared secret from ciphertext + private key.
|
|
pub fn ccc_kem_decapsulate(
|
|
algorithm: CccKemAlgorithm,
|
|
private_key: Vec<u8>,
|
|
ciphertext: Vec<u8>,
|
|
) -> Result<Vec<u8>, CccCryptoError> {
|
|
dbg_bridge!("ccc_kem_decapsulate");
|
|
let ss = kem_provider().decapsulate(algorithm.to_core(), &private_key, &ciphertext)?;
|
|
Ok(ss.to_vec())
|
|
}
|
|
|
|
// ── Self-test ────────────────────────────────────────────────────────────────
|
|
|
|
/// Run the provider self-test and return a structured report.
|
|
pub fn ccc_self_test() -> Result<CccSelfTestReport, CccCryptoError> {
|
|
dbg_bridge!("ccc_self_test");
|
|
let provider = default_provider()?;
|
|
Ok(CccSelfTestReport::from(provider.self_test()))
|
|
}
|