#include "fiko/orkestra/eslesme.hpp" #include #include "fiko/orkestra/protokol.hpp" namespace fiko::orkestra { namespace { constexpr uint16_t ESLESME_SURUM = 1; // FNV-1a 64 tabanlı çok-tur genişletme (bkz. başlık uyarısı: kripto DEĞİL, TOFU). uint64_t fnvTur(uint64_t h, const uint8_t* p, size_t n) { for (size_t i = 0; i < n; ++i) { h ^= p[i]; h *= 1099511628211ull; } return h; } // Gövdeler: [u16 sürüm][u64 nodeId][str ad][16B nonce] (onayda ad boş). std::string govdeKur(uint64_t nodeId, const std::string& ad, const std::array& nonce) { std::string s; surecproto::yazU16(s, ESLESME_SURUM); surecproto::yazU64(s, nodeId); surecproto::yazStr(s, ad); s.append((const char*)nonce.data(), nonce.size()); return s; } bool govdeCoz(const std::string& govde, uint64_t& nodeId, std::string& ad, std::array& nonce) { const char* p = govde.data(); const char* son = p + govde.size(); if (son - p < 2 + 8) return false; p += 2; nodeId = surecproto::okuU64(p); p += 8; if (!surecproto::okuStr(p, son, ad)) return false; if ((size_t)(son - p) < EslesmeYonetici::NONCE) return false; for (size_t i = 0; i < EslesmeYonetici::NONCE; ++i) nonce[i] = (uint8_t)p[i]; return nodeId != 0; } } // namespace std::array eslesmeAnahtarTuret(uint64_t idA, const std::array& nonceA, uint64_t idB, const std::array& nonceB) { // Kanonik sıra: küçük id + onun nonce'u önce → iki uç aynı anahtarı bulur. const bool aKucuk = idA < idB; const uint64_t id1 = aKucuk ? idA : idB, id2 = aKucuk ? idB : idA; const auto& n1 = aKucuk ? nonceA : nonceB; const auto& n2 = aKucuk ? nonceB : nonceA; std::array anahtar{}; uint64_t h = 1469598103934665603ull; for (int blok = 0; blok < 4; ++blok) { h = fnvTur(h, (const uint8_t*)&id1, 8); h = fnvTur(h, n1.data(), n1.size()); h = fnvTur(h, (const uint8_t*)&id2, 8); h = fnvTur(h, n2.data(), n2.size()); h = fnvTur(h, (const uint8_t*)&blok, 4); for (int t = 0; t < 8; ++t) h = fnvTur(h, (const uint8_t*)&h, 8); // karıştırma turları for (int i = 0; i < 8; ++i) anahtar[(size_t)blok * 8 + (size_t)i] = (uint8_t)(h >> (8 * i)); } return anahtar; } std::string eslesmeKodTuret(const std::array& anahtar) { uint64_t v = 0; for (int i = 0; i < 8; ++i) v |= (uint64_t)anahtar[(size_t)i] << (8 * i); char kod[8]; std::snprintf(kod, sizeof(kod), "%06llu", (unsigned long long)(v % 1000000ull)); return kod; } EslesmeYonetici::Bekleyen* EslesmeYonetici::bekleyenBul(uint64_t nodeId) { for (auto& b : bekleyenler_) if (b.nodeId == nodeId) return &b; return nullptr; } const EslesmeKaydi* EslesmeYonetici::kayitBul(uint64_t nodeId) const { for (const auto& k : kayitlar_) if (k.nodeId == nodeId) return &k; return nullptr; } void EslesmeYonetici::kaydet(uint64_t nodeId, const std::string& ad, const std::array& anahtar) { for (auto& k : kayitlar_) { if (k.nodeId == nodeId) { // yeniden eşleşme → anahtar tazelenir k.ad = ad; k.anahtar = anahtar; return; } } kayitlar_.push_back({nodeId, ad, Rol::Izleyici, anahtar}); // yeni eşleşme → salt-okuma } std::string EslesmeYonetici::istekOlustur(uint64_t kendiId, const std::string& kendiAd, uint64_t hedefId, uint64_t simdiMs) { Bekleyen b; b.nodeId = hedefId; b.gelen = false; b.zamanMs = simdiMs; rastgele_(b.bizimNonce.data(), b.bizimNonce.size()); // Aynı hedefe önceki bekleyen varsa yenisi onun yerine geçer (tek istek). for (size_t i = 0; i < bekleyenler_.size(); ++i) if (bekleyenler_[i].nodeId == hedefId) { bekleyenler_.erase(bekleyenler_.begin() + (long)i); break; } bekleyenler_.push_back(b); return govdeKur(kendiId, kendiAd, b.bizimNonce); } bool EslesmeYonetici::istekAl(const std::string& govde, uint64_t kendiId, uint64_t simdiMs, uint64_t& istekNodeId, std::string& ad, std::string& kod) { std::array karsiNonce{}; if (!govdeCoz(govde, istekNodeId, ad, karsiNonce)) return false; if (istekNodeId == kendiId) return false; // kendi loopback isteğimiz if (esliMi(istekNodeId)) return false; // zaten eşli — yeniden eşleşme = önce kaldir() Bekleyen* b = bekleyenBul(istekNodeId); if (!b) { bekleyenler_.push_back({}); b = &bekleyenler_.back(); b->nodeId = istekNodeId; rastgele_(b->bizimNonce.data(), b->bizimNonce.size()); } b->ad = ad; b->karsiNonce = karsiNonce; b->gelen = true; b->zamanMs = simdiMs; const auto anahtar = eslesmeAnahtarTuret(istekNodeId, karsiNonce, kendiId, b->bizimNonce); kod = eslesmeKodTuret(anahtar); b->kod = kod; // panel bekleyen kartı için sakla (onaya dek gösterilir) return true; } std::vector EslesmeYonetici::bekleyenGelenler() const { std::vector o; for (const auto& b : bekleyenler_) if (b.gelen) o.push_back({b.nodeId, b.ad, b.kod}); return o; } bool EslesmeYonetici::onayla(uint64_t kendiId, uint64_t nodeId, std::string& onayGovde) { Bekleyen* b = bekleyenBul(nodeId); if (!b || !b->gelen) return false; // Onay gövdesi BİZİM kimlik + nonce'umuzu taşır (karşı uç anahtarı bununla türetir). onayGovde = govdeKur(kendiId, "", b->bizimNonce); const auto anahtar = eslesmeAnahtarTuret(nodeId, b->karsiNonce, kendiId, b->bizimNonce); kaydet(nodeId, b->ad, anahtar); reddet(nodeId); // bekleyen tüketildi return true; } void EslesmeYonetici::reddet(uint64_t nodeId) { for (size_t i = 0; i < bekleyenler_.size(); ++i) if (bekleyenler_[i].nodeId == nodeId) { bekleyenler_.erase(bekleyenler_.begin() + (long)i); return; } } bool EslesmeYonetici::onayAl(const std::string& govde, uint64_t kendiId, uint64_t& nodeId, std::string& kod) { std::string bosAd; std::array karsiNonce{}; if (!govdeCoz(govde, nodeId, bosAd, karsiNonce)) return false; Bekleyen* b = bekleyenBul(nodeId); // istekOlustur hedefiyle eşleşmeli if (!b || b->gelen) return false; // istek bizden çıkmadıysa onay sahte const auto anahtar = eslesmeAnahtarTuret(kendiId, b->bizimNonce, nodeId, karsiNonce); kod = eslesmeKodTuret(anahtar); kaydet(nodeId, b->ad, anahtar); reddet(nodeId); // bekleyen tüketildi return true; } void EslesmeYonetici::temizle(uint64_t simdiMs, uint64_t ttlMs) { for (size_t i = bekleyenler_.size(); i-- > 0;) if (simdiMs - bekleyenler_[i].zamanMs > ttlMs) bekleyenler_.erase(bekleyenler_.begin() + (long)i); } bool EslesmeYonetici::rolAyarla(uint64_t nodeId, Rol rol) { for (auto& k : kayitlar_) if (k.nodeId == nodeId) { k.rol = rol; return true; } return false; } Rol EslesmeYonetici::rol(uint64_t nodeId) const { const EslesmeKaydi* k = kayitBul(nodeId); return k ? k->rol : Rol::Izleyici; // eşli değil → en kısıtlı (komut reddedilir) } bool EslesmeYonetici::kaldir(uint64_t nodeId) { for (size_t i = 0; i < kayitlar_.size(); ++i) { if (kayitlar_[i].nodeId == nodeId) { kayitlar_.erase(kayitlar_.begin() + (long)i); return true; } } return false; } std::string EslesmeYonetici::serialize() const { std::string s; surecproto::yazU16(s, ESLESME_SURUM); surecproto::yazU32(s, (uint32_t)kayitlar_.size()); for (const auto& k : kayitlar_) { surecproto::yazU64(s, k.nodeId); surecproto::yazStr(s, k.ad); s.push_back((char)k.rol); // sürüm-1 sona rol eklendi (eski depo → varsayılan İzleyici) s.append((const char*)k.anahtar.data(), k.anahtar.size()); } return s; } bool EslesmeYonetici::yukle(const std::string& veri) { const char* p = veri.data(); const char* son = p + veri.size(); if (son - p < 6) return false; p += 2; const uint32_t adet = surecproto::okuU32(p); p += 4; std::vector yeni; for (uint32_t i = 0; i < adet; ++i) { EslesmeKaydi k; if (son - p < 8) return false; k.nodeId = surecproto::okuU64(p); p += 8; if (!surecproto::okuStr(p, son, k.ad)) return false; if ((size_t)(son - p) < 1 + k.anahtar.size()) return false; const uint8_t r = (uint8_t)*p++; k.rol = r <= (uint8_t)Rol::Yonetici ? (Rol)r : Rol::Izleyici; // bilinmeyen → kısıtlı for (size_t j = 0; j < k.anahtar.size(); ++j) k.anahtar[j] = (uint8_t)p[j]; p += k.anahtar.size(); yeni.push_back(std::move(k)); } kayitlar_ = std::move(yeni); return true; } } // namespace fiko::orkestra