-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from Web3Auth/session-management
Session management
- Loading branch information
Showing
12 changed files
with
790 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
230 changes: 230 additions & 0 deletions
230
Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/ECCrypto.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
#include "ECCrypto.h" | ||
#include <string> | ||
#include <vector> | ||
#include <Web3Auth.h> | ||
|
||
#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() | ||
{ | ||
} | ||
|
||
|
101 changes: 101 additions & 0 deletions
101
Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/Keccak256.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <cassert> | ||
|
||
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<uint64_t>(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<uint8_t>(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<uint64_t>(r & 1) << ((1 << j) - 1); | ||
r = static_cast<uint8_t>((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}, | ||
}; |
30 changes: 30 additions & 0 deletions
30
Plugins/Web3AuthSDK/Source/Web3AuthSDK/Private/KeyStoreUtils.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#include "KeyStoreUtils.h" | ||
|
||
UKeyStoreUtils::UKeyStoreUtils() { | ||
StorageInstance = Cast<UWeb3StorageAdapter>(UGameplayStatics::LoadGameFromSlot(TEXT("Web3AuthDataSlot"), 0)); | ||
if(StorageInstance == nullptr) { | ||
StorageInstance = Cast<UWeb3StorageAdapter>(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); | ||
} | ||
} |
Oops, something went wrong.