rsa key initialization

This commit is contained in:
Timerix 2025-09-13 02:29:26 +05:00
parent f01c5fc8a9
commit 98ae36ad2f
8 changed files with 292 additions and 16 deletions

2
dependencies/tlibc vendored

@ -1 +1 @@
Subproject commit c415e2ca8ff51f41984ace8fe796187e6ad0fa27
Subproject commit 7e7bd195a9715abceb4131b21232aed7d990b75d

View File

@ -77,7 +77,7 @@ Result(void) client_run() {
Return RESULT_VOID;
}
#define inp_eq(LITERAL) str_equals(command, STR(LITERAL))
#define is_alias(LITERAL) str_equals(command, STR(LITERAL))
static ClientCredential* client_credential = NULL;
@ -132,7 +132,7 @@ void ClientCredential_free(ClientCredential* cred){
#define __passhash_lvl_iter 1e5
static Result(ClientCredential*) ClientCredential_create(str username, str password){
Result(ClientCredential*) ClientCredential_create(str username, str password){
Deferral(32);
ClientCredential* cred = (ClientCredential*)malloc(sizeof(ClientCredential));
memset(cred, 0, sizeof(ClientCredential));
@ -154,7 +154,7 @@ static Result(ClientCredential*) ClientCredential_create(str username, str passw
u8 passhash_lvl1[password_hash_size];
hash_password(StringBuilder_getStr(&sb), passhash_lvl1, __passhash_lvl_iter);
// lvl 2 hash - is being used to authorize client on server
str _passhash_lvl1_str = str_construct(passhash_lvl1, password_hash_size, false);
str _passhash_lvl1_str = str_construct((void*)passhash_lvl1, password_hash_size, false);
hash_password(_passhash_lvl1_str, cred->passhash_lvl2, __passhash_lvl_iter);
@ -162,7 +162,7 @@ static Result(ClientCredential*) ClientCredential_create(str username, str passw
return RESULT_VALUE(p, cred);
}
static void ServerConnection_close(ServerConnection* conn){
void ServerConnection_close(ServerConnection* conn){
if(conn == NULL)
return;
socket_close(conn->system_socket);
@ -170,7 +170,7 @@ static void ServerConnection_close(ServerConnection* conn){
free(conn);
}
static Result(ServerConnection*) connectToServer(EndpointIPv4 server_end, str server_key){
Result(ServerConnection*) connectToServer(EndpointIPv4 server_end, str server_key){
Deferral(64);
if(client_credential == NULL){

View File

@ -1,15 +1,13 @@
#include "cryptography.h"
#include <assert.h>
#include "tlibc/time.h"
void EncryptorAES_create(EncryptorAES* ptr, Array(u8) key){
//TODO: use AES CTR encryption instead of my own padding algorithm
void EncryptorAES_init(EncryptorAES* ptr, Array(u8) key){
assert(key.size == 16 || key.size == 24 || key.size == 32);
br_aes_ct64_cbcenc_init(&ptr->enc_ctx, key.data, key.size);
// uses CLOCK_REALTIME to seed rng
nsec_t time_now = getTimeNsec();
br_hmac_drbg_init(&ptr->rng_ctx, &br_sha256_vtable, &time_now, sizeof(time_now));
rng_init_sha256_seedFromTime(&br_hmac_drbg_vtable, &ptr->rng_ctx.vtable);
memset(ptr->buf, 0, __AES_BUFFER_SIZE);
memset(ptr->iv, 0, sizeof(ptr->iv));
@ -51,7 +49,7 @@ void EncryptorAES_encrypt(EncryptorAES* ptr, Array(u8) src, Array(u8) dst){
}
void DecryptorAES_create(DecryptorAES* ptr, Array(u8) key){
void DecryptorAES_init(DecryptorAES* ptr, Array(u8) key){
assert(key.size == 16 || key.size == 24 || key.size == 32);
br_aes_ct64_cbcdec_init(&ptr->dec_ctx, key.data, key.size);

164
src/cryptography/RSA.c Normal file
View File

@ -0,0 +1,164 @@
#include "cryptography.h"
#include <assert.h>
#include "bearssl_x509.h"
// https://crypto.stackexchange.com/questions/3110/impacts-of-not-using-rsa-exponent-of-65537
#define DEFAULT_PUBLIC_EXPONENT 65537
bool RSA_generateKeyPair(u32 key_size,
br_rsa_private_key* sk, void* sk_buf,
NULLABLE(br_rsa_public_key*) pk, NULLABLE(void* pk_buf))
{
br_hmac_drbg_context rng_ctx;
const br_prng_class** rng_class_ptr = &rng_ctx.vtable;
rng_init_sha256_seedFromTime(&br_hmac_drbg_vtable, rng_class_ptr);
u32 r = br_rsa_i31_keygen(rng_class_ptr, sk, sk_buf, pk, pk_buf, key_size, DEFAULT_PUBLIC_EXPONENT);
return r;
}
Result(void) RSA_computePublicKey(br_rsa_private_key* sk, br_rsa_public_key* pk){
Deferral(16);
br_rsa_compute_modulus compute_modulus = br_rsa_i31_compute_modulus;
br_rsa_compute_pubexp compute_pubexp = br_rsa_i31_compute_pubexp;
size_t modulus_size = compute_modulus(NULL, sk);
if (modulus_size == 0) {
Return RESULT_ERROR("compute_modulus", false);
}
void* modulus = malloc(modulus_size);
bool success = false;
Defer(
if(!success)
free(modulus)
);
if (compute_modulus(modulus, sk) != modulus_size) {
Return RESULT_ERROR("compute_modulus", false);
}
u32 pubexp_little_endian = compute_pubexp(sk);
if (pubexp_little_endian == 0) {
Return RESULT_ERROR("compute_pubexp", false);
}
u8 pubexp_big_endian[4];
pubexp_big_endian[0] = pubexp_little_endian >> 24;
pubexp_big_endian[1] = pubexp_little_endian >> 16;
pubexp_big_endian[2] = pubexp_little_endian >> 8;
pubexp_big_endian[3] = pubexp_little_endian;
pk->n = modulus;
pk->nlen = modulus_size;
pk->e = pubexp_big_endian;
pk->elen = sizeof pubexp_big_endian;
success = true;
Return RESULT_VOID;
}
Result(void) RSA_serializePrivateKey_RawDER(
br_rsa_private_key* sk,
NULLABLE(br_rsa_public_key*) pk,
Array(u8)* out_der)
{
Deferral(32);
br_rsa_compute_pubexp compute_pubexp = br_rsa_i31_compute_pubexp;
br_rsa_compute_privexp compute_privexp = br_rsa_i31_compute_privexp;
if(pk == NULL){
try_void(RSA_computePublicKey(sk, pk));
Defer(free(pk->n));
}
u32 pubexp_little_endian = compute_pubexp(sk);
if (pubexp_little_endian == 0) {
Return RESULT_ERROR("compute_pubexp", false);
}
size_t privexp_size = compute_privexp(NULL, sk, pubexp_little_endian);
if (privexp_size == 0) {
Return RESULT_ERROR("compute_privexp", false);
}
void* privexp = malloc(privexp_size);
Defer(free(privexp));
if (compute_privexp(privexp, sk, pubexp_little_endian) != privexp_size) {
Return RESULT_ERROR("compute_privexp", false);
}
size_t der_size = br_encode_rsa_raw_der(NULL, sk, pk, privexp, privexp_size);
if (der_size == 0) {
Return RESULT_ERROR("br_encode_rsa_raw_der", false);
}
void* der = malloc(der_size);
bool success = false;
Defer(
if(!success)
free(der)
);
if (br_encode_rsa_raw_der(der, sk, pk, privexp, privexp_size) != der_size) {
Return RESULT_ERROR("br_encode_rsa_raw_der", false);
}
success = true;
out_der->data = der;
out_der->size = der_size;
Return RESULT_VOID;
}
void PEM_encode(Array(u8) src, Array(u8)* dst, cstr label){
u64 encoded_size = br_pem_encode(NULL, src.data, src.size, label, 0);
// br_pem_encode doesn't count '\0' but writes it
*dst = Array_alloc_size(encoded_size + 1);
br_pem_encode(dst->data, src.data, src.size, label, 0);
}
Result(void) RSA_parsePrivateKey_DER(Array(u8) _src, br_rsa_private_key* sk){
Deferral(16);
// private key data will be written in this buffer on success
Array(u8) buf = Array_copy(_src);
bool success = false;
Defer(free(buf.data));
br_skey_decoder_context decoder;
br_skey_decoder_init(&decoder);
br_skey_decoder_push(&decoder, buf.data, buf.size);
i32 errcode = br_skey_decoder_last_error(&decoder);
if (errcode != 0) {
Return RESULT_ERROR_FMT("br_skey_decoder error %i", errcode);
}
i32 parsed_type = br_skey_decoder_key_type(&decoder);
if(parsed_type != BR_KEYTYPE_RSA){
Return RESULT_ERROR_FMT("parsed key has unsupported type %i", parsed_type);
}
const br_rsa_private_key* decoded_key = br_skey_decoder_get_rsa(&decoder);
if(decoded_key == NULL){
Return RESULT_ERROR("decoder failed without errors", false);
}
success = true;
memcpy(sk, decoded_key, sizeof(*decoded_key));
// sk fields still point to stack array decoder.key_data
// This code copies the data and adjusts sk fields to point to the copied chunk
Array(u8) key_data_copy = Array_alloc_size(BR_RSA_KBUF_PRIV_SIZE(decoded_key->n_bitlen));
Defer(
if(!success)
free(key_data_copy.data);
);
memcpy(key_data_copy.data, decoder.key_data, key_data_copy.size);
u64 memory_distance = (u64)key_data_copy.data - (u64)(void*)decoder.key_data;
u8** sk_pointer_fields[] = {
&sk->p, &sk->q, &sk->dp, &sk->dq, &sk->iq
};
for(u32 i = 0; i < ARRAY_LEN(sk_pointer_fields); i++){
u8** field_place = sk_pointer_fields[i];
u64 field_value = (u64)*field_place;
field_value += memory_distance;
*field_place = (void*)field_value;
}
Return RESULT_VOID;
}
void EncryptorRSA_init(EncryptorRSA* ptr, Array(u8) key){
}

View File

@ -2,9 +2,15 @@
#include "tlibc/std.h"
#include "tlibc/collections/Array.h"
#include "tlibc/string/str.h"
#include "tlibc/errors.h"
#include "bearssl_block.h"
#include "bearssl_rand.h"
#include "bearssl_rsa.h"
#include "bearssl_pem.h"
//////////////////////////////////////////////////////////////////////////////
// hash.c //
//////////////////////////////////////////////////////////////////////////////
/// @brief hashes password multiple times using its own hash as salt
/// @param password some byte array
@ -14,6 +20,25 @@ void hash_password(str password, u8* out_buffer, i32 iterations);
#define password_hash_size 32
//////////////////////////////////////////////////////////////////////////////
// rng.c //
//////////////////////////////////////////////////////////////////////////////
/// @brief Initialize prng context with sha256 hashing algorithm and seed from CLOCK_REALTIME.
/// @param rng_class pointer to static vtable variable
/// @param rng_ctx pointer to vtable field in prng context
/// EXAMPLE:
/// ```
/// br_hmac_drbg_context rng_ctx;
/// rng_init_sha256_seedFromTime(&br_hmac_drbg_vtable, &rng_ctx.vtable);
/// ```
void rng_init_sha256_seedFromTime(const br_prng_class* rng_class, const br_prng_class** rng_ctx);
//////////////////////////////////////////////////////////////////////////////
// AES.c //
//////////////////////////////////////////////////////////////////////////////
typedef struct EncryptedBlockInfo {
u8 padding_size;
u32 _reserved;
@ -33,7 +58,7 @@ typedef struct EncryptorAES {
} EncryptorAES;
/// @param key Array<u8, 16 | 24 | 32>
void EncryptorAES_create(EncryptorAES* ptr, Array(u8) key);
void EncryptorAES_init(EncryptorAES* ptr, Array(u8) key);
/// @brief Encrypts `src` and writes output to `dst`.
/// @param src array of any size
@ -50,7 +75,7 @@ typedef struct DecryptorAES {
} DecryptorAES;
/// @param key Array<u8, 16 | 24 | 32>
void DecryptorAES_create(DecryptorAES* ptr, Array(u8) key);
void DecryptorAES_init(DecryptorAES* ptr, Array(u8) key);
/// @brief Decrypts `src` and writes output to `dst`.
/// @param src array of any size
@ -59,12 +84,47 @@ void DecryptorAES_create(DecryptorAES* ptr, Array(u8) key);
void DecryptorAES_decrypt(DecryptorAES* ptr, Array(u8) src, Array(u8) dst, u32* decrypted_size);
//////////////////////////////////////////////////////////////////////////////
// RSA.c //
//////////////////////////////////////////////////////////////////////////////
bool RSA_generateKeyPair(u32 key_size,
br_rsa_private_key* sk, void* sk_buf,
NULLABLE(br_rsa_public_key*) pk, NULLABLE(void* pk_buf));
/// @param sk some private key
/// @param pk out public key. WARNING: .n is allocated on heap
Result(void) RSA_computePublicKey(br_rsa_private_key* sk, br_rsa_public_key* pk);
/// @brief Serialize key in raw DER binary format
/// @param sk the private key
/// @param pk set to NULL to calculate automatically
/// @param out_der out array. WARNING: .data is allocated on heap
Result(void) RSA_serializePrivateKey_RawDER(
br_rsa_private_key* sk,
NULLABLE(br_rsa_public_key*) pk,
Array(u8)* out_der);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @param dst out array. WARNING: .data is allocated on heap
/// @param label some string to write at the top of PEM file
void PEM_encode(Array(u8) src, Array(u8)* dst, cstr label);
/// @param src serialized private key in DER format
/// @param sk out private key. WARNING: .p is allocated on heap
Result(void) RSA_parsePrivateKey_DER(Array(u8) src, br_rsa_private_key* sk);
typedef struct EncryptorRSA {
br_rsa_public_key public_key;
} EncryptorRSA;
/// @param key Array<u8, 16 | 24 | 32>
void EncryptorRSA_init(EncryptorRSA* ptr, Array(u8) key);
typedef struct DecryptorRSA {
br_rsa_private_key private_key;
} DecryptorRSA;
/// @param key Array<u8, 16 | 24 | 32>
void DecryptorRSA_init(DecryptorRSA* ptr, Array(u8) key);

7
src/cryptography/rng.c Normal file
View File

@ -0,0 +1,7 @@
#include "cryptography.h"
#include "tlibc/time.h"
void rng_init_sha256_seedFromTime(const br_prng_class* rng_class, const br_prng_class** rng_ctx){
nsec_t time_now = getTimeNsec();
rng_class->init(rng_ctx, &br_sha256_vtable, &time_now, sizeof(time_now));
}

View File

@ -1,5 +1,6 @@
#include "network/network.h"
#include "chat.h"
#include "cryptography/cryptography.h"
typedef enum ProgramMode {
Client,
@ -11,6 +12,51 @@ typedef enum ProgramMode {
int main(const int argc, cstr const* argv){
Deferral(32);
const u32 key_size = 2048;
br_rsa_private_key sk;
const u32 sk_buf_size = BR_RSA_KBUF_PRIV_SIZE(key_size);
u8 sk_buf[sk_buf_size];
memset(sk_buf, 0, sk_buf_size);
br_rsa_public_key pk;
const u32 pk_buf_size = BR_RSA_KBUF_PUB_SIZE(key_size);
u8 pk_buf[pk_buf_size];
memset(pk_buf, 0, pk_buf_size);
if(!RSA_generateKeyPair(key_size, &sk, sk_buf, &pk, pk_buf)){
printfe("ERROR: can't generate RSA key pair\n");
Return 1;
}
br_rsa_public_key pk2;
try_fatal_void(RSA_computePublicKey(&sk, &pk2));
Defer(free(pk2.n));
if(memcmp(pk2.n, pk.n, pk.nlen) != 0){
printfe("public key computation failed\n");
Return 1;
}
Array(u8) der;
try_fatal_void(RSA_serializePrivateKey_RawDER(&sk, &pk, &der));
Defer(free(der.data));
Array(u8) pem;
Defer(free(pem.data));
PEM_encode(der, &pem, "RSA PRIVATE KEY");
printf("\nserialized key:\n%s\n\n", (char*)pem.data);
br_rsa_private_key sk2;
try_fatal_void(RSA_parsePrivateKey_DER(der, &sk2));
Defer(free(sk2.p));
free(der.data);
try_fatal_void(RSA_serializePrivateKey_RawDER(&sk2, &pk, &der));
free(pem.data);
PEM_encode(der, &pem, "RSA PRIVATE KEY");
printf("\nparsed key:\n%s\n\n", (char*)pem.data);
Return 0;
ProgramMode mode = Client;
cstr server_endpoint_cstr;

View File

@ -12,7 +12,8 @@ static void* handle_connection(void* _args);
Result(void) server_run(cstr server_endpoint_str){
Deferral(32);
EndpointIPv4 server_end = EndpointIPv4_fromStr(server_endpoint_str);
EndpointIPv4 server_end;
EndpointIPv4_parse(server_endpoint_str, &server_end);
//TODO: add log
try(Socket main_socket, i, socket_open_TCP());
try_void(socket_bind(main_socket, server_end));