cryptography rework and beginning of tcp-chat-protocol

This commit is contained in:
2025-10-31 23:19:08 +05:00
parent 42702ffbe7
commit a0bcd2560a
24 changed files with 682 additions and 283 deletions

View File

@@ -1,52 +1,56 @@
#include "cryptography.h"
#include "AES.h"
#include <assert.h>
// write data from src to array and increment array data pointer
static inline void __Array_writeNext(Array(u8)* dst, void* src, size_t size){
static inline void __Array_writeNext(Array(u8)* dst, u8* src, size_t size){
memcpy(dst->data, src, size);
dst->data = (u8*)dst->data + size;
dst->size -= size;
}
// read data from array to dst and increment array data pointer
static inline void __Array_readNext(void* dst, Array(u8)* src, size_t size){
static inline void __Array_readNext(u8* dst, Array(u8)* src, size_t size){
memcpy(dst, src->data, size);
src->data = (u8*)src->data + size;
src->size -= size;
}
void EncryptorAES_construct(EncryptorAES* ptr, Array(u8) key){
void AESBlockEncryptor_construct(AESBlockEncryptor* ptr, Array(u8) key, const br_block_cbcenc_class* enc_class){
assert(key.size == 16 || key.size == 24 || key.size == 32);
//TODO: use AES CTR encryption?
br_aes_ct64_cbcenc_init(&ptr->enc_ctx, key.data, key.size);
ptr->enc_class = enc_class;
ptr->enc_class->init((void*)ptr->enc_keys, key.data, key.size);
ptr->rng_ctx.vtable = &br_hmac_drbg_vtable;
rng_init_sha256_seedFromSystem(&ptr->rng_ctx.vtable);
}
Result(void) EncryptorAES_encrypt(EncryptorAES* ptr, Array(u8) src, Array(u8) dst){
Result(u32) AESBlockEncryptor_encrypt(AESBlockEncryptor* ptr, Array(u8) src, Array(u8) dst){
Deferral(4);
try_assert(dst.size >= EncryptorAES_calcDstSize(src.size));
u32 encrypted_size = AESBlockEncryptor_calcDstSize(src.size);
try_assert(dst.size >= encrypted_size);
// generate random initial vector
br_hmac_drbg_generate(&ptr->rng_ctx, ptr->iv, __AES_IV_SIZE);
br_hmac_drbg_generate(&ptr->rng_ctx, ptr->iv, __AES_BLOCK_IV_SIZE);
// write IV to the beginning of dst
__Array_writeNext(&dst, ptr->iv, __AES_IV_SIZE);
__Array_writeNext(&dst, ptr->iv, __AES_BLOCK_IV_SIZE);
const EncryptedBlockHeader header = { .padding_size = 16 - src.size % 16 };
// write header to buffer
memcpy(ptr->buf, &header, sizeof(header));
// encrypt header
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, sizeof(header));
ptr->enc_class->run((void*)ptr->enc_keys, ptr->iv, ptr->buf, sizeof(header));
// write encrypted header to dst
__Array_writeNext(&dst, ptr->buf, sizeof(header));
// encrypt full EncryptorAES buffers
// encrypt full AESBlockEncryptor buffers
while(src.size > __AES_BUFFER_SIZE){
__Array_readNext(ptr->buf, &src, __AES_BUFFER_SIZE);
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE);
ptr->enc_class->run((void*)ptr->enc_keys,
ptr->iv,
ptr->buf, __AES_BUFFER_SIZE);
__Array_writeNext(&dst, ptr->buf, __AES_BUFFER_SIZE);
}
@@ -55,52 +59,152 @@ Result(void) EncryptorAES_encrypt(EncryptorAES* ptr, Array(u8) src, Array(u8) ds
memcpy(ptr->buf, src.data, src.size);
u32 src_size_padded = src.size + header.padding_size;
memset(ptr->buf + src.size, 0, header.padding_size);
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, src_size_padded);
ptr->enc_class->run((void*)ptr->enc_keys,
ptr->iv,
ptr->buf, src_size_padded);
memcpy(dst.data, ptr->buf, src_size_padded);
}
Return RESULT_VOID;
Return RESULT_VALUE(u, encrypted_size);
}
void DecryptorAES_construct(DecryptorAES* ptr, Array(u8) key){
void AESBlockDecryptor_construct(AESBlockDecryptor* ptr, Array(u8) key, const br_block_cbcdec_class* dec_class){
assert(key.size == 16 || key.size == 24 || key.size == 32);
br_aes_ct64_cbcdec_init(&ptr->dec_ctx, key.data, key.size);
ptr->dec_class = dec_class;
ptr->dec_class->init((void*)ptr->dec_keys, key.data, key.size);
}
Result(void) DecryptorAES_decrypt(DecryptorAES* ptr, Array(u8) src, Array(u8) dst, u32* decrypted_size){
Result(u32) AESBlockDecryptor_decrypt(AESBlockDecryptor* ptr, Array(u8) src, Array(u8) dst){
Deferral(4);
try_assert(src.size >= EncryptorAES_calcDstSize(0));
try_assert(src.size >= AESBlockEncryptor_calcDstSize(0));
try_assert(src.size % 16 == 0 && "src must be array of 16-byte blocks");
try_assert(dst.size >= src.size);
// read IV from the beginning of src
__Array_readNext(ptr->iv, &src, __AES_IV_SIZE);
__Array_readNext(ptr->iv, &src, __AES_BLOCK_IV_SIZE);
EncryptedBlockHeader header;
// read encrypted header from src
__Array_readNext(&header, &src, sizeof(header));
__Array_readNext((void*)&header, &src, sizeof(header));
// decrypt header
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, &header, sizeof(header));
ptr->dec_class->run((void*)ptr->dec_keys, ptr->iv, &header, sizeof(header));
// size of decrypted data without padding
*decrypted_size = src.size - header.padding_size;
u32 decrypted_size = src.size - header.padding_size;
const u32 src_size_padded = src.size;
src.size = *decrypted_size;
src.size = decrypted_size;
// decrypt full buffers
while(src.size > __AES_BUFFER_SIZE){
__Array_readNext(ptr->buf, &src, __AES_BUFFER_SIZE);
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE);
ptr->dec_class->run((void*)ptr->dec_keys,
ptr->iv,
ptr->buf, __AES_BUFFER_SIZE);
__Array_writeNext(&dst, ptr->buf, __AES_BUFFER_SIZE);
}
// decrypt buffer with remaining data
if(src.size > 0){
memcpy(ptr->buf, src.data, src.size);
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, ptr->buf, src_size_padded);
ptr->dec_class->run((void*)ptr->dec_keys,
ptr->iv,
ptr->buf, src_size_padded);
memcpy(dst.data, ptr->buf, src.size);
}
Return RESULT_VOID;
Return RESULT_VALUE(u, decrypted_size);
}
void AESStreamEncryptor_construct(AESStreamEncryptor* ptr, Array(u8) key, const br_block_ctr_class* ctr_class){
assert(key.size == 16 || key.size == 24 || key.size == 32);
ptr->ctr_class = ctr_class;
ptr->ctr_class->init((void*)ptr->ctr_keys, key.data, key.size);
br_hmac_drbg_context rng_ctx;
rng_ctx.vtable = &br_hmac_drbg_vtable;
rng_init_sha256_seedFromSystem(&rng_ctx.vtable);
br_hmac_drbg_generate(&rng_ctx, ptr->iv, __AES_STREAM_IV_SIZE);
ptr->block_counter = 0;
}
Result(u32) AESStreamEncryptor_encrypt(AESStreamEncryptor* ptr, Array(u8) src, Array(u8) dst){
Deferral(4);
u32 encrypted_size = AESStreamEncryptor_calcDstSize(src.size);
try_assert(dst.size >= encrypted_size);
// if it is the beginning of the stream, write IV
if(ptr->block_counter == 0){
__Array_writeNext(&dst, ptr->iv, __AES_STREAM_IV_SIZE);
}
// encrypt full buffers
while(src.size > __AES_BUFFER_SIZE){
__Array_readNext(ptr->buf, &src, __AES_BUFFER_SIZE);
ptr->ctr_class->run((void*)ptr->ctr_keys,
ptr->iv, ptr->block_counter,
ptr->buf, __AES_BUFFER_SIZE);
__Array_writeNext(&dst, ptr->buf, __AES_BUFFER_SIZE);
}
// encrypt remaining data
if(src.size > 0){
memcpy(ptr->buf, src.data, src.size);
ptr->ctr_class->run((void*)ptr->ctr_keys,
ptr->iv, ptr->block_counter,
ptr->buf, src.size);
memcpy(dst.data, ptr->buf, src.size);
}
ptr->block_counter++;
Return RESULT_VALUE(u, encrypted_size);
}
void AESStreamDecryptor_construct(AESStreamDecryptor* ptr, Array(u8) key, const br_block_ctr_class* ctr_class){
assert(key.size == 16 || key.size == 24 || key.size == 32);
ptr->ctr_class = ctr_class;
ptr->ctr_class->init((void*)ptr->ctr_keys, key.data, key.size);
ptr->block_counter = 0;
}
Result(u32) AESStreamDecryptor_decrypt(AESStreamDecryptor* ptr, Array(u8) src, Array(u8) dst){
Deferral(4);
try_assert(src.size >= AESStreamEncryptor_calcDstSize(0));
u32 decrypted_size = __AESStreamDecryptor_calcDstSize(src.size);
try_assert(dst.size >= decrypted_size);
// if it is the beginning of the stream, read IV
if(ptr->block_counter == 0){
__Array_readNext(ptr->iv, &src, __AES_STREAM_IV_SIZE);
}
// decrypt full buffers
while(src.size > __AES_BUFFER_SIZE){
__Array_readNext(ptr->buf, &src, __AES_BUFFER_SIZE);
ptr->ctr_class->run((void*)ptr->ctr_keys,
ptr->iv, ptr->block_counter,
ptr->buf, __AES_BUFFER_SIZE);
__Array_writeNext(&dst, ptr->buf, __AES_BUFFER_SIZE);
}
// decrypt remaining data
if(src.size > 0){
memcpy(ptr->buf, src.data, src.size);
ptr->ctr_class->run((void*)ptr->ctr_keys,
ptr->iv, ptr->block_counter,
ptr->buf, src.size);
memcpy(dst.data, ptr->buf, src.size);
}
ptr->block_counter++;
Return RESULT_VALUE(u, decrypted_size);
}

122
src/cryptography/AES.h Normal file
View File

@@ -0,0 +1,122 @@
#pragma once
#include "tlibc/collections/Array.h"
#include "tlibc/errors.h"
#include "bearssl_block.h"
#include "cryptography.h"
//////////////////////////////////////////////////////////////////////////////
// //
// AES.c //
// //
//////////////////////////////////////////////////////////////////////////////
#define AESBlockEncryptor_DEFAULT_CLASS (&br_aes_ct64_cbcenc_vtable)
#define AESBlockDecryptor_DEFAULT_CLASS (&br_aes_ct64_cbcdec_vtable)
#define AESStream_DEFAULT_CLASS (&br_aes_ct64_ctr_vtable)
//TODO: use PKS#7 instead of this garbage
typedef struct EncryptedBlockHeader {
u8 padding_size;
} __attribute__((aligned(16))) EncryptedBlockHeader;
//////////////////////////////////////////////////////////////////////////////
// AESBlockEncryptor //
//////////////////////////////////////////////////////////////////////////////
#define __AES_BLOCK_IV_SIZE 16
// must be multiple of 16
#define __AES_BUFFER_SIZE 512
typedef struct AESBlockEncryptor {
const br_block_cbcenc_class* enc_class;
u8 enc_keys[sizeof(br_aes_ct64_cbcenc_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_BLOCK_IV_SIZE];
br_hmac_drbg_context rng_ctx;
} AESBlockEncryptor;
/// @param key supported sizes: 16, 24, 32
/// @param enc_class &br_aes_XXX_cbcenc_vtable
void AESBlockEncryptor_construct(AESBlockEncryptor* ptr, Array(u8) key, const br_block_cbcenc_class* enc_class);
/// @brief Encrypts a complete message. For part-by-part encryption use AESStreamEncryptor.
/// @param src array of any size
/// @param dst array of size >= AESBlockEncryptor_calcDstSize(src.size)
/// @return size of encrypted data
Result(u32) AESBlockEncryptor_encrypt(AESBlockEncryptor* ptr, Array(u8) src, Array(u8) dst);
#define AESBlockEncryptor_calcDstSize(SRC_SIZE) (__AES_BLOCK_IV_SIZE + sizeof(EncryptedBlockHeader) + ALIGN_TO(SRC_SIZE, 16))
//////////////////////////////////////////////////////////////////////////////
// AESBlockDecryptor //
//////////////////////////////////////////////////////////////////////////////
typedef struct AESBlockDecryptor {
const br_block_cbcdec_class* dec_class;
u8 dec_keys[sizeof(br_aes_ct64_cbcdec_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_BLOCK_IV_SIZE];
} AESBlockDecryptor;
/// @param key supported sizes: 16, 24, 32
/// @param dec_class &br_aes_XXX_cbcdec_vtable
void AESBlockDecryptor_construct(AESBlockDecryptor* ptr, Array(u8) key, const br_block_cbcdec_class* dec_class);
/// @brief Decrypts a complete message. For part-by-part decryption use AESStreamEncryptor.
/// @param src array of size at least AESBlockEncryptor_calcDstSize(0). Size must be multiple of 16.
/// @param dst array of size >= src.size
/// @return size of decrypted data
Result(u32) AESBlockDecryptor_decrypt(AESBlockDecryptor* ptr, Array(u8) src, Array(u8) dst);
//////////////////////////////////////////////////////////////////////////////
// AESStreamEncryptor //
//////////////////////////////////////////////////////////////////////////////
#define __AES_STREAM_IV_SIZE 12
typedef struct AESStreamEncryptor {
const br_block_ctr_class* ctr_class;
u8 ctr_keys[sizeof(br_aes_ct64_ctr_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_STREAM_IV_SIZE];
u32 block_counter;
} AESStreamEncryptor;
/// @warning If you start from not first block in sequence (example: to continue a previously interrupted operation) set correct values for ptr->block_counter and ptr->iv or encryption/decryption will produce incorrect data.
/// @param key supported sizes: 16, 24, 32
/// @param dec_class &br_aes_XXX_ctr_vtable
void AESStreamEncryptor_construct(AESStreamEncryptor* ptr, Array(u8) key, const br_block_ctr_class* ctr_class);
#define AESStreamEncryptor_calcDstSize(src_size) (src_size + __AES_BLOCK_IV_SIZE)
/// @brief If ptr->block_counter == 0, writes random IV to `dst`. After that writes encrypted data to dst.
/// @param src array of any size
/// @param dst array of size >= AESStreamEncryptor_calcDstSize(src.size)
/// @return size of encrypted data
Result(u32) AESStreamEncryptor_encrypt(AESStreamEncryptor* ptr, Array(u8) src, Array(u8) dst);
//////////////////////////////////////////////////////////////////////////////
// AESStreamDecryptor //
//////////////////////////////////////////////////////////////////////////////
typedef struct AESStreamDecryptor {
const br_block_ctr_class* ctr_class;
u8 ctr_keys[sizeof(br_aes_ct64_ctr_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_STREAM_IV_SIZE];
u32 block_counter;
} AESStreamDecryptor;
/// @warning If you start from not first block in sequence (example: to continue a previously interrupted operation) set correct values for ptr->block_counter and ptr->iv or encryption/decryption will produce incorrect data.
/// @param key supported sizes: 16, 24, 32
/// @param dec_class &br_aes_XXX_ctr_vtable
void AESStreamDecryptor_construct(AESStreamDecryptor* ptr, Array(u8) key, const br_block_ctr_class* ctr_class);
/// @brief Reads IV from `src`, then decrypts data and writes it to dst
/// @param src array of size at least AESStreamEncryptor_calcDstSize(0).
/// @param dst array of size >= src.size
/// @return size of decrypted data
Result(u32) AESStreamDecryptor_decrypt(AESStreamDecryptor* ptr, Array(u8) src, Array(u8) dst);
#define __AESStreamDecryptor_calcDstSize(src_size) (src_size - __AES_BLOCK_IV_SIZE)

View File

@@ -1,4 +1,4 @@
#include "cryptography.h"
#include "RSA.h"
#include <assert.h>
#include "bearssl_x509.h"
#include "bearssl_pem.h"
@@ -173,33 +173,55 @@ Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk){
Return RESULT_VOID;
}
void EncryptorRSA_construct(EncryptorRSA* ptr, const br_rsa_public_key* pk){
void RSAEncryptor_construct(RSAEncryptor* ptr, const br_rsa_public_key* pk){
ptr->pk = pk;
ptr->rng.vtable = &br_hmac_drbg_vtable;
rng_init_sha256_seedFromSystem(&ptr->rng.vtable);
}
void EncryptorRSA_encrypt(EncryptorRSA* ptr, Array(u8) src, Array(u8) dst, u32* encrypted_size){
Result(u32) RSAEncryptor_encrypt(RSAEncryptor* ptr, Array(u8) src, Array(u8) dst){
const u32 max_src_size = RSAEncryptor_calcMaxSrcSize(ptr->pk->nlen * 8, 256);
if(src.size > max_src_size){
return RESULT_ERROR_FMT("src.size (%u) must be <= %u (use RSAEncryptor_calcMaxSrcSize)",
src.size, max_src_size);
}
if(dst.size < ptr->pk->nlen){
return RESULT_ERROR_FMT("dst.size (%u) must be >= %u (key length in bytes)",
dst.size, (u32)ptr->pk->nlen);
}
size_t sz = br_rsa_i31_oaep_encrypt(
&ptr->rng.vtable, &br_sha256_vtable,
NULL, 0,
ptr->pk,
dst.data, dst.size,
src.data, src.size);
*encrypted_size = sz;
if(sz == 0){
return RESULT_ERROR("RSA encryption failed", false);
}
return RESULT_VALUE(u, sz);
}
void DecryptorRSA_construct(DecryptorRSA* ptr, const br_rsa_private_key* sk){
void RSADecryptor_construct(RSADecryptor* ptr, const br_rsa_private_key* sk){
ptr->sk = sk;
}
void DecryptorRSA_decrypt(DecryptorRSA* ptr, Array(u8) buf, u32* decrypted_size){
Result(u32) RSADecryptor_decrypt(RSADecryptor* ptr, Array(u8) buf){
if(buf.size != ptr->sk->n_bitlen/8){
return RESULT_ERROR_FMT("buf.size (%u) must be == %u (key length in bytes)",
buf.size, ptr->sk->n_bitlen/8);
}
size_t sz = buf.size;
br_rsa_i31_oaep_decrypt(
size_t r = br_rsa_i31_oaep_decrypt(
&br_sha256_vtable,
NULL, 0,
ptr->sk,
buf.data, &sz);
*decrypted_size = sz;
if(r == 0){
return RESULT_ERROR("RSA encryption failed", false);
}
return RESULT_VALUE(u, sz);
}

105
src/cryptography/RSA.h Normal file
View File

@@ -0,0 +1,105 @@
#pragma once
#include "tlibc/collections/Array.h"
#include "tlibc/errors.h"
#include "bearssl_rsa.h"
#include "cryptography.h"
//////////////////////////////////////////////////////////////////////////////
// //
// RSA.c //
// //
//////////////////////////////////////////////////////////////////////////////
#define RSA_DEFAULT_KEY_SIZE 3072
/// @brief generate random key pair based on system time
/// @param key_size size of public key in bits (2048/3072/4096)
/// @param sk key for decryption
/// @param pk key for encryption
/// @param rng_vtable_ptr pointer to vtable field in prng context. The context must be initialized
Result(void) RSA_generateKeyPair(u32 key_size,
br_rsa_private_key* sk, br_rsa_public_key* pk,
const br_prng_class** rng_vtable_ptr);
Result(void) RSA_generateKeyPairFromTime(u32 key_size,
br_rsa_private_key* sk, br_rsa_public_key* pk);
Result(void) RSA_generateKeyPairFromPassword(u32 key_size,
br_rsa_private_key* sk, br_rsa_public_key* pk, str password);
static inline void RSA_destroyPrivateKey(br_rsa_private_key* sk){
free(sk->p);
}
static inline void RSA_destroyPublicKey(br_rsa_public_key* sk){
free(sk->n);
}
/// @param sk some private key
/// @param pk out public key. WARNING: .n is allocated on heap
Result(void) RSA_computePublicKey(const br_rsa_private_key* sk, br_rsa_public_key* pk);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @return heap-allocated string
str RSA_serializePrivateKey_base64(const br_rsa_private_key* sk);
/// @param src serialized private key format "RSA-Private-%SIZE%:%DATA_BASE64%"
/// @param sk out private key. WARNING: .p is allocated on heap
Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @return heap-allocated string
str RSA_serializePublicKey_base64(const br_rsa_public_key* sk);
/// @param src serialized public key format "RSA-Public-%SIZE%:%DATA_BASE64%"
/// @param sk out public key. WARNING: .p is allocated on heap
Result(void) RSA_parsePublicKey_base64(const str src, br_rsa_public_key* sk);
//////////////////////////////////////////////////////////////////////////////
// RSAEncryptor //
//////////////////////////////////////////////////////////////////////////////
typedef struct RSAEncryptor {
const br_rsa_public_key* pk;
br_hmac_drbg_context rng;
} RSAEncryptor;
/// RSA OAEP encryption with SHA256 hashing algorithm
void RSAEncryptor_construct(RSAEncryptor* ptr, const br_rsa_public_key* pk);
/*
https://crypto.stackexchange.com/a/42100
+---------+----------+-------------------------------------------+
| | overhead | max message size (bytes) |
| Hash | (bytes) | RSA-1024 | RSA-2048 | RSA-3072 | RSA-4096 |
+---------+----------+----------+----------+----------+----------+
| SHA-1 | 42 | 86 | 214 | 342 | 470 |
| SHA-224 | 58 | 70 | 198 | 326 | 454 |
| SHA-256 | 66 | 62 | 190 | 318 | 446 |
| SHA-384 | 98 | 30 | 158 | 286 | 414 |
| SHA-512 | 130 | N/A | 126 | 254 | 382 |
+---------+----------+----------+----------+----------+----------+
*/
#define RSAEncryptor_calcMaxSrcSize(KEY_LEN_BITS, HASH_LEN_BITS) (KEY_LEN_BITS / 8 - 2 * HASH_LEN_BITS / 8 - 2)
/// @param src buffer with size <= `RSAEncryptor_calcMaxSrcSize(key_size_bits, 256)`
/// @param dst buffer with size >= key size in bytes
/// @return size of encrypted data
Result(u32) RSAEncryptor_encrypt(RSAEncryptor* ptr, Array(u8) src, Array(u8) dst);
//////////////////////////////////////////////////////////////////////////////
// RSADecryptor //
//////////////////////////////////////////////////////////////////////////////
typedef struct RSADecryptor {
const br_rsa_private_key* sk;
} RSADecryptor;
/// RSA OAEP encryption with SHA256 hashing algorithm
void RSADecryptor_construct(RSADecryptor* ptr, const br_rsa_private_key* sk);
/// @param buf buffer with size == key size in bytes
/// @return size of decrypted data
Result(u32) RSADecryptor_decrypt(RSADecryptor* ptr, Array(u8) buf);

View File

@@ -1,14 +1,12 @@
#pragma once
#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"
//////////////////////////////////////////////////////////////////////////////
// //
// hash.c //
// //
//////////////////////////////////////////////////////////////////////////////
/// @brief hashes password multiple times using its own hash as salt
@@ -21,7 +19,9 @@ void hash_password(Array(u8) password, u8* out_buffer, i32 iterations);
#define __PASSWORD_HASH_LVL_ITERATIONS 1e5
//////////////////////////////////////////////////////////////////////////////
// rng.c //
// //
// rng.c //
// //
//////////////////////////////////////////////////////////////////////////////
/// @brief Initialize prng context with sha256 hashing algorithm
@@ -42,120 +42,3 @@ void rng_init_sha256_seedFromSystem(const br_prng_class** rng_vtable_ptr);
/// rng_init_sha256_seedFromTime(&rng_ctx.vtable);
/// ```
void rng_init_sha256_seedFromTime(const br_prng_class** rng_vtable_ptr);
//////////////////////////////////////////////////////////////////////////////
// AES.c //
//////////////////////////////////////////////////////////////////////////////
#define __AES_SESSION_KEY_SIZE 32
#define __AES_DB_KEY_SIZE 32
typedef struct EncryptedBlockHeader {
u8 padding_size;
} __attribute__((aligned(16))) EncryptedBlockHeader;
// must be multiple of 16
#define __AES_IV_SIZE 16
// must be multiple of 16
#define __AES_BUFFER_SIZE 512
typedef struct EncryptorAES {
br_aes_ct64_cbcenc_keys enc_ctx;
br_hmac_drbg_context rng_ctx;
u8 iv[__AES_IV_SIZE];
u8 buf[__AES_BUFFER_SIZE];
} EncryptorAES;
/// @param key Array<u8, 16 | 24 | 32>
void EncryptorAES_construct(EncryptorAES* ptr, Array(u8) key);
/// @brief Encrypts `src` and writes output to `dst`.
/// @param src array of any size
/// @param dst array of size >= EncryptorAES_calcDstSize(src.size)
Result(void) EncryptorAES_encrypt(EncryptorAES* ptr, Array(u8) src, Array(u8) dst);
#define EncryptorAES_calcDstSize(SRC_SIZE) (__AES_IV_SIZE + sizeof(EncryptedBlockHeader) + ALIGN_TO(SRC_SIZE, 16))
typedef struct DecryptorAES {
br_aes_ct64_cbcdec_keys dec_ctx;
u8 iv[__AES_IV_SIZE];
u8 buf[__AES_BUFFER_SIZE];
} DecryptorAES;
/// @param key Array<u8, 16 | 24 | 32>
void DecryptorAES_construct(DecryptorAES* ptr, Array(u8) key);
/// @brief Decrypts `src` and writes output to `dst`.
/// @param src array of size at least EncryptorAES_calcDstSize(0). Size must be multiple of 16.
/// @param dst array of size >= src.size
/// @param decrypted_size size of original data without padding added by EncryptorAES_encrypt
Result(void) DecryptorAES_decrypt(DecryptorAES* ptr, Array(u8) src, Array(u8) dst, u32* decrypted_size);
//////////////////////////////////////////////////////////////////////////////
// RSA.c //
//////////////////////////////////////////////////////////////////////////////
#define __RSA_DEFAULT_KEY_SIZE 3072
/// @brief generate random key pair based on system time
/// @param key_size size of public key in bits (2048/3072/4096)
/// @param sk key for decryption
/// @param pk key for encryption
/// @param rng_vtable_ptr pointer to vtable field in prng context. The context must be initialized
Result(void) RSA_generateKeyPair(u32 key_size,
br_rsa_private_key* sk, br_rsa_public_key* pk,
const br_prng_class** rng_vtable_ptr);
Result(void) RSA_generateKeyPairFromTime(u32 key_size,
br_rsa_private_key* sk, br_rsa_public_key* pk);
Result(void) RSA_generateKeyPairFromPassword(u32 key_size,
br_rsa_private_key* sk, br_rsa_public_key* pk, str password);
static inline void RSA_destroyPrivateKey(br_rsa_private_key* sk){
free(sk->p);
}
static inline void RSA_destroyPublicKey(br_rsa_public_key* sk){
free(sk->n);
}
/// @param sk some private key
/// @param pk out public key. WARNING: .n is allocated on heap
Result(void) RSA_computePublicKey(const br_rsa_private_key* sk, br_rsa_public_key* pk);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @return heap-allocated string
str RSA_serializePrivateKey_base64(const br_rsa_private_key* sk);
/// @param src serialized private key format "RSA-Private-%SIZE%:%DATA_BASE64%"
/// @param sk out private key. WARNING: .p is allocated on heap
Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @return heap-allocated string
str RSA_serializePublicKey_base64(const br_rsa_public_key* sk);
/// @param src serialized public key format "RSA-Public-%SIZE%:%DATA_BASE64%"
/// @param sk out public key. WARNING: .p is allocated on heap
Result(void) RSA_parsePublicKey_base64(const str src, br_rsa_public_key* sk);
typedef struct EncryptorRSA {
const br_rsa_public_key* pk;
br_hmac_drbg_context rng;
} EncryptorRSA;
void EncryptorRSA_construct(EncryptorRSA* ptr, const br_rsa_public_key* pk);
void EncryptorRSA_encrypt(EncryptorRSA* ptr, Array(u8) src, Array(u8) dst, u32* encrypted_size);
typedef struct DecryptorRSA {
const br_rsa_private_key* sk;
} DecryptorRSA;
void DecryptorRSA_construct(DecryptorRSA* ptr, const br_rsa_private_key* sk);
void DecryptorRSA_decrypt(DecryptorRSA* ptr, Array(u8) buf, u32* decrypted_size);