namespace Utils { namespace Cryptography { class Token { public: Token() { this->TokenString.clear(); }; Token(std::string token) : TokenString(token.begin(), token.end()) { }; Token(std::basic_string token) : TokenString(token.begin(), token.end()) { }; Token& operator++ () { if (this->TokenString.empty()) { this->TokenString.append(reinterpret_cast("\0"), 1); } else { for (unsigned int i = (this->TokenString.size() - 1); i >= 0; i--) { if (this->TokenString[i] == 0xFF) { this->TokenString[i] = 0; if (!i) { // Prepend here, as /dev/urandom says so ;) https://github.com/IW4x/iw4x-client-node/wikis/technical-information#incrementing-the-token this->TokenString = std::basic_string(reinterpret_cast("\0"), 1) + this->TokenString; break; } } else { this->TokenString[i]++; break; } } } return *this; } Token operator++ (int) { Token result = *this; ++(*this); return result; } std::string ToString() { auto str = this->ToUnsignedString(); return std::string(str.begin(), str.end()); } std::basic_string ToUnsignedString() { return this->TokenString; } private: std::basic_string TokenString; }; class Rand { public: static uint32_t GenerateInt(); static void Initialize(); private: static prng_state State; }; class ECDSA { public: class Key { public: Key() : KeyStorage(new ecc_key) { ZeroMemory(this->KeyStorage.get(), sizeof(*this->GetKeyPtr())); }; Key(ecc_key* key) : Key() { if(key) std::memmove(this->GetKeyPtr(), key, sizeof(*key)); }; Key(ecc_key key) : Key(&key) {}; ~Key() { if (this->KeyStorage.use_count() <= 1) { this->Free(); } }; bool IsValid() { return (!Utils::MemIsSet(this->GetKeyPtr(), 0, sizeof(*this->GetKeyPtr()))); } ecc_key* GetKeyPtr() { return this->KeyStorage.get(); } std::string GetPublicKey() { uint8_t buffer[512] = { 0 }; DWORD length = sizeof(buffer); if (ecc_ansi_x963_export(this->GetKeyPtr(), buffer, &length) == CRYPT_OK) { return std::string(reinterpret_cast(buffer), length); } return ""; } void Set(std::string pubKeyBuffer) { this->Free(); if (ecc_ansi_x963_import(reinterpret_cast(pubKeyBuffer.data()), pubKeyBuffer.size(), this->GetKeyPtr()) != CRYPT_OK) { ZeroMemory(this->KeyStorage.get(), sizeof(*this->GetKeyPtr())); } } void Import(std::string key, int type = PK_PRIVATE) { this->Free(); if (ecc_import(reinterpret_cast(key.data()), key.size(), this->GetKeyPtr()) != CRYPT_OK) { ZeroMemory(this->KeyStorage.get(), sizeof(*this->GetKeyPtr())); } } std::string Export(int type = PK_PRIVATE) { uint8_t buffer[4096] = { 0 }; DWORD length = sizeof(buffer); if (ecc_export(buffer, &length, type, this->GetKeyPtr()) == CRYPT_OK) { return std::string(reinterpret_cast(buffer), length); } return ""; } void Free() { if (this->IsValid()) { ecc_free(this->GetKeyPtr()); } ZeroMemory(this->GetKeyPtr(), sizeof(*this->GetKeyPtr())); } private: std::shared_ptr KeyStorage; }; static Key GenerateKey(int bits); static std::string SignMessage(Key key, std::string message); static bool VerifyMessage(Key key, std::string message, std::string signature); }; class RSA { public: class Key { public: Key() : KeyStorage(new rsa_key) { ZeroMemory(this->KeyStorage.get(), sizeof(*this->GetKeyPtr())); }; Key(rsa_key* key) : Key() { if (key) std::memmove(this->GetKeyPtr(), key, sizeof(*key)); }; Key(rsa_key key) : Key(&key) {}; ~Key() { if (this->KeyStorage.use_count() <= 1) { this->Free(); } }; rsa_key* GetKeyPtr() { return this->KeyStorage.get(); } bool IsValid() { return (!Utils::MemIsSet(this->GetKeyPtr(), 0, sizeof(*this->GetKeyPtr()))); } void Free() { if (this->IsValid()) { rsa_free(this->GetKeyPtr()); } ZeroMemory(this->GetKeyPtr(), sizeof(*this->GetKeyPtr())); } private: std::shared_ptr KeyStorage; }; static Key GenerateKey(int bits); static std::string SignMessage(Key key, std::string message); static bool VerifyMessage(Key key, std::string message, std::string signature); }; } }