Skip to content

Commit d0f21a4

Browse files
Merge pull request #6 from Web3Auth/session-management
Session management
2 parents 9dd8fa6 + c897045 commit d0f21a4

File tree

12 files changed

+790
-7
lines changed

12 files changed

+790
-7
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1"]
2+
path = Plugins/Web3AuthSDK/Source/Web3AuthSDK/Public/secp256k1
3+
url = https://github.com/bitcoin-core/secp256k1
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#include "ECCrypto.h"
2+
#include <string>
3+
#include <vector>
4+
#include <Web3Auth.h>
5+
6+
#pragma comment(lib, "crypt32.lib")
7+
#pragma comment(lib, "WS2_32.lib")
8+
9+
10+
unsigned char* toByteArray(const std::string& s) {
11+
size_t len = s.length() / 2;
12+
unsigned char* data = new unsigned char[len];
13+
14+
for (size_t i = 0; i < len * 2; i += 2) {
15+
int hi = std::stoi(s.substr(i, 1), nullptr, 16);
16+
int lo = std::stoi(s.substr(i + 1, 1), nullptr, 16);
17+
data[i / 2] = (unsigned char)((hi << 4) + lo);
18+
}
19+
20+
return data;
21+
22+
}
23+
24+
char* FStringToCharArray(const FString& InString) {
25+
char* CharArray = new char[InString.Len() + 1];
26+
27+
strcpy(CharArray, TCHAR_TO_ANSI(*InString));
28+
return CharArray;
29+
}
30+
31+
UECCrypto::UECCrypto() {
32+
}
33+
34+
FString UECCrypto::decrypt(FString data, FString privateKeyHex, FString ephemPublicKeyHex, FString encryptionIvHex)
35+
{
36+
// Convert to bytes array
37+
const char* priv_hex = FStringToCharArray(privateKeyHex);
38+
const char* pub_hex = FStringToCharArray(ephemPublicKeyHex);
39+
40+
// Decode IV key
41+
const unsigned char* iv = toByteArray(FStringToCharArray(encryptionIvHex));
42+
43+
// Decode cipher text
44+
const unsigned char* src = toByteArray(FStringToCharArray(data));
45+
int srclen = data.Len() / 2;
46+
47+
// Convert to BIGNUM
48+
BIGNUM* priv_bn = BN_new();
49+
BIGNUM* pub_bn = BN_new();
50+
BN_hex2bn(&priv_bn, priv_hex);
51+
BN_hex2bn(&pub_bn, pub_hex);
52+
53+
// Create EC_KEY objects from the BIGNUMs
54+
EC_KEY* priv_key = EC_KEY_new_by_curve_name(NID_secp256k1);
55+
EC_KEY* pub_key = EC_KEY_new_by_curve_name(NID_secp256k1);
56+
EC_KEY_set_private_key(priv_key, priv_bn);
57+
EC_KEY_set_public_key(pub_key, EC_POINT_bn2point(EC_KEY_get0_group(pub_key), pub_bn, NULL, NULL));
58+
59+
// Create the shared secret
60+
unsigned char* secret = new unsigned char[32];
61+
int secret_len = ECDH_compute_key(secret, EVP_MAX_KEY_LENGTH, EC_KEY_get0_public_key(pub_key), priv_key, NULL);
62+
63+
// Calculate SHA-512 hash of secret
64+
unsigned char hash[SHA512_DIGEST_LENGTH];
65+
SHA512(secret, 32, hash);
66+
67+
// Copy first 32 bytes of the hash into a new buffer
68+
unsigned char key[32];
69+
memcpy(key, hash, 32);
70+
71+
// Create a new encryption context for AES-256 CBC mode with the key and IV
72+
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
73+
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
74+
75+
// Allocate a string buffer for the decrypted data
76+
std::string dst;
77+
dst.resize(srclen + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
78+
79+
// Decrypt the input data
80+
int outlen;
81+
EVP_DecryptUpdate(ctx, (unsigned char*)dst.data(), &outlen, src, srclen);
82+
83+
// Finalize the decryption and retrieve any remaining data
84+
int finaloutlen;
85+
EVP_DecryptFinal_ex(ctx, (unsigned char*)dst.data() + outlen, &finaloutlen);
86+
87+
// Resize the buffer to the actual decrypted length
88+
dst.resize(outlen + finaloutlen);
89+
90+
// Free the encryption context
91+
EVP_CIPHER_CTX_free(ctx);
92+
93+
// Clean up resources
94+
BN_free(priv_bn);
95+
BN_free(pub_bn);
96+
EC_KEY_free(priv_key);
97+
EC_KEY_free(pub_key);
98+
EVP_cleanup();
99+
100+
return FString(dst.c_str());
101+
}
102+
103+
FString UECCrypto::encrypt(FString data, FString privateKeyHex, FString ephemPublicKeyHex, FString encryptionIvHex)
104+
{
105+
// Convert to bytes array
106+
const char* priv_hex = FStringToCharArray(privateKeyHex);
107+
const char* pub_hex = FStringToCharArray(ephemPublicKeyHex);
108+
109+
// Decode IV key
110+
const unsigned char* iv = toByteArray(FStringToCharArray(encryptionIvHex));
111+
112+
// Decode cipher text
113+
const unsigned char* src = (unsigned char*)FStringToCharArray(data);
114+
int srclen = data.Len() / 2;
115+
116+
// Convert to BIGNUM
117+
BIGNUM* priv_bn = BN_new();
118+
BIGNUM* pub_bn = BN_new();
119+
BN_hex2bn(&priv_bn, priv_hex);
120+
BN_hex2bn(&pub_bn, pub_hex);
121+
122+
// Create EC_KEY objects from the BIGNUMs
123+
EC_KEY* priv_key = EC_KEY_new_by_curve_name(NID_secp256k1);
124+
EC_KEY* pub_key = EC_KEY_new_by_curve_name(NID_secp256k1);
125+
EC_KEY_set_private_key(priv_key, priv_bn);
126+
EC_KEY_set_public_key(pub_key, EC_POINT_bn2point(EC_KEY_get0_group(pub_key), pub_bn, NULL, NULL));
127+
128+
// Create the shared secret
129+
unsigned char* secret = new unsigned char[32];
130+
int secret_len = ECDH_compute_key(secret, EVP_MAX_KEY_LENGTH, EC_KEY_get0_public_key(pub_key), priv_key, NULL);
131+
132+
// Calculate SHA-512 hash of secret
133+
unsigned char hash[SHA512_DIGEST_LENGTH];
134+
SHA512(secret, 32, hash);
135+
136+
// Copy first 32 bytes of the hash into a new buffer
137+
unsigned char key[32];
138+
memcpy(key, hash, 32);
139+
140+
// Create a new encryption context for AES-256 CBC mode with the key and IV
141+
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
142+
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
143+
144+
// Allocate a string buffer for the decrypted data
145+
std::string dst;
146+
dst.resize(srclen + EVP_CIPHER_block_size(EVP_aes_256_cbc()));
147+
148+
// Decrypt the input data
149+
int outlen;
150+
EVP_EncryptUpdate(ctx, (unsigned char*)dst.data(), &outlen, src, srclen);
151+
152+
// Finalize the decryption and retrieve any remaining data
153+
int finaloutlen;
154+
EVP_EncryptFinal_ex(ctx, (unsigned char*)dst.data() + outlen, &finaloutlen);
155+
156+
// Resize the buffer to the actual decrypted length
157+
dst.resize(outlen + finaloutlen);
158+
159+
// Free the encryption context
160+
EVP_CIPHER_CTX_free(ctx);
161+
162+
// Clean up resources
163+
BN_free(priv_bn);
164+
BN_free(pub_bn);
165+
EC_KEY_free(priv_key);
166+
EC_KEY_free(pub_key);
167+
EVP_cleanup();
168+
169+
return FString(UTF8_TO_TCHAR(dst.c_str()));
170+
}
171+
172+
FString UECCrypto::generatePublicKey(const FString& privateKeyHex) {
173+
BIGNUM* bn_private_key = NULL;
174+
BN_hex2bn(&bn_private_key, TCHAR_TO_ANSI(*privateKeyHex));
175+
176+
EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
177+
EC_KEY_set_private_key(ec_key, bn_private_key);
178+
179+
EC_POINT* ec_point = EC_POINT_new(EC_KEY_get0_group(ec_key));
180+
EC_POINT_mul(EC_KEY_get0_group(ec_key), ec_point, EC_KEY_get0_private_key(ec_key), NULL, NULL, NULL);
181+
EC_KEY_set_public_key(ec_key, ec_point);
182+
183+
BIGNUM* bn = EC_POINT_point2bn(EC_KEY_get0_group(ec_key), EC_KEY_get0_public_key(ec_key), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
184+
185+
char* hex = BN_bn2hex(bn);
186+
FString result(UTF8_TO_TCHAR(hex));
187+
188+
OPENSSL_free(hex);
189+
BN_free(bn_private_key);
190+
191+
return result.ToLower();
192+
}
193+
194+
FString UECCrypto::generateECDSASignature(const FString& privateKeyHex, const FString& data) {
195+
// Initialize OpenSSL's elliptic curve library
196+
EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1);
197+
198+
BIGNUM* priv_bn = BN_new();
199+
BN_hex2bn(&priv_bn, FStringToCharArray(privateKeyHex));
200+
201+
EC_KEY_set_private_key(key, priv_bn);
202+
203+
const unsigned char* msg = (const unsigned char* ) FStringToCharArray(data);
204+
size_t msglen = data.Len();
205+
206+
unsigned char hash[SHA256_DIGEST_LENGTH];
207+
Keccak256::getHash(msg, msglen, hash);
208+
209+
unsigned char* sig_buf = nullptr;
210+
211+
ECDSA_SIG* signature = ECDSA_do_sign(hash, SHA256_DIGEST_LENGTH, key);
212+
int n = i2d_ECDSA_SIG(signature, &sig_buf);
213+
214+
//// Convert signature to hex string
215+
FString signature_hex;
216+
for (int i = 0; i < n; ++i) {
217+
signature_hex += FString::Printf(TEXT("%02x"), sig_buf[i]);
218+
}
219+
220+
EC_KEY_free(key);
221+
ECDSA_SIG_free(signature);
222+
223+
return signature_hex;
224+
}
225+
226+
UECCrypto::~UECCrypto()
227+
{
228+
}
229+
230+
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Bitcoin cryptography library
3+
* Copyright (c) Project Nayuki
4+
*
5+
* https://www.nayuki.io/page/bitcoin-cryptography-library
6+
* https://github.com/nayuki/Bitcoin-Cryptography-Library
7+
*/
8+
9+
#include "Keccak256.h"
10+
#include <cassert>
11+
12+
using std::uint8_t;
13+
using std::uint64_t;
14+
using std::size_t;
15+
16+
17+
void Keccak256::getHash(const uint8_t msg[], size_t len, uint8_t hashResult[HASH_LEN]) {
18+
assert((msg != nullptr || len == 0) && hashResult != nullptr);
19+
uint64_t state[5][5] = {};
20+
21+
// XOR each message byte into the state, and absorb full blocks
22+
int blockOff = 0;
23+
for (size_t i = 0; i < len; i++) {
24+
int j = blockOff >> 3;
25+
state[j % 5][j / 5] ^= static_cast<uint64_t>(msg[i]) << ((blockOff & 7) << 3);
26+
blockOff++;
27+
if (blockOff == BLOCK_SIZE) {
28+
absorb(state);
29+
blockOff = 0;
30+
}
31+
}
32+
33+
// Final block and padding
34+
{
35+
int i = blockOff >> 3;
36+
state[i % 5][i / 5] ^= UINT64_C(0x01) << ((blockOff & 7) << 3);
37+
blockOff = BLOCK_SIZE - 1;
38+
int j = blockOff >> 3;
39+
state[j % 5][j / 5] ^= UINT64_C(0x80) << ((blockOff & 7) << 3);
40+
absorb(state);
41+
}
42+
43+
// Uint64 array to bytes in little endian
44+
for (int i = 0; i < HASH_LEN; i++) {
45+
int j = i >> 3;
46+
hashResult[i] = static_cast<uint8_t>(state[j % 5][j / 5] >> ((i & 7) << 3));
47+
}
48+
}
49+
50+
51+
void Keccak256::absorb(uint64_t state[5][5]) {
52+
uint64_t(*a)[5] = state;
53+
uint8_t r = 1; // LFSR
54+
for (int i = 0; i < NUM_ROUNDS; i++) {
55+
// Theta step
56+
uint64_t c[5] = {};
57+
for (int x = 0; x < 5; x++) {
58+
for (int y = 0; y < 5; y++)
59+
c[x] ^= a[x][y];
60+
}
61+
for (int x = 0; x < 5; x++) {
62+
uint64_t d = c[(x + 4) % 5] ^ rotl64(c[(x + 1) % 5], 1);
63+
for (int y = 0; y < 5; y++)
64+
a[x][y] ^= d;
65+
}
66+
67+
// Rho and pi steps
68+
uint64_t b[5][5];
69+
for (int x = 0; x < 5; x++) {
70+
for (int y = 0; y < 5; y++)
71+
b[y][(x * 2 + y * 3) % 5] = rotl64(a[x][y], ROTATION[x][y]);
72+
}
73+
74+
// Chi step
75+
for (int x = 0; x < 5; x++) {
76+
for (int y = 0; y < 5; y++)
77+
a[x][y] = b[x][y] ^ (~b[(x + 1) % 5][y] & b[(x + 2) % 5][y]);
78+
}
79+
80+
// Iota step
81+
for (int j = 0; j < 7; j++) {
82+
a[0][0] ^= static_cast<uint64_t>(r & 1) << ((1 << j) - 1);
83+
r = static_cast<uint8_t>((r << 1) ^ ((r >> 7) * 0x171));
84+
}
85+
}
86+
}
87+
88+
89+
uint64_t Keccak256::rotl64(uint64_t x, int i) {
90+
return ((0U + x) << i) | (x >> ((64 - i) & 63));
91+
}
92+
93+
94+
// Static initializers
95+
const unsigned char Keccak256::ROTATION[5][5] = {
96+
{ 0, 36, 3, 41, 18},
97+
{ 1, 44, 10, 45, 2},
98+
{62, 6, 43, 15, 61},
99+
{28, 55, 25, 21, 56},
100+
{27, 20, 39, 8, 14},
101+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "KeyStoreUtils.h"
2+
3+
UKeyStoreUtils::UKeyStoreUtils() {
4+
StorageInstance = Cast<UWeb3StorageAdapter>(UGameplayStatics::LoadGameFromSlot(TEXT("Web3AuthDataSlot"), 0));
5+
if(StorageInstance == nullptr) {
6+
StorageInstance = Cast<UWeb3StorageAdapter>(UGameplayStatics::CreateSaveGameObject(UWeb3StorageAdapter::StaticClass()));
7+
}
8+
}
9+
10+
UKeyStoreUtils::~UKeyStoreUtils() {
11+
}
12+
13+
void UKeyStoreUtils::Add(FString key, FString value) {
14+
StorageInstance->KeyValuePairs.Add(key, value);
15+
UGameplayStatics::SaveGameToSlot(StorageInstance, TEXT("Web3AuthDataSlot"), 0);
16+
}
17+
18+
FString UKeyStoreUtils::Get(FString key) {
19+
if (StorageInstance->KeyValuePairs.Contains(key)) {
20+
return StorageInstance->KeyValuePairs[key];
21+
}
22+
return "";
23+
}
24+
25+
void UKeyStoreUtils::Remove(FString key) {
26+
if (StorageInstance->KeyValuePairs.Contains(key)) {
27+
StorageInstance->KeyValuePairs.Remove(key);
28+
UGameplayStatics::SaveGameToSlot(StorageInstance, TEXT("Web3AuthDataSlot"), 0);
29+
}
30+
}

0 commit comments

Comments
 (0)