From 26a690d822b5cd0af131328ac44e311bdf7c6332 Mon Sep 17 00:00:00 2001 From: Muhammad Usman Date: Fri, 17 Mar 2023 10:05:11 +0500 Subject: [PATCH 1/3] crypto algorithms added --- .gitmodules | 3 +++ Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d94c5a1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1"] + path = Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 + url = https://github.com/bitcoin-core/secp256k1 diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 new file mode 160000 index 0000000..e1817a6 --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 @@ -0,0 +1 @@ +Subproject commit e1817a6f54faa20bc7f40d5a9a98a815bd6b6f57 From daf8505eabda5b24d59c74b898db15949aaceeea Mon Sep 17 00:00:00 2001 From: Muhammad Usman Date: Fri, 17 Mar 2023 10:06:50 +0500 Subject: [PATCH 2/3] session management updates --- .../Source/Web3AuthSDK/Private/ECCrypto.cpp | 230 ++++++++++++++++++ .../Source/Web3AuthSDK/Private/Keccak256.cpp | 101 ++++++++ .../Web3AuthSDK/Private/KeyStoreUtils.cpp | 30 +++ .../Source/Web3AuthSDK/Private/Web3Auth.cpp | 116 ++++++++- .../Web3AuthSDK/Private/Web3AuthApi.cpp | 82 +++++++ .../Source/Web3AuthSDK/Public/ECCrypto.h | 45 ++++ .../Source/Web3AuthSDK/Public/Keccak256.h | 41 ++++ .../Source/Web3AuthSDK/Public/KeyStoreUtils.h | 33 +++ .../Source/Web3AuthSDK/Public/Web3Auth.h | 32 ++- .../Source/Web3AuthSDK/Public/Web3AuthApi.h | 61 +++++ .../Source/Web3AuthSDK/Public/secp256k1 | 1 - .../Source/Web3AuthSDK/Web3AuthSDK.Build.cs | 28 ++- 12 files changed, 792 insertions(+), 8 deletions(-) create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/ECCrypto.cpp create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Keccak256.cpp create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/KeyStoreUtils.cpp create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/ECCrypto.h create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Keccak256.h create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/KeyStoreUtils.h create mode 100644 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3AuthApi.h delete mode 160000 Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/ECCrypto.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/ECCrypto.cpp new file mode 100644 index 0000000..c77866b --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/ECCrypto.cpp @@ -0,0 +1,230 @@ +#include "ECCrypto.h" +#include +#include +#include + +#pragma comment(lib, "crypt32.lib") +#pragma comment(lib, "WS2_32.lib") + + +unsigned char* toByteArray(const std::string& s) { + size_t len = s.length() / 2; + unsigned char* data = new unsigned char[len]; + + for (size_t i = 0; i < len * 2; i += 2) { + int hi = std::stoi(s.substr(i, 1), nullptr, 16); + int lo = std::stoi(s.substr(i + 1, 1), nullptr, 16); + data[i / 2] = (unsigned char)((hi << 4) + lo); + } + + return data; + +} + +char* FStringToCharArray(const FString& InString) { + char* CharArray = new char[InString.Len() + 1]; + + strcpy(CharArray, TCHAR_TO_ANSI(*InString)); + return CharArray; +} + +UECCrypto::UECCrypto() { +} + +FString UECCrypto::decrypt(FString data, FString privateKeyHex, FString ephemPublicKeyHex, FString encryptionIvHex) +{ + // Convert to bytes array + const char* priv_hex = FStringToCharArray(privateKeyHex); + const char* pub_hex = FStringToCharArray(ephemPublicKeyHex); + + // Decode IV key + const unsigned char* iv = toByteArray(FStringToCharArray(encryptionIvHex)); + + // Decode cipher text + const unsigned char* src = toByteArray(FStringToCharArray(data)); + int srclen = data.Len() / 2; + + // Convert to BIGNUM + BIGNUM* priv_bn = BN_new(); + BIGNUM* pub_bn = BN_new(); + BN_hex2bn(&priv_bn, priv_hex); + BN_hex2bn(&pub_bn, pub_hex); + + // Create EC_KEY objects from the BIGNUMs + EC_KEY* priv_key = EC_KEY_new_by_curve_name(NID_secp256k1); + EC_KEY* pub_key = EC_KEY_new_by_curve_name(NID_secp256k1); + EC_KEY_set_private_key(priv_key, priv_bn); + EC_KEY_set_public_key(pub_key, EC_POINT_bn2point(EC_KEY_get0_group(pub_key), pub_bn, NULL, NULL)); + + // Create the shared secret + unsigned char* secret = new unsigned char[32]; + int secret_len = ECDH_compute_key(secret, EVP_MAX_KEY_LENGTH, EC_KEY_get0_public_key(pub_key), priv_key, NULL); + + // Calculate SHA-512 hash of secret + unsigned char hash[SHA512_DIGEST_LENGTH]; + SHA512(secret, 32, hash); + + // Copy first 32 bytes of the hash into a new buffer + unsigned char key[32]; + memcpy(key, hash, 32); + + // Create a new encryption context for AES-256 CBC mode with the key and IV + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); + + // Allocate a string buffer for the decrypted data + std::string dst; + dst.resize(srclen + EVP_CIPHER_block_size(EVP_aes_256_cbc())); + + // Decrypt the input data + int outlen; + EVP_DecryptUpdate(ctx, (unsigned char*)dst.data(), &outlen, src, srclen); + + // Finalize the decryption and retrieve any remaining data + int finaloutlen; + EVP_DecryptFinal_ex(ctx, (unsigned char*)dst.data() + outlen, &finaloutlen); + + // Resize the buffer to the actual decrypted length + dst.resize(outlen + finaloutlen); + + // Free the encryption context + EVP_CIPHER_CTX_free(ctx); + + // Clean up resources + BN_free(priv_bn); + BN_free(pub_bn); + EC_KEY_free(priv_key); + EC_KEY_free(pub_key); + EVP_cleanup(); + + return FString(dst.c_str()); +} + +FString UECCrypto::encrypt(FString data, FString privateKeyHex, FString ephemPublicKeyHex, FString encryptionIvHex) +{ + // Convert to bytes array + const char* priv_hex = FStringToCharArray(privateKeyHex); + const char* pub_hex = FStringToCharArray(ephemPublicKeyHex); + + // Decode IV key + const unsigned char* iv = toByteArray(FStringToCharArray(encryptionIvHex)); + + // Decode cipher text + const unsigned char* src = (unsigned char*)FStringToCharArray(data); + int srclen = data.Len() / 2; + + // Convert to BIGNUM + BIGNUM* priv_bn = BN_new(); + BIGNUM* pub_bn = BN_new(); + BN_hex2bn(&priv_bn, priv_hex); + BN_hex2bn(&pub_bn, pub_hex); + + // Create EC_KEY objects from the BIGNUMs + EC_KEY* priv_key = EC_KEY_new_by_curve_name(NID_secp256k1); + EC_KEY* pub_key = EC_KEY_new_by_curve_name(NID_secp256k1); + EC_KEY_set_private_key(priv_key, priv_bn); + EC_KEY_set_public_key(pub_key, EC_POINT_bn2point(EC_KEY_get0_group(pub_key), pub_bn, NULL, NULL)); + + // Create the shared secret + unsigned char* secret = new unsigned char[32]; + int secret_len = ECDH_compute_key(secret, EVP_MAX_KEY_LENGTH, EC_KEY_get0_public_key(pub_key), priv_key, NULL); + + // Calculate SHA-512 hash of secret + unsigned char hash[SHA512_DIGEST_LENGTH]; + SHA512(secret, 32, hash); + + // Copy first 32 bytes of the hash into a new buffer + unsigned char key[32]; + memcpy(key, hash, 32); + + // Create a new encryption context for AES-256 CBC mode with the key and IV + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); + + // Allocate a string buffer for the decrypted data + std::string dst; + dst.resize(srclen + EVP_CIPHER_block_size(EVP_aes_256_cbc())); + + // Decrypt the input data + int outlen; + EVP_EncryptUpdate(ctx, (unsigned char*)dst.data(), &outlen, src, srclen); + + // Finalize the decryption and retrieve any remaining data + int finaloutlen; + EVP_EncryptFinal_ex(ctx, (unsigned char*)dst.data() + outlen, &finaloutlen); + + // Resize the buffer to the actual decrypted length + dst.resize(outlen + finaloutlen); + + // Free the encryption context + EVP_CIPHER_CTX_free(ctx); + + // Clean up resources + BN_free(priv_bn); + BN_free(pub_bn); + EC_KEY_free(priv_key); + EC_KEY_free(pub_key); + EVP_cleanup(); + + return FString(UTF8_TO_TCHAR(dst.c_str())); +} + +FString UECCrypto::generatePublicKey(const FString& privateKeyHex) { + BIGNUM* bn_private_key = NULL; + BN_hex2bn(&bn_private_key, TCHAR_TO_ANSI(*privateKeyHex)); + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); + EC_KEY_set_private_key(ec_key, bn_private_key); + + EC_POINT* ec_point = EC_POINT_new(EC_KEY_get0_group(ec_key)); + EC_POINT_mul(EC_KEY_get0_group(ec_key), ec_point, EC_KEY_get0_private_key(ec_key), NULL, NULL, NULL); + EC_KEY_set_public_key(ec_key, ec_point); + + BIGNUM* bn = EC_POINT_point2bn(EC_KEY_get0_group(ec_key), EC_KEY_get0_public_key(ec_key), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); + + char* hex = BN_bn2hex(bn); + FString result(UTF8_TO_TCHAR(hex)); + + OPENSSL_free(hex); + BN_free(bn_private_key); + + return result.ToLower(); +} + +FString UECCrypto::generateECDSASignature(const FString& privateKeyHex, const FString& data) { + // Initialize OpenSSL's elliptic curve library + EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1); + + BIGNUM* priv_bn = BN_new(); + BN_hex2bn(&priv_bn, FStringToCharArray(privateKeyHex)); + + EC_KEY_set_private_key(key, priv_bn); + + const unsigned char* msg = (const unsigned char* ) FStringToCharArray(data); + size_t msglen = data.Len(); + + unsigned char hash[SHA256_DIGEST_LENGTH]; + Keccak256::getHash(msg, msglen, hash); + + unsigned char* sig_buf = nullptr; + + ECDSA_SIG* signature = ECDSA_do_sign(hash, SHA256_DIGEST_LENGTH, key); + int n = i2d_ECDSA_SIG(signature, &sig_buf); + + //// Convert signature to hex string + FString signature_hex; + for (int i = 0; i < n; ++i) { + signature_hex += FString::Printf(TEXT("%02x"), sig_buf[i]); + } + + EC_KEY_free(key); + ECDSA_SIG_free(signature); + + return signature_hex; +} + +UECCrypto::~UECCrypto() +{ +} + + diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Keccak256.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Keccak256.cpp new file mode 100644 index 0000000..1292c69 --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Keccak256.cpp @@ -0,0 +1,101 @@ +/* + * Bitcoin cryptography library + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/bitcoin-cryptography-library + * https://github.com/nayuki/Bitcoin-Cryptography-Library + */ + +#include "Keccak256.h" +#include + +using std::uint8_t; +using std::uint64_t; +using std::size_t; + + +void Keccak256::getHash(const uint8_t msg[], size_t len, uint8_t hashResult[HASH_LEN]) { + assert((msg != nullptr || len == 0) && hashResult != nullptr); + uint64_t state[5][5] = {}; + + // XOR each message byte into the state, and absorb full blocks + int blockOff = 0; + for (size_t i = 0; i < len; i++) { + int j = blockOff >> 3; + state[j % 5][j / 5] ^= static_cast(msg[i]) << ((blockOff & 7) << 3); + blockOff++; + if (blockOff == BLOCK_SIZE) { + absorb(state); + blockOff = 0; + } + } + + // Final block and padding + { + int i = blockOff >> 3; + state[i % 5][i / 5] ^= UINT64_C(0x01) << ((blockOff & 7) << 3); + blockOff = BLOCK_SIZE - 1; + int j = blockOff >> 3; + state[j % 5][j / 5] ^= UINT64_C(0x80) << ((blockOff & 7) << 3); + absorb(state); + } + + // Uint64 array to bytes in little endian + for (int i = 0; i < HASH_LEN; i++) { + int j = i >> 3; + hashResult[i] = static_cast(state[j % 5][j / 5] >> ((i & 7) << 3)); + } +} + + +void Keccak256::absorb(uint64_t state[5][5]) { + uint64_t(*a)[5] = state; + uint8_t r = 1; // LFSR + for (int i = 0; i < NUM_ROUNDS; i++) { + // Theta step + uint64_t c[5] = {}; + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) + c[x] ^= a[x][y]; + } + for (int x = 0; x < 5; x++) { + uint64_t d = c[(x + 4) % 5] ^ rotl64(c[(x + 1) % 5], 1); + for (int y = 0; y < 5; y++) + a[x][y] ^= d; + } + + // Rho and pi steps + uint64_t b[5][5]; + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) + b[y][(x * 2 + y * 3) % 5] = rotl64(a[x][y], ROTATION[x][y]); + } + + // Chi step + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) + a[x][y] = b[x][y] ^ (~b[(x + 1) % 5][y] & b[(x + 2) % 5][y]); + } + + // Iota step + for (int j = 0; j < 7; j++) { + a[0][0] ^= static_cast(r & 1) << ((1 << j) - 1); + r = static_cast((r << 1) ^ ((r >> 7) * 0x171)); + } + } +} + + +uint64_t Keccak256::rotl64(uint64_t x, int i) { + return ((0U + x) << i) | (x >> ((64 - i) & 63)); +} + + +// Static initializers +const unsigned char Keccak256::ROTATION[5][5] = { + { 0, 36, 3, 41, 18}, + { 1, 44, 10, 45, 2}, + {62, 6, 43, 15, 61}, + {28, 55, 25, 21, 56}, + {27, 20, 39, 8, 14}, +}; \ No newline at end of file diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/KeyStoreUtils.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/KeyStoreUtils.cpp new file mode 100644 index 0000000..b0e3a32 --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/KeyStoreUtils.cpp @@ -0,0 +1,30 @@ +#include "KeyStoreUtils.h" + +UKeyStoreUtils::UKeyStoreUtils() { + StorageInstance = Cast(UGameplayStatics::LoadGameFromSlot(TEXT("Web3AuthDataSlot"), 0)); + if(StorageInstance == nullptr) { + StorageInstance = Cast(UGameplayStatics::CreateSaveGameObject(UWeb3StorageAdapter::StaticClass())); + } +} + +UKeyStoreUtils::~UKeyStoreUtils() { +} + +void UKeyStoreUtils::Add(FString key, FString value) { + StorageInstance->KeyValuePairs.Add(key, value); + UGameplayStatics::SaveGameToSlot(StorageInstance, TEXT("Web3AuthDataSlot"), 0); +} + +FString UKeyStoreUtils::Get(FString key) { + if (StorageInstance->KeyValuePairs.Contains(key)) { + return StorageInstance->KeyValuePairs[key]; + } + return ""; +} + +void UKeyStoreUtils::Remove(FString key) { + if (StorageInstance->KeyValuePairs.Contains(key)) { + StorageInstance->KeyValuePairs.Remove(key); + UGameplayStatics::SaveGameToSlot(StorageInstance, TEXT("Web3AuthDataSlot"), 0); + } +} diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp index eb86d7e..0921378 100644 --- a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp @@ -1,4 +1,4 @@ -// Fill out your copyright notice in the Description page of Project Settings. +// Fill out your copyright notice in the Description page of Project Settings. #include "Web3Auth.h" @@ -10,6 +10,9 @@ FOnLogin AWeb3Auth::loginEvent; FOnLogout AWeb3Auth::logoutEvent; +UKeyStoreUtils* AWeb3Auth::keyStoreUtils; +UECCrypto* AWeb3Auth::crypto; + #if PLATFORM_ANDROID JNI_METHOD void Java_com_epicgames_unreal_GameActivity_onDeepLink(JNIEnv* env, jclass clazz, jstring uri) { if (JNIEnv* Env = FAndroidApplication::GetJavaEnv(true)) { @@ -44,6 +47,10 @@ AWeb3Auth::AWeb3Auth() void AWeb3Auth::setOptions(FWeb3AuthOptions options) { this->web3AuthOptions = options; + this->keyStoreUtils = NewObject(); + this->crypto = NewObject(); + + authorizeSession(); } void AWeb3Auth::request(FString path, FLoginParams* loginParams = NULL, TSharedPtr extraParams = NULL) { @@ -161,7 +168,8 @@ void AWeb3Auth::proccessLogout(FString redirectUrl, FString appState) { if (appState != "") extraParams->SetStringField("appState", appState); - this->request("logout", NULL, extraParams); + //this->request("logout", NULL, extraParams); + sessionTimeout(); } void AWeb3Auth::setResultUrl(FString hash) { @@ -207,6 +215,7 @@ void AWeb3Auth::setResultUrl(FString hash) { }); } else { + AWeb3Auth::keyStoreUtils->Add("sessionid", web3AuthResponse.sessionId); AsyncTask(ENamedThreads::GameThread, [=]() { AWeb3Auth::loginEvent.ExecuteIfBound(web3AuthResponse); }); @@ -347,6 +356,109 @@ void AWeb3Auth::EndPlay(const EEndPlayReason::Type EndPlayReason) { httpRoutes.Empty(); } +void AWeb3Auth::authorizeSession() { + FString sessionId = AWeb3Auth::keyStoreUtils->Get("sessionid"); + if (!sessionId.IsEmpty()) { + FString pubKey = crypto->generatePublicKey(sessionId); + UE_LOG(LogTemp, Log, TEXT("public key %s"), *pubKey); + + web3AuthApi->AuthorizeSession(pubKey, [](FStoreApiResponse response) + { + UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response.message); + }); + + FString jsonString = "{\"iv\":\"e9b09a4e58c0763c6c6547ed76f3c481\",\"ephemPublicKey\":\"044d52f016e2b7374381e0bf48b240803083702c7739afc36766c6f62f3080cb0c3b0a1da22f3644ad5d447c9d494b78ad82271043729d8fc373b8754c4eb8f5b3\",\"ciphertext\":\"3b1a647d7203dbeeac8e538164465d4040fe1697e15ea881c3e1926595dd92332226e04e3512b0b4934ee403b058be1da5934d8d44f7137f121084c433b190865483dab1baaf372468ecb511404519b56aca6eaaf4a69aaa8add30145a4795ed20da83b8689f1c175e8e8d95e5a798925b86768f83baa6dbb4f81fc92f1113ee2241691211bcadb6b7d2e7635ec5c9ef06f136f2e647844d31b6895402bcf1802ba08412bcf553a92e188ead80c212197ad053e8c4fbed67039e683d177b48121d8b823015d6e5dc850b50aaa2e95ca2af5f6951153386e0f98621332b2495caf45abe8a0b49790ca1b1e05c3af55138612682efd4d28367cbfbd273c95292e92a2ff073946ca689a2e6b9709a4b08ce2782c57f871f3c13fea55add85a32441d22d8ce56de588eebf55e3132bcaa1d03a6ca48726de6e05047c9fabbb7f4aeef0501fbcaa839a73ea9ce6b3947511f1cb341db8af35b3c2ab89365e784b0f1485fc3be2f7723541cce55ae3ede78efb09ecca8918b0514c620ce56e41efa98e715f91d04e813f27b78bec10da61e9259b1ec7aca2c3fb062590dda5ca510c3800955988830c0173dc2f5d911bfcb0fc1d23881a21df03f5e0e3a8a040ac223fce20199e47a8a1d16d511fa3758a937984f47a111f7da8bd6d87ff484b3c0b98fc889bd75a3893d16e51dcf1d493c4fb99f194cd474a77a7fce541c99a3924a5be5bd78477082f40bf3771f76d8a150372fbcf64a8a19f990a3170ae5867c168f371a28df90e78e31420eba031aff880b46cc9c96021dca5d975baba412e396f74092e360d62f72fea547e7698e80442ee251246627e0a095b72c374ce5da4cb877e49f8acefa442987028f8a3aed5a41e95752b4c70af8fcd995310b3c3f68104fd05bd3546e78624d61f1fd46dbd26add39207501fd4f16a07d57eeded8d5ed91b50f25ce8993c982ecde5cffa09f94c70843f3c61749920ded84e0de345361605e8a2b9054359d76901c8f6ea0df09f81f91b7e6e88d0cc5e2e07facebb57fce27f433406cdcc03397da92ecd6b26a0a79c760e913a562520fb3b0e9b944e027d854891726176f860474a105eb44a49f86d284c24f7d4b20e5a8e265f23f01c6ab166a7cdf4ef2f65e95860654f083b4b72f00b593bc74e269ef49c33bc3fe7fdaab84744c69b247a9f77dac681ceff5cba1f225d5bc62f582a6fd64b5d942c8fd03883e7d0618cbb87647eb4c037964e1cef35ab42423ab375005678b80cd9d5c6f9b574d32489339583dba81be4f637d898dcd350ddfd38bf18f67636dcc398a0e16c984d7c7f5dee6e2bb8b7b63d9c581e47da06c5c6734de858a12d3c2ab09b38163d3be1741195c4eb07152f38e5fc65372807d5517ff2f8ebb047a5868b773983f78d663140c6532dd09078ae54b1c9fedf3e2a2ba9857010ee6c4ee09533a0df2418e523b3e5f9e297e22a0de3ed398e8302b95507689833476679577b479266a5b1b65d95227f36451dad497eeec9838778c59c7ebdc3989c20e66f423fde732ad5a9a85cbd71e9418903787d09db4526b4d6f987ace4874309b9a52d635bdccbd2734dc73a4cfbf373d601a7e6e7c8eb075b6438bb329528426a63b0392896c064b86de68a004842a1380feb4710a5e6ffe7df13e5540d0d1b4f77d007d8d76427c985fd0a6a31b92a400bd24a6edd69c507687448bdc7c2e556753a2f62fce9e7d7525a9f90b5f5572b62f5c38aa954168cadd775782379cfe2846016d437b2a2df58ed8884f90e58fd85109ae8a39ac4802a9ba0a32f707d39e843e419d097e1a24acb05a5ea9305a839a659be5475d58bb89548c5348204ff8aad84138824329605e4363b88b770903057a1231a219223616dc041f1dc279234c3432859e2e94a6b0686ecfa35f02e6ec771f3d60e05b0b619e8be9adff848879e08fc5464ff57b9a12376398b30d7c94120217e9ebdad023911ab7f54fb6c287fda2149ea7f96123b0c92022367baee0089dbd99bf572d79278c235fe51baf6b13f60aa64204d5ed57ac82d5b7251a5d2b93a65fd323f8878e20718489a72ae482356d5a78b11a2c3bfad66a6f5e3fb617256ad0cf989b01144a052d8d5d28295bbe5a61cfcc16475394044678d006488a36110eae7490b1e58fee997098b63e65eb917d7236e77f909d0fa47771d1d57c68d931e26760f010582dd4d8493b3181eee36679c2aa3d9af2dccfa8fbc2fd5b380de2bf27e38f1b6ef8537c940cac5cdb5517142f86ab9c6dd26cfb9ad7bbc96b8a750c9f1713d623599642db6d79b2f0c62ce69ff042d73afca214504e2a9da7d30ff17bc5abffaa6895bdb34e3af9aced0af52c2c3944ec2e9aa3619219f662bb3c7b692cc1bd39934807897fb32d8ff08d0aa76aa928c6a094398db968c97d6faea7c4eaf8a2e714199cef772e08e7481fc1033dcacbb8e847aac9c68b021e2ec6b644e3b458e2a456694b6cc7ffffbda8798cba6a9d3f0f9f75e5873eaac006d7f7e7f0619ab44293981dbdf5bac1793561274e435c793f67ae755a7c5256166035e3149da3f03a9bd0504\", \"mac\":\"50bc2e8d29368875bf214eea319f8aa5336337a95d2685359438d84a61bd17a3\"}"; + + FShareMetaData shareMetaData; + + if (!FJsonObjectConverter::JsonObjectStringToUStruct(jsonString, &shareMetaData, 0, 0)) { + UE_LOG(LogTemp, Error, TEXT("failed to parse json")); + return; + } + + FString output = crypto->decrypt(shareMetaData.ciphertext, sessionId, shareMetaData.ephemPublicKey, shareMetaData.iv); + UE_LOG(LogTemp, Log, TEXT("output %s"), *output); + + TSharedPtr tempJson; + TSharedRef> JsonReader = TJsonReaderFactory::Create(output); + + if (FJsonSerializer::Deserialize(JsonReader, tempJson) && tempJson.IsValid()) { + tempJson->SetObjectField("userInfo", tempJson->GetObjectField("store")); + tempJson->RemoveField("store"); + + FString json; + TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&json); + FJsonSerializer::Serialize(tempJson.ToSharedRef(), Writer); + + FWeb3AuthResponse web3AuthResponse; + + if (!FJsonObjectConverter::JsonObjectStringToUStruct(json, &web3AuthResponse, 0, 0)) { + UE_LOG(LogTemp, Error, TEXT("failed to parse json")); + return; + } + + if (web3AuthResponse.error != "") { + return; + } + + AsyncTask(ENamedThreads::GameThread, [=]() { + AWeb3Auth::loginEvent.ExecuteIfBound(web3AuthResponse); + }); + } + } +} + +void AWeb3Auth::sessionTimeout() { + FString sessionId = AWeb3Auth::keyStoreUtils->Get("sessionid"); + + if (!sessionId.IsEmpty()) { + FString pubKey = crypto->generatePublicKey(sessionId); + UE_LOG(LogTemp, Log, TEXT("public key %s"), *pubKey); + + web3AuthApi->AuthorizeSession(pubKey, [](FStoreApiResponse response) + { + UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response.message); + }); + + FString jsonOutput = "{\"iv\":\"e9b09a4e58c0763c6c6547ed76f3c481\",\"ephemPublicKey\":\"044d52f016e2b7374381e0bf48b240803083702c7739afc36766c6f62f3080cb0c3b0a1da22f3644ad5d447c9d494b78ad82271043729d8fc373b8754c4eb8f5b3\",\"ciphertext\":\"3b1a647d7203dbeeac8e538164465d4040fe1697e15ea881c3e1926595dd92332226e04e3512b0b4934ee403b058be1da5934d8d44f7137f121084c433b190865483dab1baaf372468ecb511404519b56aca6eaaf4a69aaa8add30145a4795ed20da83b8689f1c175e8e8d95e5a798925b86768f83baa6dbb4f81fc92f1113ee2241691211bcadb6b7d2e7635ec5c9ef06f136f2e647844d31b6895402bcf1802ba08412bcf553a92e188ead80c212197ad053e8c4fbed67039e683d177b48121d8b823015d6e5dc850b50aaa2e95ca2af5f6951153386e0f98621332b2495caf45abe8a0b49790ca1b1e05c3af55138612682efd4d28367cbfbd273c95292e92a2ff073946ca689a2e6b9709a4b08ce2782c57f871f3c13fea55add85a32441d22d8ce56de588eebf55e3132bcaa1d03a6ca48726de6e05047c9fabbb7f4aeef0501fbcaa839a73ea9ce6b3947511f1cb341db8af35b3c2ab89365e784b0f1485fc3be2f7723541cce55ae3ede78efb09ecca8918b0514c620ce56e41efa98e715f91d04e813f27b78bec10da61e9259b1ec7aca2c3fb062590dda5ca510c3800955988830c0173dc2f5d911bfcb0fc1d23881a21df03f5e0e3a8a040ac223fce20199e47a8a1d16d511fa3758a937984f47a111f7da8bd6d87ff484b3c0b98fc889bd75a3893d16e51dcf1d493c4fb99f194cd474a77a7fce541c99a3924a5be5bd78477082f40bf3771f76d8a150372fbcf64a8a19f990a3170ae5867c168f371a28df90e78e31420eba031aff880b46cc9c96021dca5d975baba412e396f74092e360d62f72fea547e7698e80442ee251246627e0a095b72c374ce5da4cb877e49f8acefa442987028f8a3aed5a41e95752b4c70af8fcd995310b3c3f68104fd05bd3546e78624d61f1fd46dbd26add39207501fd4f16a07d57eeded8d5ed91b50f25ce8993c982ecde5cffa09f94c70843f3c61749920ded84e0de345361605e8a2b9054359d76901c8f6ea0df09f81f91b7e6e88d0cc5e2e07facebb57fce27f433406cdcc03397da92ecd6b26a0a79c760e913a562520fb3b0e9b944e027d854891726176f860474a105eb44a49f86d284c24f7d4b20e5a8e265f23f01c6ab166a7cdf4ef2f65e95860654f083b4b72f00b593bc74e269ef49c33bc3fe7fdaab84744c69b247a9f77dac681ceff5cba1f225d5bc62f582a6fd64b5d942c8fd03883e7d0618cbb87647eb4c037964e1cef35ab42423ab375005678b80cd9d5c6f9b574d32489339583dba81be4f637d898dcd350ddfd38bf18f67636dcc398a0e16c984d7c7f5dee6e2bb8b7b63d9c581e47da06c5c6734de858a12d3c2ab09b38163d3be1741195c4eb07152f38e5fc65372807d5517ff2f8ebb047a5868b773983f78d663140c6532dd09078ae54b1c9fedf3e2a2ba9857010ee6c4ee09533a0df2418e523b3e5f9e297e22a0de3ed398e8302b95507689833476679577b479266a5b1b65d95227f36451dad497eeec9838778c59c7ebdc3989c20e66f423fde732ad5a9a85cbd71e9418903787d09db4526b4d6f987ace4874309b9a52d635bdccbd2734dc73a4cfbf373d601a7e6e7c8eb075b6438bb329528426a63b0392896c064b86de68a004842a1380feb4710a5e6ffe7df13e5540d0d1b4f77d007d8d76427c985fd0a6a31b92a400bd24a6edd69c507687448bdc7c2e556753a2f62fce9e7d7525a9f90b5f5572b62f5c38aa954168cadd775782379cfe2846016d437b2a2df58ed8884f90e58fd85109ae8a39ac4802a9ba0a32f707d39e843e419d097e1a24acb05a5ea9305a839a659be5475d58bb89548c5348204ff8aad84138824329605e4363b88b770903057a1231a219223616dc041f1dc279234c3432859e2e94a6b0686ecfa35f02e6ec771f3d60e05b0b619e8be9adff848879e08fc5464ff57b9a12376398b30d7c94120217e9ebdad023911ab7f54fb6c287fda2149ea7f96123b0c92022367baee0089dbd99bf572d79278c235fe51baf6b13f60aa64204d5ed57ac82d5b7251a5d2b93a65fd323f8878e20718489a72ae482356d5a78b11a2c3bfad66a6f5e3fb617256ad0cf989b01144a052d8d5d28295bbe5a61cfcc16475394044678d006488a36110eae7490b1e58fee997098b63e65eb917d7236e77f909d0fa47771d1d57c68d931e26760f010582dd4d8493b3181eee36679c2aa3d9af2dccfa8fbc2fd5b380de2bf27e38f1b6ef8537c940cac5cdb5517142f86ab9c6dd26cfb9ad7bbc96b8a750c9f1713d623599642db6d79b2f0c62ce69ff042d73afca214504e2a9da7d30ff17bc5abffaa6895bdb34e3af9aced0af52c2c3944ec2e9aa3619219f662bb3c7b692cc1bd39934807897fb32d8ff08d0aa76aa928c6a094398db968c97d6faea7c4eaf8a2e714199cef772e08e7481fc1033dcacbb8e847aac9c68b021e2ec6b644e3b458e2a456694b6cc7ffffbda8798cba6a9d3f0f9f75e5873eaac006d7f7e7f0619ab44293981dbdf5bac1793561274e435c793f67ae755a7c5256166035e3149da3f03a9bd0504\", \"mac\":\"50bc2e8d29368875bf214eea319f8aa5336337a95d2685359438d84a61bd17a3\"}"; + + FShareMetaData shareMetaData; + + if (!FJsonObjectConverter::JsonObjectStringToUStruct(jsonOutput, &shareMetaData, 0, 0)) { + UE_LOG(LogTemp, Error, TEXT("failed to parse json")); + return; + } + + FString encryptedData = crypto->encrypt("", sessionId, shareMetaData.ephemPublicKey, shareMetaData.iv); + shareMetaData.ciphertext = encryptedData; + + + TSharedPtr jsonObject = MakeShareable(new FJsonObject); + FJsonObjectConverter::UStructToJsonObject(FShareMetaData::StaticStruct(), &shareMetaData, jsonObject.ToSharedRef(), 0, 0); + + FString jsonString; + TSharedRef> jsonWriter = TJsonWriterFactory<>::Create(&jsonString); + FJsonSerializer::Serialize(jsonObject.ToSharedRef(), jsonWriter); + + FLogoutApiRequest request; + request.data = jsonString; + request.key = pubKey; + request.signature = crypto->generateECDSASignature(sessionId, jsonString); + request.timeout = 1; + + web3AuthApi->Logout(request, [](FString response) + { + UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response); + AWeb3Auth::keyStoreUtils->Remove("sessionId"); + AsyncTask(ENamedThreads::GameThread, [=]() { + AWeb3Auth::logoutEvent.ExecuteIfBound(); + }); + }); + + } +} + + void AWeb3Auth::Tick(float DeltaTime) { Super::Tick(DeltaTime); } diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp new file mode 100644 index 0000000..53a301d --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp @@ -0,0 +1,82 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Web3AuthApi.h" +#include "GenericPlatform/GenericPlatformHttp.h" + +UWeb3AuthApi* UWeb3AuthApi::Instance = nullptr; + +UWeb3AuthApi* UWeb3AuthApi::GetInstance() +{ + if (!Instance) { + Instance = NewObject(); + } + return Instance; +} + + +void UWeb3AuthApi::AuthorizeSession(const FString& key, const TFunction callback) +{ + TSharedRef request = FHttpModule::Get().CreateRequest(); + request->SetVerb(TEXT("GET")); + request->SetURL(TEXT("https://broadcast-server.tor.us/store/get?key=" + key)); + auto headers = request->GetAllHeaders(); + for (auto header : headers) { + UE_LOG(LogTemp, Log, TEXT("length: %s %s"), *header); + + } + + + request->OnProcessRequestComplete().BindLambda([callback](FHttpRequestPtr request, FHttpResponsePtr response, bool success) { + FString response_string = response->GetContentAsString(); + FString url = request->GetURL(); + UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response_string); + + if (success && response->GetResponseCode() == EHttpResponseCodes::Ok) { + FStoreApiResponse api_response; + if (FJsonObjectConverter::JsonObjectStringToUStruct(response_string, &api_response, 0, 0)) { + callback(api_response); + } + else { + UE_LOG(LogTemp, Error, TEXT("Failed to parse response")); + } + } + else { + UE_LOG(LogTemp, Error, TEXT("Request failed")); + } + }); + + request->ProcessRequest(); +} + +void UWeb3AuthApi::Logout(const FLogoutApiRequest logoutApiRequest, const TFunction callback) +{ + TSharedRef request = FHttpModule::Get().CreateRequest(); + request->SetVerb(TEXT("POST")); + request->SetURL(TEXT("https://broadcast-server.tor.us/store/set")); + + FString FormString = "key=" + logoutApiRequest.key + "&data=" + FGenericPlatformHttp::UrlEncode(logoutApiRequest.data) + "&signature=" + logoutApiRequest.signature + "&timeout=" + FString::FromInt(logoutApiRequest.timeout); + UE_LOG(LogTemp, Error, TEXT("%s"), *FormString); + + request->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded")); + request->SetContentAsString(FormString); + + request->OnProcessRequestComplete().BindLambda([callback](FHttpRequestPtr request, FHttpResponsePtr response, bool success) { + FString response_string = response->GetContentAsString(); + UE_LOG(LogTemp, Log, TEXT("Response: %s "), *response_string); + UE_LOG(LogTemp, Log, TEXT("Status code: %d "), response->GetResponseCode()); + + if (success && response->GetResponseCode() == EHttpResponseCodes::Created) { + callback(response_string); + } + else { + UE_LOG(LogTemp, Error, TEXT("Request failed")); + } + }); + + request->ProcessRequest(); +} + +UWeb3AuthApi::UWeb3AuthApi() +{ +} diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/ECCrypto.h b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/ECCrypto.h new file mode 100644 index 0000000..f6650f9 --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/ECCrypto.h @@ -0,0 +1,45 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" + +#pragma warning(disable:4996) +#pragma comment(lib,"WS2_32.Lib") //Winsock Library + +#define UI UI_ST +THIRD_PARTY_INCLUDES_START +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +THIRD_PARTY_INCLUDES_END +#undef UI + +#include "Misc/SecureHash.h" +#include +#include "Keccak256.h" + +#include "ECCrypto.generated.h" + +UCLASS() +class WEB3AUTHSDK_API UECCrypto : public UObject +{ + GENERATED_BODY() +public: + UECCrypto(); + ~UECCrypto(); + + FString decrypt(FString data, FString privateKeyHex, FString ephemPublicKeyHex, FString encryptionIvHex); + FString encrypt(FString data, FString privateKeyHex, FString ephemPublicKeyHex, FString encryptionIvHex); + + FString generatePublicKey(const FString& privateKeyHex); + FString generateECDSASignature(const FString& privateKeyHex, const FString& data); +}; diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Keccak256.h b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Keccak256.h new file mode 100644 index 0000000..ccbb170 --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Keccak256.h @@ -0,0 +1,41 @@ +/* + * Bitcoin cryptography library + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/bitcoin-cryptography-library + * https://github.com/nayuki/Bitcoin-Cryptography-Library + */ + +#pragma once + +#include +#include + + + /* + * Computes the Keccak-256 hash of a sequence of bytes. The hash value is 32 bytes long. + * Provides just one static method. + */ +class Keccak256 final { + +public: static constexpr int HASH_LEN = 32; +private: static constexpr int BLOCK_SIZE = 200 - HASH_LEN * 2; +private: static constexpr int NUM_ROUNDS = 24; + + +public: static void getHash(const std::uint8_t msg[], std::size_t len, std::uint8_t hashResult[HASH_LEN]); + + +private: static void absorb(std::uint64_t state[5][5]); + + + // Requires 0 <= i <= 63 +private: static std::uint64_t rotl64(std::uint64_t x, int i); + + + Keccak256() = delete; // Not instantiable + + +private: static const unsigned char ROTATION[5][5]; + +}; \ No newline at end of file diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/KeyStoreUtils.h b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/KeyStoreUtils.h new file mode 100644 index 0000000..0f7cd4a --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/KeyStoreUtils.h @@ -0,0 +1,33 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/SaveGame.h" +#include "Kismet/GameplayStatics.h" + +#include "KeyStoreUtils.generated.h" + +UCLASS() +class UWeb3StorageAdapter : public USaveGame +{ + GENERATED_BODY() +public: + UPROPERTY() + TMap KeyValuePairs; +}; + +UCLASS() +class WEB3AUTHSDK_API UKeyStoreUtils : public UObject +{ + GENERATED_BODY() +private: + UWeb3StorageAdapter* StorageInstance; +public: + void Add(FString key, FString value); + FString Get(FString key); + void Remove(FString key); +public: + UKeyStoreUtils(); + ~UKeyStoreUtils(); +}; diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3Auth.h b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3Auth.h index f98a7d4..1c730f0 100644 --- a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3Auth.h +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3Auth.h @@ -10,7 +10,9 @@ #include "JsonUtilities.h" #include "Misc/Base64.h" - +#include "KeyStoreUtils.h" +#include "ECCrypto.h" +#include "Web3AuthApi.h" #include "Runtime/Online/HTTPServer/Public/HttpPath.h" @@ -521,6 +523,25 @@ struct FWeb3AuthResponse }; +USTRUCT(BlueprintType) +struct FShareMetaData +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintReadWrite) + FString iv; + + UPROPERTY(BlueprintReadWrite) + FString ephemPublicKey; + + UPROPERTY(BlueprintReadWrite) + FString ciphertext; + + UPROPERTY(BlueprintReadWrite) + FString mac; +}; + DECLARE_DYNAMIC_DELEGATE_OneParam(FOnLogin, FWeb3AuthResponse, response); DECLARE_DYNAMIC_DELEGATE(FOnLogout); @@ -539,6 +560,12 @@ class WEB3AUTHSDK_API AWeb3Auth : public AActor static FOnLogin loginEvent; static FOnLogout logoutEvent; + + static UKeyStoreUtils* keyStoreUtils; + static UECCrypto* crypto; + + UWeb3AuthApi* web3AuthApi = UWeb3AuthApi::GetInstance(); + protected: // Called when the game starts or when spawned virtual void BeginPlay() override; @@ -600,4 +627,7 @@ class WEB3AUTHSDK_API AWeb3Auth : public AActor bool requestAuthCallback(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete); bool requestCompleteCallback(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete); + + void authorizeSession(); + void sessionTimeout(); }; diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3AuthApi.h b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3AuthApi.h new file mode 100644 index 0000000..5198b91 --- /dev/null +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/Web3AuthApi.h @@ -0,0 +1,61 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Http.h" +#include "JsonUtilities.h" + +#include "Web3AuthApi.generated.h" + +USTRUCT() +struct FStoreApiResponse +{ + GENERATED_BODY() + + UPROPERTY() + FString message; + + UPROPERTY() + bool success; +}; + +USTRUCT() +struct FLogoutApiRequest +{ + GENERATED_BODY() + + UPROPERTY() + FString key; + + UPROPERTY() + FString data; + + UPROPERTY() + FString signature; + + UPROPERTY() + int32 timeout; +}; + +UCLASS() +class WEB3AUTHSDK_API UWeb3AuthApi : public UObject +{ + GENERATED_BODY() + +public: + static UWeb3AuthApi* GetInstance(); + + // Authorize the user session + void AuthorizeSession(const FString& key, const TFunction callback); + + // Logout the user session + void Logout(const FLogoutApiRequest logoutApiRequest, const TFunction callback); + +private: + // Private constructor to enforce singleton pattern + UWeb3AuthApi(); + + // Singleton instance of the Web3AuthApi class + static UWeb3AuthApi* Instance; +}; \ No newline at end of file diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 deleted file mode 160000 index e1817a6..0000000 --- a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e1817a6f54faa20bc7f40d5a9a98a815bd6b6f57 diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Web3AuthSDK.Build.cs b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Web3AuthSDK.Build.cs index 5affc4c..dfd4db8 100644 --- a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Web3AuthSDK.Build.cs +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Web3AuthSDK.Build.cs @@ -60,6 +60,7 @@ public Web3AuthSDK(ReadOnlyTargetRules Target) : base(Target) { "Core", // ... add other public dependencies that you statically link with here ... + "OpenSSL" } ); @@ -79,14 +80,33 @@ public Web3AuthSDK(ReadOnlyTargetRules Target) : base(Target) "UMG" } ); - - - DynamicallyLoadedModuleNames.AddRange( + + if (Target.Platform == UnrealTargetPlatform.Win64) + { + PrivateDependencyModuleNames.Add("OpenSSL"); + + if (Target.LinkType == TargetLinkType.Monolithic) + { + PrivateDependencyModuleNames.Add("ws2_32"); + } + else + { + PublicAdditionalLibraries.Add("ws2_32.lib"); + } + } + + DynamicallyLoadedModuleNames.AddRange( new string[] { // ... add any modules that your module loads dynamically here ... } ); - } + PublicDefinitions.AddRange( + new string[] + { + } + ); + + } } From c897045a3335ef46fc7cad3aab61df4d2aadbf53 Mon Sep 17 00:00:00 2001 From: Muhammad Usman Date: Thu, 30 Mar 2023 12:41:16 +0500 Subject: [PATCH 3/3] session api updates --- .../Source/Web3AuthSDK/Private/Web3Auth.cpp | 133 +++++++++--------- .../Web3AuthSDK/Private/Web3AuthApi.cpp | 12 +- 2 files changed, 70 insertions(+), 75 deletions(-) diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp index 0921378..e0db502 100644 --- a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3Auth.cpp @@ -362,49 +362,48 @@ void AWeb3Auth::authorizeSession() { FString pubKey = crypto->generatePublicKey(sessionId); UE_LOG(LogTemp, Log, TEXT("public key %s"), *pubKey); - web3AuthApi->AuthorizeSession(pubKey, [](FStoreApiResponse response) + web3AuthApi->AuthorizeSession(pubKey, [sessionId](FStoreApiResponse response) { UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response.message); - }); - FString jsonString = "{\"iv\":\"e9b09a4e58c0763c6c6547ed76f3c481\",\"ephemPublicKey\":\"044d52f016e2b7374381e0bf48b240803083702c7739afc36766c6f62f3080cb0c3b0a1da22f3644ad5d447c9d494b78ad82271043729d8fc373b8754c4eb8f5b3\",\"ciphertext\":\"3b1a647d7203dbeeac8e538164465d4040fe1697e15ea881c3e1926595dd92332226e04e3512b0b4934ee403b058be1da5934d8d44f7137f121084c433b190865483dab1baaf372468ecb511404519b56aca6eaaf4a69aaa8add30145a4795ed20da83b8689f1c175e8e8d95e5a798925b86768f83baa6dbb4f81fc92f1113ee2241691211bcadb6b7d2e7635ec5c9ef06f136f2e647844d31b6895402bcf1802ba08412bcf553a92e188ead80c212197ad053e8c4fbed67039e683d177b48121d8b823015d6e5dc850b50aaa2e95ca2af5f6951153386e0f98621332b2495caf45abe8a0b49790ca1b1e05c3af55138612682efd4d28367cbfbd273c95292e92a2ff073946ca689a2e6b9709a4b08ce2782c57f871f3c13fea55add85a32441d22d8ce56de588eebf55e3132bcaa1d03a6ca48726de6e05047c9fabbb7f4aeef0501fbcaa839a73ea9ce6b3947511f1cb341db8af35b3c2ab89365e784b0f1485fc3be2f7723541cce55ae3ede78efb09ecca8918b0514c620ce56e41efa98e715f91d04e813f27b78bec10da61e9259b1ec7aca2c3fb062590dda5ca510c3800955988830c0173dc2f5d911bfcb0fc1d23881a21df03f5e0e3a8a040ac223fce20199e47a8a1d16d511fa3758a937984f47a111f7da8bd6d87ff484b3c0b98fc889bd75a3893d16e51dcf1d493c4fb99f194cd474a77a7fce541c99a3924a5be5bd78477082f40bf3771f76d8a150372fbcf64a8a19f990a3170ae5867c168f371a28df90e78e31420eba031aff880b46cc9c96021dca5d975baba412e396f74092e360d62f72fea547e7698e80442ee251246627e0a095b72c374ce5da4cb877e49f8acefa442987028f8a3aed5a41e95752b4c70af8fcd995310b3c3f68104fd05bd3546e78624d61f1fd46dbd26add39207501fd4f16a07d57eeded8d5ed91b50f25ce8993c982ecde5cffa09f94c70843f3c61749920ded84e0de345361605e8a2b9054359d76901c8f6ea0df09f81f91b7e6e88d0cc5e2e07facebb57fce27f433406cdcc03397da92ecd6b26a0a79c760e913a562520fb3b0e9b944e027d854891726176f860474a105eb44a49f86d284c24f7d4b20e5a8e265f23f01c6ab166a7cdf4ef2f65e95860654f083b4b72f00b593bc74e269ef49c33bc3fe7fdaab84744c69b247a9f77dac681ceff5cba1f225d5bc62f582a6fd64b5d942c8fd03883e7d0618cbb87647eb4c037964e1cef35ab42423ab375005678b80cd9d5c6f9b574d32489339583dba81be4f637d898dcd350ddfd38bf18f67636dcc398a0e16c984d7c7f5dee6e2bb8b7b63d9c581e47da06c5c6734de858a12d3c2ab09b38163d3be1741195c4eb07152f38e5fc65372807d5517ff2f8ebb047a5868b773983f78d663140c6532dd09078ae54b1c9fedf3e2a2ba9857010ee6c4ee09533a0df2418e523b3e5f9e297e22a0de3ed398e8302b95507689833476679577b479266a5b1b65d95227f36451dad497eeec9838778c59c7ebdc3989c20e66f423fde732ad5a9a85cbd71e9418903787d09db4526b4d6f987ace4874309b9a52d635bdccbd2734dc73a4cfbf373d601a7e6e7c8eb075b6438bb329528426a63b0392896c064b86de68a004842a1380feb4710a5e6ffe7df13e5540d0d1b4f77d007d8d76427c985fd0a6a31b92a400bd24a6edd69c507687448bdc7c2e556753a2f62fce9e7d7525a9f90b5f5572b62f5c38aa954168cadd775782379cfe2846016d437b2a2df58ed8884f90e58fd85109ae8a39ac4802a9ba0a32f707d39e843e419d097e1a24acb05a5ea9305a839a659be5475d58bb89548c5348204ff8aad84138824329605e4363b88b770903057a1231a219223616dc041f1dc279234c3432859e2e94a6b0686ecfa35f02e6ec771f3d60e05b0b619e8be9adff848879e08fc5464ff57b9a12376398b30d7c94120217e9ebdad023911ab7f54fb6c287fda2149ea7f96123b0c92022367baee0089dbd99bf572d79278c235fe51baf6b13f60aa64204d5ed57ac82d5b7251a5d2b93a65fd323f8878e20718489a72ae482356d5a78b11a2c3bfad66a6f5e3fb617256ad0cf989b01144a052d8d5d28295bbe5a61cfcc16475394044678d006488a36110eae7490b1e58fee997098b63e65eb917d7236e77f909d0fa47771d1d57c68d931e26760f010582dd4d8493b3181eee36679c2aa3d9af2dccfa8fbc2fd5b380de2bf27e38f1b6ef8537c940cac5cdb5517142f86ab9c6dd26cfb9ad7bbc96b8a750c9f1713d623599642db6d79b2f0c62ce69ff042d73afca214504e2a9da7d30ff17bc5abffaa6895bdb34e3af9aced0af52c2c3944ec2e9aa3619219f662bb3c7b692cc1bd39934807897fb32d8ff08d0aa76aa928c6a094398db968c97d6faea7c4eaf8a2e714199cef772e08e7481fc1033dcacbb8e847aac9c68b021e2ec6b644e3b458e2a456694b6cc7ffffbda8798cba6a9d3f0f9f75e5873eaac006d7f7e7f0619ab44293981dbdf5bac1793561274e435c793f67ae755a7c5256166035e3149da3f03a9bd0504\", \"mac\":\"50bc2e8d29368875bf214eea319f8aa5336337a95d2685359438d84a61bd17a3\"}"; + FShareMetaData shareMetaData; - FShareMetaData shareMetaData; + if (!FJsonObjectConverter::JsonObjectStringToUStruct(response.message, &shareMetaData, 0, 0)) { + UE_LOG(LogTemp, Error, TEXT("failed to parse json")); + return; + } - if (!FJsonObjectConverter::JsonObjectStringToUStruct(jsonString, &shareMetaData, 0, 0)) { - UE_LOG(LogTemp, Error, TEXT("failed to parse json")); - return; - } - - FString output = crypto->decrypt(shareMetaData.ciphertext, sessionId, shareMetaData.ephemPublicKey, shareMetaData.iv); - UE_LOG(LogTemp, Log, TEXT("output %s"), *output); + FString output = crypto->decrypt(shareMetaData.ciphertext, sessionId, shareMetaData.ephemPublicKey, shareMetaData.iv); + UE_LOG(LogTemp, Log, TEXT("output %s"), *output); - TSharedPtr tempJson; - TSharedRef> JsonReader = TJsonReaderFactory::Create(output); + TSharedPtr tempJson; + TSharedRef> JsonReader = TJsonReaderFactory::Create(output); - if (FJsonSerializer::Deserialize(JsonReader, tempJson) && tempJson.IsValid()) { - tempJson->SetObjectField("userInfo", tempJson->GetObjectField("store")); - tempJson->RemoveField("store"); + if (FJsonSerializer::Deserialize(JsonReader, tempJson) && tempJson.IsValid()) { + tempJson->SetObjectField("userInfo", tempJson->GetObjectField("store")); + tempJson->RemoveField("store"); - FString json; - TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&json); - FJsonSerializer::Serialize(tempJson.ToSharedRef(), Writer); + FString json; + TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&json); + FJsonSerializer::Serialize(tempJson.ToSharedRef(), Writer); - FWeb3AuthResponse web3AuthResponse; + FWeb3AuthResponse web3AuthResponse; - if (!FJsonObjectConverter::JsonObjectStringToUStruct(json, &web3AuthResponse, 0, 0)) { - UE_LOG(LogTemp, Error, TEXT("failed to parse json")); - return; - } + if (!FJsonObjectConverter::JsonObjectStringToUStruct(json, &web3AuthResponse, 0, 0)) { + UE_LOG(LogTemp, Error, TEXT("failed to parse json")); + return; + } - if (web3AuthResponse.error != "") { - return; - } + if (web3AuthResponse.error != "") { + return; + } - AsyncTask(ENamedThreads::GameThread, [=]() { - AWeb3Auth::loginEvent.ExecuteIfBound(web3AuthResponse); - }); - } + AsyncTask(ENamedThreads::GameThread, [=]() { + AWeb3Auth::loginEvent.ExecuteIfBound(web3AuthResponse); + }); + } + + }); } } @@ -415,45 +414,43 @@ void AWeb3Auth::sessionTimeout() { FString pubKey = crypto->generatePublicKey(sessionId); UE_LOG(LogTemp, Log, TEXT("public key %s"), *pubKey); - web3AuthApi->AuthorizeSession(pubKey, [](FStoreApiResponse response) + web3AuthApi->AuthorizeSession(pubKey, [pubKey, sessionId, this](FStoreApiResponse response) { UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response.message); - }); - - FString jsonOutput = "{\"iv\":\"e9b09a4e58c0763c6c6547ed76f3c481\",\"ephemPublicKey\":\"044d52f016e2b7374381e0bf48b240803083702c7739afc36766c6f62f3080cb0c3b0a1da22f3644ad5d447c9d494b78ad82271043729d8fc373b8754c4eb8f5b3\",\"ciphertext\":\"3b1a647d7203dbeeac8e538164465d4040fe1697e15ea881c3e1926595dd92332226e04e3512b0b4934ee403b058be1da5934d8d44f7137f121084c433b190865483dab1baaf372468ecb511404519b56aca6eaaf4a69aaa8add30145a4795ed20da83b8689f1c175e8e8d95e5a798925b86768f83baa6dbb4f81fc92f1113ee2241691211bcadb6b7d2e7635ec5c9ef06f136f2e647844d31b6895402bcf1802ba08412bcf553a92e188ead80c212197ad053e8c4fbed67039e683d177b48121d8b823015d6e5dc850b50aaa2e95ca2af5f6951153386e0f98621332b2495caf45abe8a0b49790ca1b1e05c3af55138612682efd4d28367cbfbd273c95292e92a2ff073946ca689a2e6b9709a4b08ce2782c57f871f3c13fea55add85a32441d22d8ce56de588eebf55e3132bcaa1d03a6ca48726de6e05047c9fabbb7f4aeef0501fbcaa839a73ea9ce6b3947511f1cb341db8af35b3c2ab89365e784b0f1485fc3be2f7723541cce55ae3ede78efb09ecca8918b0514c620ce56e41efa98e715f91d04e813f27b78bec10da61e9259b1ec7aca2c3fb062590dda5ca510c3800955988830c0173dc2f5d911bfcb0fc1d23881a21df03f5e0e3a8a040ac223fce20199e47a8a1d16d511fa3758a937984f47a111f7da8bd6d87ff484b3c0b98fc889bd75a3893d16e51dcf1d493c4fb99f194cd474a77a7fce541c99a3924a5be5bd78477082f40bf3771f76d8a150372fbcf64a8a19f990a3170ae5867c168f371a28df90e78e31420eba031aff880b46cc9c96021dca5d975baba412e396f74092e360d62f72fea547e7698e80442ee251246627e0a095b72c374ce5da4cb877e49f8acefa442987028f8a3aed5a41e95752b4c70af8fcd995310b3c3f68104fd05bd3546e78624d61f1fd46dbd26add39207501fd4f16a07d57eeded8d5ed91b50f25ce8993c982ecde5cffa09f94c70843f3c61749920ded84e0de345361605e8a2b9054359d76901c8f6ea0df09f81f91b7e6e88d0cc5e2e07facebb57fce27f433406cdcc03397da92ecd6b26a0a79c760e913a562520fb3b0e9b944e027d854891726176f860474a105eb44a49f86d284c24f7d4b20e5a8e265f23f01c6ab166a7cdf4ef2f65e95860654f083b4b72f00b593bc74e269ef49c33bc3fe7fdaab84744c69b247a9f77dac681ceff5cba1f225d5bc62f582a6fd64b5d942c8fd03883e7d0618cbb87647eb4c037964e1cef35ab42423ab375005678b80cd9d5c6f9b574d32489339583dba81be4f637d898dcd350ddfd38bf18f67636dcc398a0e16c984d7c7f5dee6e2bb8b7b63d9c581e47da06c5c6734de858a12d3c2ab09b38163d3be1741195c4eb07152f38e5fc65372807d5517ff2f8ebb047a5868b773983f78d663140c6532dd09078ae54b1c9fedf3e2a2ba9857010ee6c4ee09533a0df2418e523b3e5f9e297e22a0de3ed398e8302b95507689833476679577b479266a5b1b65d95227f36451dad497eeec9838778c59c7ebdc3989c20e66f423fde732ad5a9a85cbd71e9418903787d09db4526b4d6f987ace4874309b9a52d635bdccbd2734dc73a4cfbf373d601a7e6e7c8eb075b6438bb329528426a63b0392896c064b86de68a004842a1380feb4710a5e6ffe7df13e5540d0d1b4f77d007d8d76427c985fd0a6a31b92a400bd24a6edd69c507687448bdc7c2e556753a2f62fce9e7d7525a9f90b5f5572b62f5c38aa954168cadd775782379cfe2846016d437b2a2df58ed8884f90e58fd85109ae8a39ac4802a9ba0a32f707d39e843e419d097e1a24acb05a5ea9305a839a659be5475d58bb89548c5348204ff8aad84138824329605e4363b88b770903057a1231a219223616dc041f1dc279234c3432859e2e94a6b0686ecfa35f02e6ec771f3d60e05b0b619e8be9adff848879e08fc5464ff57b9a12376398b30d7c94120217e9ebdad023911ab7f54fb6c287fda2149ea7f96123b0c92022367baee0089dbd99bf572d79278c235fe51baf6b13f60aa64204d5ed57ac82d5b7251a5d2b93a65fd323f8878e20718489a72ae482356d5a78b11a2c3bfad66a6f5e3fb617256ad0cf989b01144a052d8d5d28295bbe5a61cfcc16475394044678d006488a36110eae7490b1e58fee997098b63e65eb917d7236e77f909d0fa47771d1d57c68d931e26760f010582dd4d8493b3181eee36679c2aa3d9af2dccfa8fbc2fd5b380de2bf27e38f1b6ef8537c940cac5cdb5517142f86ab9c6dd26cfb9ad7bbc96b8a750c9f1713d623599642db6d79b2f0c62ce69ff042d73afca214504e2a9da7d30ff17bc5abffaa6895bdb34e3af9aced0af52c2c3944ec2e9aa3619219f662bb3c7b692cc1bd39934807897fb32d8ff08d0aa76aa928c6a094398db968c97d6faea7c4eaf8a2e714199cef772e08e7481fc1033dcacbb8e847aac9c68b021e2ec6b644e3b458e2a456694b6cc7ffffbda8798cba6a9d3f0f9f75e5873eaac006d7f7e7f0619ab44293981dbdf5bac1793561274e435c793f67ae755a7c5256166035e3149da3f03a9bd0504\", \"mac\":\"50bc2e8d29368875bf214eea319f8aa5336337a95d2685359438d84a61bd17a3\"}"; - - FShareMetaData shareMetaData; - - if (!FJsonObjectConverter::JsonObjectStringToUStruct(jsonOutput, &shareMetaData, 0, 0)) { - UE_LOG(LogTemp, Error, TEXT("failed to parse json")); - return; - } - - FString encryptedData = crypto->encrypt("", sessionId, shareMetaData.ephemPublicKey, shareMetaData.iv); - shareMetaData.ciphertext = encryptedData; - - - TSharedPtr jsonObject = MakeShareable(new FJsonObject); - FJsonObjectConverter::UStructToJsonObject(FShareMetaData::StaticStruct(), &shareMetaData, jsonObject.ToSharedRef(), 0, 0); - - FString jsonString; - TSharedRef> jsonWriter = TJsonWriterFactory<>::Create(&jsonString); - FJsonSerializer::Serialize(jsonObject.ToSharedRef(), jsonWriter); - - FLogoutApiRequest request; - request.data = jsonString; - request.key = pubKey; - request.signature = crypto->generateECDSASignature(sessionId, jsonString); - request.timeout = 1; - - web3AuthApi->Logout(request, [](FString response) - { - UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response); - AWeb3Auth::keyStoreUtils->Remove("sessionId"); - AsyncTask(ENamedThreads::GameThread, [=]() { - AWeb3Auth::logoutEvent.ExecuteIfBound(); - }); - }); + + FShareMetaData shareMetaData; + + if (!FJsonObjectConverter::JsonObjectStringToUStruct(response.message, &shareMetaData, 0, 0)) { + UE_LOG(LogTemp, Error, TEXT("failed to parse json")); + return; + } + + FString encryptedData = crypto->encrypt("", sessionId, shareMetaData.ephemPublicKey, shareMetaData.iv); + shareMetaData.ciphertext = encryptedData; + + + TSharedPtr jsonObject = MakeShareable(new FJsonObject); + FJsonObjectConverter::UStructToJsonObject(FShareMetaData::StaticStruct(), &shareMetaData, jsonObject.ToSharedRef(), 0, 0); + + FString jsonString; + TSharedRef> jsonWriter = TJsonWriterFactory<>::Create(&jsonString); + FJsonSerializer::Serialize(jsonObject.ToSharedRef(), jsonWriter); + + FLogoutApiRequest request; + request.data = jsonString; + request.key = pubKey; + request.signature = crypto->generateECDSASignature(sessionId, jsonString); + request.timeout = 1; + + web3AuthApi->Logout(request, [](FString response) + { + UE_LOG(LogTemp, Log, TEXT("Response: %s"), *response); + AWeb3Auth::keyStoreUtils->Remove("sessionId"); + AsyncTask(ENamedThreads::GameThread, [=]() { + AWeb3Auth::logoutEvent.ExecuteIfBound(); + }); + }); + }); } } diff --git a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp index 53a301d..c3f29c3 100644 --- a/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp +++ b/Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Web3AuthApi.cpp @@ -18,14 +18,13 @@ UWeb3AuthApi* UWeb3AuthApi::GetInstance() void UWeb3AuthApi::AuthorizeSession(const FString& key, const TFunction callback) { TSharedRef request = FHttpModule::Get().CreateRequest(); - request->SetVerb(TEXT("GET")); + request->SetVerb(TEXT("POST")); request->SetURL(TEXT("https://broadcast-server.tor.us/store/get?key=" + key)); - auto headers = request->GetAllHeaders(); - for (auto header : headers) { - UE_LOG(LogTemp, Log, TEXT("length: %s %s"), *header); + + FString FormString = "key=" + key; - } - + request->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded")); + request->SetContentAsString(FormString); request->OnProcessRequestComplete().BindLambda([callback](FHttpRequestPtr request, FHttpResponsePtr response, bool success) { FString response_string = response->GetContentAsString(); @@ -56,7 +55,6 @@ void UWeb3AuthApi::Logout(const FLogoutApiRequest logoutApiRequest, const TFunct request->SetURL(TEXT("https://broadcast-server.tor.us/store/set")); FString FormString = "key=" + logoutApiRequest.key + "&data=" + FGenericPlatformHttp::UrlEncode(logoutApiRequest.data) + "&signature=" + logoutApiRequest.signature + "&timeout=" + FString::FromInt(logoutApiRequest.timeout); - UE_LOG(LogTemp, Error, TEXT("%s"), *FormString); request->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded")); request->SetContentAsString(FormString);