--- id: secret_store_cpp_infra name: secret_store kind: function lang: cpp domain: infra version: 1.0.0 purity: impure signature: "fn_secret::encrypt(plaintext) -> blob; fn_secret::decrypt(blob) -> string; fn_secret::is_strong() -> bool" description: "Encrypt/decrypt sensitive strings for local SQLite storage. Windows: DPAPI (user-bound, machine-local, cryptographically strong). Linux/WSL fallback: XOR with per-user seed key (not crypto-secure, shows warning). Used by agents_dashboard to store API keys." tags: [security, credentials, dpapi, encrypt, infra, agents] uses_functions: [] uses_types: [] returns: "" returns_optional: false error_type: "" imports: "infra/secret_store.h" example: | #include "infra/secret_store.h" // Encrypt an API key before storing in SQLite: std::string apikey = "sk-mykey-123"; auto blob = fn_secret::encrypt(apikey); // store blob in SQLite BLOB column... // Decrypt when needed: std::string recovered = fn_secret::decrypt(blob); assert(recovered == apikey); // Check platform strength: if (!fn_secret::is_strong()) { // Show warning: Linux fallback is NOT crypto-secure } tested: false tests: [] test_file_path: "" file_path: "cpp/functions/infra/secret_store.cpp" params_schema: '{"params":[{"name":"plaintext","desc":"Sensitive string to encrypt (API key, password, token)."},{"name":"blob","desc":"Opaque byte vector returned by encrypt(), stored as SQLite BLOB."}],"output":"encrypt returns vector blob (empty on failure). decrypt returns plaintext string (empty on failure). is_strong() returns true on Windows (DPAPI), false on Linux (XOR fallback)."}' --- # secret_store Encrypt/decrypt sensitive credentials for local SQLite storage. ## Ejemplo ```cpp #include "infra/secret_store.h" // Store API key encrypted: std::vector blob = fn_secret::encrypt("my-api-key-here"); // Insert blob into SQLite BLOB column via sqlite3_bind_blob()... // Recover: std::string key = fn_secret::decrypt(blob); // Base64 helpers for TEXT columns: std::string b64 = fn_secret::encrypt_b64("my-api-key-here"); std::string back = fn_secret::decrypt_b64(b64); // Platform check (show warning on Linux): if (!fn_secret::is_strong()) { fn_log::warn("[security] apikey stored with weak Linux fallback encryption"); } ``` ## Cuando usarla Antes de guardar una API key, token o contrasena en SQLite local. Siempre usar `fn::local_path("app.db")` para la DB. En Windows (DPAPI) la clave nunca sale de la maquina. En Linux, mostrar aviso en UI de que la proteccion es basica. ## Gotchas - **DPAPI is Windows-only**: el blob cifrado en Windows NO se puede descifrar en Linux y viceversa. Si el usuario mueve la DB entre plataformas, las credenciales se pierden — debe reingresar la apikey. - **Linux fallback NO es criptograficamente seguro**: XOR con semilla derivada de username+hostname. Previene lectura casual pero no protege contra atacante con acceso al sistema. - **CryptProtectData es sincrono**: no llamar desde el thread principal con datos grandes. Para una apikey (tipicamente <200 bytes) el coste es despreciable. - Linkear `crypt32.lib` en Windows: el `.cpp` tiene `#pragma comment(lib, "crypt32.lib")` — no necesita entry en CMakeLists para MSVC. Con MinGW se enlaza automaticamente si se incluye `wincrypt.h`.