#include "fiko/cekirdek/kripto.hpp" #include #include #if defined(_WIN32) #include // #include #ifndef STATUS_SUCCESS #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif #endif namespace fiko::kripto { namespace { int hexBasamak(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } } // namespace bool hexBayt(std::string_view hex, u8* out, std::size_t n) { if (hex.size() < n * 2) return false; for (std::size_t i = 0; i < n; ++i) { const int hi = hexBasamak(hex[2 * i]), lo = hexBasamak(hex[2 * i + 1]); if (hi < 0 || lo < 0) return false; out[i] = static_cast((hi << 4) | lo); } return true; } std::string baytHex(const u8* b, std::size_t n) { static const char* h = "0123456789abcdef"; std::string s; s.reserve(n * 2); for (std::size_t i = 0; i < n; ++i) { s.push_back(h[b[i] >> 4]); s.push_back(h[b[i] & 0xF]); } return s; } bool base64Coz(std::string_view g, std::vector& out) { auto v = [](unsigned char c) -> int { if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '+') return 62; if (c == '/') return 63; return -1; }; out.clear(); int biriktir = 0, bit = 0; for (char ch : g) { if (ch == '=' || ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t') continue; const int d = v(static_cast(ch)); if (d < 0) return false; biriktir = (biriktir << 6) | d; bit += 6; if (bit >= 8) { bit -= 8; out.push_back(static_cast((biriktir >> bit) & 0xFF)); } } return true; } #if defined(_WIN32) bool sha256(const void* veri, std::size_t n, u8 out[32]) { BCRYPT_ALG_HANDLE alg = nullptr; if (BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA256_ALGORITHM, nullptr, 0) != STATUS_SUCCESS) return false; BCRYPT_HASH_HANDLE h = nullptr; bool ok = false; if (BCryptCreateHash(alg, &h, nullptr, 0, nullptr, 0, 0) == STATUS_SUCCESS) { ok = (n == 0 || BCryptHashData(h, (PUCHAR)veri, (ULONG)n, 0) == STATUS_SUCCESS) && BCryptFinishHash(h, out, 32, 0) == STATUS_SUCCESS; BCryptDestroyHash(h); } BCryptCloseAlgorithmProvider(alg, 0); return ok; } bool sha256Dosya(const std::string& yol, u8 out[32]) { BCRYPT_ALG_HANDLE alg = nullptr; if (BCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA256_ALGORITHM, nullptr, 0) != STATUS_SUCCESS) return false; BCRYPT_HASH_HANDLE h = nullptr; bool ok = false; if (BCryptCreateHash(alg, &h, nullptr, 0, nullptr, 0, 0) == STATUS_SUCCESS) { std::ifstream f(yol, std::ios::binary); if (f) { std::vector buf(65536); ok = true; while (f) { f.read(buf.data(), (std::streamsize)buf.size()); const std::streamsize n = f.gcount(); if (n > 0 && BCryptHashData(h, (PUCHAR)buf.data(), (ULONG)n, 0) != STATUS_SUCCESS) { ok = false; break; } } if (ok && BCryptFinishHash(h, out, 32, 0) != STATUS_SUCCESS) ok = false; } BCryptDestroyHash(h); } BCryptCloseAlgorithmProvider(alg, 0); return ok; } bool ecdsaP256Dogrula(const u8 digest[32], const u8* sig, std::size_t sigLen, const u8 pub[64]) { if (sigLen != 64) return false; BCRYPT_ALG_HANDLE alg = nullptr; if (BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P256_ALGORITHM, nullptr, 0) != STATUS_SUCCESS) return false; std::vector blob(sizeof(BCRYPT_ECCKEY_BLOB) + 64); auto* hdr = reinterpret_cast(blob.data()); hdr->dwMagic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; hdr->cbKey = 32; std::memcpy(blob.data() + sizeof(BCRYPT_ECCKEY_BLOB), pub, 64); BCRYPT_KEY_HANDLE key = nullptr; bool ok = false; if (BCryptImportKeyPair(alg, nullptr, BCRYPT_ECCPUBLIC_BLOB, &key, blob.data(), (ULONG)blob.size(), 0) == STATUS_SUCCESS) { ok = BCryptVerifySignature(key, nullptr, (PUCHAR)digest, 32, (PUCHAR)sig, (ULONG)sigLen, 0) == STATUS_SUCCESS; BCryptDestroyKey(key); } BCryptCloseAlgorithmProvider(alg, 0); return ok; } bool p256AnahtarUret(std::string& ozelHex, std::string& acikHex) { BCRYPT_ALG_HANDLE alg = nullptr; if (BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P256_ALGORITHM, nullptr, 0) != STATUS_SUCCESS) return false; BCRYPT_KEY_HANDLE key = nullptr; bool ok = false; if (BCryptGenerateKeyPair(alg, &key, 256, 0) == STATUS_SUCCESS && BCryptFinalizeKeyPair(key, 0) == STATUS_SUCCESS) { ULONG n = 0; std::vector blob(sizeof(BCRYPT_ECCKEY_BLOB) + 96); if (BCryptExportKey(key, nullptr, BCRYPT_ECCPRIVATE_BLOB, blob.data(), (ULONG)blob.size(), &n, 0) == STATUS_SUCCESS && n >= sizeof(BCRYPT_ECCKEY_BLOB) + 96) { const u8* p = blob.data() + sizeof(BCRYPT_ECCKEY_BLOB); ozelHex = baytHex(p, 96); acikHex = baytHex(p, 64); ok = true; } } if (key) BCryptDestroyKey(key); BCryptCloseAlgorithmProvider(alg, 0); return ok; } bool imzala(std::string_view govde, std::string_view ozelHex, std::string& imzaB64) { u8 ozel[96]; if (!hexBayt(ozelHex, ozel, 96)) return false; u8 digest[32]; if (!sha256(govde.data(), govde.size(), digest)) return false; BCRYPT_ALG_HANDLE alg = nullptr; if (BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P256_ALGORITHM, nullptr, 0) != STATUS_SUCCESS) return false; std::vector blob(sizeof(BCRYPT_ECCKEY_BLOB) + 96); auto* hdr = reinterpret_cast(blob.data()); hdr->dwMagic = BCRYPT_ECDSA_PRIVATE_P256_MAGIC; hdr->cbKey = 32; std::memcpy(blob.data() + sizeof(BCRYPT_ECCKEY_BLOB), ozel, 96); BCRYPT_KEY_HANDLE key = nullptr; bool ok = false; if (BCryptImportKeyPair(alg, nullptr, BCRYPT_ECCPRIVATE_BLOB, &key, blob.data(), (ULONG)blob.size(), 0) == STATUS_SUCCESS) { u8 sig[64]; ULONG n = 0; if (BCryptSignHash(key, nullptr, (PUCHAR)digest, 32, sig, 64, &n, 0) == STATUS_SUCCESS && n == 64) { imzaB64 = base64Kodla(sig, 64); ok = true; } BCryptDestroyKey(key); } BCryptCloseAlgorithmProvider(alg, 0); return ok; } bool rastgeleBayt(u8* out, std::size_t n) { if (n == 0) return true; return BCryptGenRandom(nullptr, out, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS; } namespace { // AES-256-GCM ortak kurulumu: sağlayıcı + GCM zincir kipi + simetrik anahtar. // Çağıran kapatmakla yükümlü (aesGcmKapat). bool aesGcmAc(const u8 anahtar[32], BCRYPT_ALG_HANDLE& alg, BCRYPT_KEY_HANDLE& key) { alg = nullptr; key = nullptr; if (BCryptOpenAlgorithmProvider(&alg, BCRYPT_AES_ALGORITHM, nullptr, 0) != STATUS_SUCCESS) return false; if (BCryptSetProperty(alg, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0) != STATUS_SUCCESS || BCryptGenerateSymmetricKey(alg, &key, nullptr, 0, (PUCHAR)anahtar, 32, 0) != STATUS_SUCCESS) { if (key) BCryptDestroyKey(key); key = nullptr; BCryptCloseAlgorithmProvider(alg, 0); alg = nullptr; return false; } return true; } void aesGcmKapat(BCRYPT_ALG_HANDLE alg, BCRYPT_KEY_HANDLE key) { if (key) BCryptDestroyKey(key); if (alg) BCryptCloseAlgorithmProvider(alg, 0); } constexpr char AES_SIHIR[5] = {'F', 'K', 'L', 'E', '1'}; constexpr std::size_t AES_BASLIK = 5 + 12 + 16; // sihir + nonce + etiket } // namespace bool aesGcmSifrele(std::string_view duzMetin, const u8 anahtar[32], std::string& cikti) { cikti.clear(); u8 nonce[12]; if (!rastgeleBayt(nonce, sizeof(nonce))) return false; BCRYPT_ALG_HANDLE alg = nullptr; BCRYPT_KEY_HANDLE key = nullptr; if (!aesGcmAc(anahtar, alg, key)) return false; BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO bilgi; BCRYPT_INIT_AUTH_MODE_INFO(bilgi); u8 etiket[16] = {}; bilgi.pbNonce = nonce; bilgi.cbNonce = (ULONG)sizeof(nonce); bilgi.pbTag = etiket; bilgi.cbTag = (ULONG)sizeof(etiket); std::vector ct(duzMetin.size()); ULONG n = 0; const bool ok = BCryptEncrypt(key, (PUCHAR)duzMetin.data(), (ULONG)duzMetin.size(), &bilgi, nullptr, 0, ct.empty() ? nullptr : ct.data(), (ULONG)ct.size(), &n, 0) == STATUS_SUCCESS && n == (ULONG)ct.size(); aesGcmKapat(alg, key); if (!ok) return false; cikti.reserve(AES_BASLIK + ct.size()); cikti.append(AES_SIHIR, sizeof(AES_SIHIR)); cikti.append(reinterpret_cast(nonce), sizeof(nonce)); cikti.append(reinterpret_cast(etiket), sizeof(etiket)); cikti.append(reinterpret_cast(ct.data()), ct.size()); return true; } bool aesGcmCoz(std::string_view sifreli, const u8 anahtar[32], std::string& duzMetin) { duzMetin.clear(); if (sifreli.size() < AES_BASLIK) return false; if (std::memcmp(sifreli.data(), AES_SIHIR, sizeof(AES_SIHIR)) != 0) return false; const u8* p = reinterpret_cast(sifreli.data()); u8 nonce[12], etiket[16]; std::memcpy(nonce, p + 5, sizeof(nonce)); std::memcpy(etiket, p + 17, sizeof(etiket)); const std::size_t ctBoy = sifreli.size() - AES_BASLIK; BCRYPT_ALG_HANDLE alg = nullptr; BCRYPT_KEY_HANDLE key = nullptr; if (!aesGcmAc(anahtar, alg, key)) return false; BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO bilgi; BCRYPT_INIT_AUTH_MODE_INFO(bilgi); bilgi.pbNonce = nonce; bilgi.cbNonce = (ULONG)sizeof(nonce); bilgi.pbTag = etiket; bilgi.cbTag = (ULONG)sizeof(etiket); std::vector pt(ctBoy); ULONG n = 0; // Etiket tutmazsa STATUS_AUTH_TAG_MISMATCH döner → tek bayt bozulsa bile başarısız. const bool ok = BCryptDecrypt(key, (PUCHAR)(p + AES_BASLIK), (ULONG)ctBoy, &bilgi, nullptr, 0, pt.empty() ? nullptr : pt.data(), (ULONG)pt.size(), &n, 0) == STATUS_SUCCESS && n == (ULONG)pt.size(); aesGcmKapat(alg, key); if (!ok) return false; duzMetin.assign(reinterpret_cast(pt.data()), pt.size()); return true; } #else // Windows dışı: kripto yok → doğrulama daima başarısız (sessiz kabul YASAK). bool sha256(const void*, std::size_t, u8[32]) { return false; } bool sha256Dosya(const std::string&, u8[32]) { return false; } bool ecdsaP256Dogrula(const u8[32], const u8*, std::size_t, const u8[64]) { return false; } bool p256AnahtarUret(std::string&, std::string&) { return false; } bool imzala(std::string_view, std::string_view, std::string&) { return false; } bool rastgeleBayt(u8*, std::size_t) { return false; } bool aesGcmSifrele(std::string_view, const u8[32], std::string&) { return false; } bool aesGcmCoz(std::string_view, const u8[32], std::string&) { return false; } #endif std::string base64Kodla(const u8* b, std::size_t n) { static const char* t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string s; s.reserve((n + 2) / 3 * 4); for (std::size_t i = 0; i < n; i += 3) { const u32 a = b[i]; const u32 c = (i + 1 < n) ? b[i + 1] : 0; const u32 d = (i + 2 < n) ? b[i + 2] : 0; const u32 blok = (a << 16) | (c << 8) | d; s.push_back(t[(blok >> 18) & 63]); s.push_back(t[(blok >> 12) & 63]); s.push_back(i + 1 < n ? t[(blok >> 6) & 63] : '='); s.push_back(i + 2 < n ? t[blok & 63] : '='); } return s; } bool imzaDogrula(std::string_view govde, std::string_view imzaB64, std::string_view acikAnahtarHex) { if (acikAnahtarHex.size() < 128 || imzaB64.empty()) return false; u8 pub[64]; if (!hexBayt(acikAnahtarHex, pub, 64)) return false; std::vector sig; if (!base64Coz(imzaB64, sig) || sig.size() != 64) return false; u8 digest[32]; if (!sha256(govde.data(), govde.size(), digest)) return false; return ecdsaP256Dogrula(digest, sig.data(), sig.size(), pub); } } // namespace fiko::kripto