tcp-chat/src/cryptography/AES.h

140 lines
6.4 KiB
C

#pragma once
#include "tlibc/collections/Array.h"
#include "tlibc/errors.h"
#include "tlibc/magic.h"
#include "bearssl_block.h"
#include "cryptography.h"
//////////////////////////////////////////////////////////////////////////////
// //
// AES.c //
// //
//////////////////////////////////////////////////////////////////////////////
#define AESBlockEncryptor_DEFAULT_CLASS (&br_aes_big_cbcenc_vtable)
#define AESBlockDecryptor_DEFAULT_CLASS (&br_aes_big_cbcdec_vtable)
#define AESStream_DEFAULT_CLASS (&br_aes_big_ctr_vtable)
#define __AES_BLOCK_KEY_CHECKSUM_SIZE br_sha256_SIZE
typedef struct EncryptedBlockHeader {
u8 key_checksum[__AES_BLOCK_KEY_CHECKSUM_SIZE];
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_big_cbcenc_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_BLOCK_IV_SIZE];
u8 key_checksum[__AES_BLOCK_KEY_CHECKSUM_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);
/// @param key supported sizes: 16, 24, 32
void AESBlockEncryptor_changeKey(AESBlockEncryptor* ptr, Array(u8) key);
/// @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_big_cbcdec_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_BLOCK_IV_SIZE];
u8 key_checksum[__AES_BLOCK_KEY_CHECKSUM_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);
/// @param key supported sizes: 16, 24, 32
void AESBlockDecryptor_changeKey(AESBlockDecryptor* ptr, Array(u8) key);
/// @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_big_ctr_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_STREAM_IV_SIZE];
u8 key_checksum[__AES_BLOCK_KEY_CHECKSUM_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);
/// @param key supported sizes: 16, 24, 32
void AESStreamEncryptor_changeKey(AESStreamEncryptor* ptr, Array(u8) key);
/// use this only at the beginning of the stream
#define AESStreamEncryptor_calcDstSize(src_size) (__AES_STREAM_IV_SIZE + __AES_BLOCK_KEY_CHECKSUM_SIZE + src_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)` for first block and `src.size `for other blocks
/// @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_big_ctr_keys)];
u8 buf[__AES_BUFFER_SIZE];
u8 iv[__AES_STREAM_IV_SIZE];
u8 key_checksum[__AES_BLOCK_KEY_CHECKSUM_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);
/// @param key supported sizes: 16, 24, 32
void AESStreamDecryptor_changeKey(AESStreamDecryptor* ptr, Array(u8) key);
/// @brief Reads IV from `src`, then decrypts data and writes it to dst
/// @param src array of any size
/// @param dst array of size >= src.size
/// @return size of decrypted data
Result(u32) AESStreamDecryptor_decrypt(AESStreamDecryptor* ptr, Array(u8) src, Array(u8) dst);