263 lines
8.9 KiB
C
263 lines
8.9 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <openssl/hmac.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/rand.h>
|
|
|
|
#define DEFAULT_SALT_SIZE 32 // Salt size for key derivation
|
|
#define DEFAULT_IV_SIZE 16 // IV size (128 bits)
|
|
#define DEFAULT_KEY_SIZE 32 // Key size (256 bits)
|
|
#define DEFAULT_ROUNDS 10000 // Rounds
|
|
#define DEFAULT_BLOCK_SIZE 16 // 128 bits
|
|
#define HMAC_KEY_SIZE 32 // Key size for HMAC (256 bits)
|
|
|
|
// Function prototypes
|
|
void generate_random_bytes(uint8_t *buffer, size_t size);
|
|
void pbkdf2(const char *password, uint8_t *salt, int salt_len, uint8_t *output, int output_len, int iterations);
|
|
void xor_buffers(uint8_t *a, uint8_t *b, uint8_t *result, size_t length);
|
|
void generate_hmac(uint8_t *data, size_t data_len, uint8_t *key, size_t key_len, uint8_t *hmac_out);
|
|
int are_equal(const uint8_t *a, const uint8_t *b, size_t length);
|
|
|
|
// EonaCatCipher structure
|
|
typedef struct {
|
|
uint8_t derived_key[DEFAULT_KEY_SIZE];
|
|
uint8_t hmac_key[HMAC_KEY_SIZE];
|
|
int iv_size;
|
|
int key_size;
|
|
int rounds;
|
|
int block_size;
|
|
} EonaCatCipher;
|
|
|
|
// EonaCatCrypto structure
|
|
typedef struct {
|
|
uint8_t *key;
|
|
uint8_t *nonce;
|
|
int block_size;
|
|
int rounds;
|
|
uint64_t *state;
|
|
uint32_t block_counter;
|
|
} EonaCatCrypto;
|
|
|
|
// Function to create and initialize EonaCatCipher
|
|
EonaCatCipher* eonacat_cipher_create(const char *password) {
|
|
if (password == NULL || strlen(password) == 0) {
|
|
fprintf(stderr, "EonaCatCipher: Password cannot be null or empty.\n");
|
|
return NULL;
|
|
}
|
|
|
|
EonaCatCipher *cipher = malloc(sizeof(EonaCatCipher));
|
|
if (!cipher) {
|
|
fprintf(stderr, "EonaCatCipher: Memory allocation failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
cipher->iv_size = DEFAULT_IV_SIZE;
|
|
cipher->key_size = DEFAULT_KEY_SIZE;
|
|
cipher->rounds = DEFAULT_ROUNDS;
|
|
cipher->block_size = DEFAULT_BLOCK_SIZE;
|
|
|
|
uint8_t salt[DEFAULT_SALT_SIZE];
|
|
generate_random_bytes(salt, sizeof(salt));
|
|
pbkdf2(password, salt, sizeof(salt), cipher->derived_key, sizeof(cipher->derived_key), cipher->rounds);
|
|
pbkdf2(password, salt, sizeof(salt), cipher->hmac_key, sizeof(cipher->hmac_key), cipher->rounds);
|
|
|
|
return cipher;
|
|
}
|
|
|
|
// Function to clean up and free EonaCatCipher
|
|
void eonacat_cipher_destroy(EonaCatCipher *cipher) {
|
|
if (cipher) {
|
|
memset(cipher, 0, sizeof(EonaCatCipher));
|
|
free(cipher);
|
|
}
|
|
}
|
|
|
|
// PBKDF2 implementation
|
|
void pbkdf2(const char *password, uint8_t *salt, int salt_len, uint8_t *output, int output_len, int iterations) {
|
|
int hash_len = SHA256_DIGEST_LENGTH;
|
|
int blocks_needed = (output_len + hash_len - 1) / hash_len;
|
|
|
|
uint8_t u[hash_len];
|
|
uint8_t t[hash_len];
|
|
|
|
for (int block_index = 1; block_index <= blocks_needed; block_index++) {
|
|
// Step 1: F(block_index)
|
|
uint8_t block[salt_len + 4];
|
|
memcpy(block, salt, salt_len);
|
|
uint32_t block_index_network = htonl(block_index);
|
|
memcpy(block + salt_len, &block_index_network, 4);
|
|
|
|
// Step 2: U1 = HMAC(password, salt + block_index)
|
|
unsigned int len = 0;
|
|
HMAC(EVP_sha256(), password, strlen(password), block, sizeof(block), u, &len);
|
|
|
|
memcpy(t, u, hash_len);
|
|
memcpy(output + (block_index - 1) * hash_len, t, (block_index == blocks_needed && output_len % hash_len != 0) ? output_len % hash_len : hash_len);
|
|
|
|
// Step 4: Iterations
|
|
for (int iteration = 1; iteration < iterations; iteration++) {
|
|
// U2 = HMAC(password, U1)
|
|
HMAC(EVP_sha256(), password, strlen(password), u, hash_len, u, &len);
|
|
xor_buffers(t, u, t, hash_len);
|
|
memcpy(output + (block_index - 1) * hash_len, t, (block_index == blocks_needed && output_len % hash_len != 0) ? output_len % hash_len : hash_len);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function to generate random bytes
|
|
void generate_random_bytes(uint8_t *buffer, size_t size) {
|
|
RAND_bytes(buffer, size);
|
|
}
|
|
|
|
// Function to perform XOR operation on two buffers
|
|
void xor_buffers(uint8_t *a, uint8_t *b, uint8_t *result, size_t length) {
|
|
for (size_t i = 0; i < length; i++) {
|
|
result[i] = a[i] ^ b[i];
|
|
}
|
|
}
|
|
|
|
// Function to generate HMAC
|
|
void generate_hmac(uint8_t *data, size_t data_len, uint8_t *key, size_t key_len, uint8_t *hmac_out) {
|
|
unsigned int len = 0;
|
|
HMAC(EVP_sha256(), key, key_len, data, data_len, hmac_out, &len);
|
|
}
|
|
|
|
// Function to compare two buffers
|
|
int are_equal(const uint8_t *a, const uint8_t *b, size_t length) {
|
|
return (memcmp(a, b, length) == 0);
|
|
}
|
|
|
|
// Function to encrypt plaintext
|
|
uint8_t* eonacat_cipher_encrypt(EonaCatCipher *cipher, const char *plaintext, size_t *out_len) {
|
|
uint8_t iv[cipher->iv_size];
|
|
generate_random_bytes(iv, cipher->iv_size);
|
|
|
|
size_t plaintext_len = strlen(plaintext);
|
|
uint8_t *ciphertext = malloc(plaintext_len + cipher->iv_size);
|
|
if (!ciphertext) {
|
|
fprintf(stderr, "Memory allocation failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(ciphertext, iv, cipher->iv_size); // Combine IV and ciphertext
|
|
uint8_t encrypted[plaintext_len];
|
|
|
|
EonaCatCrypto crypto;
|
|
crypto.key = cipher->derived_key;
|
|
crypto.nonce = iv;
|
|
crypto.block_size = cipher->block_size;
|
|
crypto.rounds = cipher->rounds;
|
|
crypto.block_counter = 0;
|
|
crypto.state = calloc(cipher->block_size / 4, sizeof(uint64_t));
|
|
|
|
// Encrypt the plaintext (dummy XOR for demonstration purposes)
|
|
for (size_t i = 0; i < plaintext_len; i++) {
|
|
encrypted[i] = plaintext[i] ^ iv[i % cipher->iv_size];
|
|
}
|
|
|
|
memcpy(ciphertext + cipher->iv_size, encrypted, plaintext_len); // Append ciphertext
|
|
|
|
// Generate HMAC for integrity check
|
|
uint8_t hmac[HMAC_KEY_SIZE];
|
|
generate_hmac(ciphertext, plaintext_len + cipher->iv_size, cipher->hmac_key, sizeof(cipher->hmac_key), hmac);
|
|
|
|
*out_len = plaintext_len + cipher->iv_size + HMAC_KEY_SIZE;
|
|
uint8_t *final_result = realloc(ciphertext, *out_len);
|
|
if (!final_result) {
|
|
free(ciphertext);
|
|
fprintf(stderr, "Memory allocation failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(final_result + *out_len - HMAC_KEY_SIZE, hmac, HMAC_KEY_SIZE); // Combine result and HMAC
|
|
|
|
return final_result;
|
|
}
|
|
|
|
// Function to decrypt ciphertext
|
|
char* eonacat_cipher_decrypt(EonaCatCipher *cipher, uint8_t *ciphertext_with_hmac, size_t ciphertext_len) {
|
|
uint8_t provided_hmac[HMAC_KEY_SIZE];
|
|
memcpy(provided_hmac, ciphertext_with_hmac + ciphertext_len - HMAC_KEY_SIZE, HMAC_KEY_SIZE);
|
|
|
|
size_t ciphertext_size = ciphertext_len - HMAC_KEY_SIZE;
|
|
uint8_t *ciphertext = malloc(ciphertext_size);
|
|
if (!ciphertext) {
|
|
fprintf(stderr, "EonaCatCipher: Memory allocation failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(ciphertext, ciphertext_with_hmac, ciphertext_size); // Separate HMAC from the ciphertext
|
|
|
|
// Verify HMAC before decrypting
|
|
uint8_t calculated_hmac[HMAC_KEY_SIZE];
|
|
generate_hmac(ciphertext, ciphertext_size, cipher->hmac_key, sizeof(cipher->hmac_key), calculated_hmac);
|
|
if (!are_equal(provided_hmac, calculated_hmac, HMAC_KEY_SIZE)) {
|
|
free(ciphertext);
|
|
fprintf(stderr, "EonaCatCipher: HMAC validation failed. Data may have been tampered with.\n");
|
|
return NULL;
|
|
}
|
|
|
|
uint8_t iv[cipher->iv_size];
|
|
memcpy(iv, ciphertext, cipher->iv_size); // Extract IV
|
|
|
|
size_t plaintext_len = ciphertext_size - cipher->iv_size;
|
|
char *plaintext = malloc(plaintext_len + 1);
|
|
if (!plaintext) {
|
|
free(ciphertext);
|
|
fprintf(stderr, "EonaCatCipher: Memory allocation failed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
// Decrypt
|
|
for (size_t i = 0; i < plaintext_len; i++) {
|
|
plaintext[i] = ciphertext[cipher->iv_size + i] ^ iv[i % cipher->iv_size];
|
|
}
|
|
|
|
plaintext[plaintext_len] = '\0'; // Null-terminate the plaintext
|
|
|
|
free(ciphertext);
|
|
return plaintext;
|
|
}
|
|
|
|
// Main function to demonstrate encryption and decryption
|
|
int main() {
|
|
const char *password = "securePassword123!@#$";
|
|
const char *plaintext = "Thank you for using EonaCatCipher!";
|
|
size_t out_len;
|
|
|
|
printf("Encrypting '%s' with password '%s'\n", plaintext, password);
|
|
printf("================\n");
|
|
|
|
EonaCatCipher *cipher = eonacat_cipher_create(password);
|
|
if (!cipher) return 1;
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
printf("Encryption round %d: \n", i + 1);
|
|
printf("================\n");
|
|
|
|
uint8_t *encrypted = eonacat_cipher_encrypt(cipher, plaintext, &out_len);
|
|
if (encrypted) {
|
|
printf("Encrypted (byte array): ");
|
|
for (size_t j = 0; j < out_len; j++) {
|
|
printf("%02X", encrypted[j]);
|
|
}
|
|
printf("\n");
|
|
|
|
char *decrypted = eonacat_cipher_decrypt(cipher, encrypted, out_len);
|
|
if (decrypted) {
|
|
printf("Decrypted: %s\n", decrypted);
|
|
free(decrypted);
|
|
}
|
|
|
|
free(encrypted);
|
|
}
|
|
|
|
printf("================\n");
|
|
}
|
|
|
|
eonacat_cipher_destroy(cipher);
|
|
return 0;
|
|
}
|