Skip to content

Commit cfe6239

Browse files
committed
harden public key storage and integrity checks
1 parent 52cbd61 commit cfe6239

1 file changed

Lines changed: 73 additions & 3 deletions

File tree

auth.cpp

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,22 @@ void cleanUpSeedData(const std::string& seed);
137137
std::string signature;
138138
std::string signatureTimestamp;
139139
bool initialized;
140-
std::string API_PUBLIC_KEY = "5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b";
140+
static constexpr uint8_t k_pubkey_xor1 = 0x5A;
141+
static constexpr uint8_t k_pubkey_xor2 = 0xA5;
142+
static constexpr uint64_t k_pubkey_fnv1a = 0x7553f24ca052d4b1ULL;
143+
static const uint8_t k_pubkey_obf1[64] = {
144+
0x6f, 0x6f, 0x62, 0x6c, 0x38, 0x6e, 0x38, 0x39, 0x6c, 0x63, 0x39, 0x6d, 0x3b, 0x6e, 0x38, 0x6e,
145+
0x62, 0x6d, 0x3f, 0x6e, 0x6f, 0x6c, 0x69, 0x3b, 0x6e, 0x39, 0x3e, 0x63, 0x6c, 0x3b, 0x3c, 0x3e,
146+
0x69, 0x63, 0x6b, 0x6e, 0x6a, 0x3c, 0x63, 0x6b, 0x63, 0x38, 0x3e, 0x69, 0x6b, 0x39, 0x3f, 0x3b,
147+
0x6d, 0x3e, 0x6b, 0x39, 0x6c, 0x3b, 0x6b, 0x3f, 0x62, 0x6e, 0x69, 0x63, 0x6e, 0x68, 0x68, 0x38
148+
};
149+
static const uint8_t k_pubkey_obf2[64] = {
150+
0x90, 0x90, 0x9d, 0x93, 0xc7, 0x91, 0xc7, 0xc6, 0x93, 0x9c, 0xc6, 0x92, 0xc4, 0x91, 0xc7, 0x91,
151+
0x9d, 0x92, 0xc0, 0x91, 0x90, 0x93, 0x96, 0xc4, 0x91, 0xc6, 0xc1, 0x9c, 0x93, 0xc4, 0xc3, 0xc1,
152+
0x96, 0x9c, 0x94, 0x91, 0x95, 0xc3, 0x9c, 0x94, 0x9c, 0xc7, 0xc1, 0x96, 0x94, 0xc6, 0xc0, 0xc4,
153+
0x92, 0xc1, 0x94, 0xc6, 0x93, 0xc4, 0x94, 0xc0, 0x9d, 0x91, 0x96, 0x9c, 0x91, 0x97, 0x97, 0xc7
154+
};
155+
static std::atomic<uint64_t> pubkey_hash_seen{ 0 };
141156
bool KeyAuth::api::debug = false;
142157
std::atomic<bool> LoggedIn(false);
143158
std::atomic<long long> last_integrity_check{ 0 };
@@ -188,6 +203,59 @@ static inline void securewipe(std::string& value) noexcept
188203
secure_zero(value);
189204
}
190205

206+
static uint64_t fnv1a64_bytes(const uint8_t* data, size_t len)
207+
{
208+
uint64_t h = 0xcbf29ce484222325ULL;
209+
for (size_t i = 0; i < len; ++i) {
210+
h ^= static_cast<uint64_t>(data[i]);
211+
h *= 0x100000001b3ULL;
212+
}
213+
return h;
214+
}
215+
216+
static std::string decode_pubkey_hex(const uint8_t* obf, size_t len, uint8_t key)
217+
{
218+
std::string out;
219+
out.resize(len);
220+
for (size_t i = 0; i < len; ++i) {
221+
out[i] = static_cast<char>(obf[i] ^ key);
222+
}
223+
return out;
224+
}
225+
226+
static bool pubkey_memory_protect_ok()
227+
{
228+
MEMORY_BASIC_INFORMATION mbi{};
229+
if (!VirtualQuery(k_pubkey_obf1, &mbi, sizeof(mbi)))
230+
return false;
231+
const DWORD p = mbi.Protect;
232+
if (p & PAGE_GUARD)
233+
return false;
234+
if ((p & PAGE_READWRITE) || (p & PAGE_WRITECOPY) ||
235+
(p & PAGE_EXECUTE_READWRITE) || (p & PAGE_EXECUTE_WRITECOPY)) {
236+
return false;
237+
}
238+
return true;
239+
}
240+
241+
static std::string get_public_key_hex()
242+
{
243+
if (!pubkey_memory_protect_ok()) {
244+
error(XorStr("public key memory protection tampered."));
245+
}
246+
std::string a = decode_pubkey_hex(k_pubkey_obf1, sizeof(k_pubkey_obf1), k_pubkey_xor1);
247+
std::string b = decode_pubkey_hex(k_pubkey_obf2, sizeof(k_pubkey_obf2), k_pubkey_xor2);
248+
if (a != b) {
249+
error(XorStr("public key mismatch detected."));
250+
}
251+
const uint64_t h = fnv1a64_bytes(reinterpret_cast<const uint8_t*>(a.data()), a.size());
252+
pubkey_hash_seen.store(h, std::memory_order_relaxed);
253+
if (h != k_pubkey_fnv1a) {
254+
error(XorStr("public key integrity failed."));
255+
}
256+
return a;
257+
}
258+
191259
struct ScopeWipe final {
192260
std::string* value;
193261
explicit ScopeWipe(std::string& v) noexcept : value(&v) {}
@@ -215,6 +283,7 @@ void KeyAuth::api::init()
215283
std::thread(runChecks).detach();
216284
snapshot_prologues();
217285
snapshot_checkinit();
286+
(void)get_public_key_hex();
218287
seed = generate_random_number();
219288
std::atexit([]() { cleanUpSeedData(seed); });
220289

@@ -1965,7 +2034,8 @@ int VerifyPayload(std::string signature, std::string timestamp, std::string body
19652034
exit(5);
19662035
}
19672036

1968-
if (sodium_hex2bin(pk, sizeof(pk), API_PUBLIC_KEY.c_str(), API_PUBLIC_KEY.length(), NULL, NULL, NULL) != 0) {
2037+
const std::string pubkey_hex = get_public_key_hex();
2038+
if (sodium_hex2bin(pk, sizeof(pk), pubkey_hex.c_str(), pubkey_hex.length(), NULL, NULL, NULL) != 0) {
19692039
std::cerr << "[ERROR] Failed to parse public key hex.\n";
19702040
MessageBoxA(0, "Signature verification failed (invalid public key)", "KeyAuth", MB_ICONERROR);
19712041
exit(6);
@@ -1975,7 +2045,7 @@ int VerifyPayload(std::string signature, std::string timestamp, std::string body
19752045
std::cout << "[DEBUG] Signature: " << signature << std::endl;
19762046
std::cout << "[DEBUG] Body: " << body << std::endl;
19772047
std::cout << "[DEBUG] Message (timestamp + body): " << message << std::endl;
1978-
std::cout << "[DEBUG] Public Key: " << API_PUBLIC_KEY << std::endl;*/
2048+
std::cout << "[DEBUG] Public Key: " << pubkey_hex << std::endl;*/
19792049

19802050
if (crypto_sign_ed25519_verify_detached(sig,
19812051
reinterpret_cast<const unsigned char*>(message.c_str()),

0 commit comments

Comments
 (0)