luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

EasyCrypto.c (10083B)


      1 /*
      2  * EasyCrypto.c - Implementation of simple encryption API
      3  */
      4 
      5 #include "EasyCrypto.h"
      6 #include "CSPRNG.h"
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <stdlib.h>
     10 #include <stdint.h>
     11 #include <time.h>
     12 #include <immintrin.h>
     13 #include <wmmintrin.h>
     14 
     15 #ifdef __GNUC__
     16 #include <cpuid.h>
     17 #endif
     18 
     19 // Global key storage
     20 uint8_t EASYCRYPTO_KEY[32] = {0};
     21 
     22 // CPU feature flags
     23 static int g_has_aesni = 0;
     24 static int g_has_pclmulqdq = 0;
     25 static int g_initialized = 0;
     26 
     27 // Include algorithm implementations inline
     28 // AES-256 structures and functions
     29 typedef struct {
     30     __m128i round_keys[15];
     31     int nr;
     32 } aes256_key_schedule;
     33 
     34 typedef struct {
     35     aes256_key_schedule key_schedule;
     36     __m128i H;
     37     __m128i H_powers[8];
     38 } aes256_gcm_context;
     39 
     40 // Serpent structures
     41 typedef struct {
     42     uint32_t subkeys[33][4];
     43 } serpent_key_schedule;
     44 
     45 typedef struct {
     46     serpent_key_schedule key_schedule;
     47     __m128i H;
     48     __m128i H_powers[8];
     49 } serpent_gcm_context;
     50 
     51 // Forward declarations
     52 static void detect_cpu_features(void);
     53 static int aes256_gcm_init(aes256_gcm_context *ctx, const uint8_t *key);
     54 static int aes256_gcm_encrypt(aes256_gcm_context *ctx, const uint8_t *iv, size_t iv_len,
     55                               const uint8_t *aad, size_t aad_len,
     56                               const uint8_t *plaintext, size_t pt_len,
     57                               uint8_t *ciphertext, uint8_t *tag, size_t tag_len);
     58 static int aes256_gcm_decrypt(aes256_gcm_context *ctx, const uint8_t *iv, size_t iv_len,
     59                               const uint8_t *aad, size_t aad_len,
     60                               const uint8_t *ciphertext, size_t ct_len,
     61                               const uint8_t *tag, size_t tag_len, uint8_t *plaintext);
     62 
     63 static int serpent_gcm_init(serpent_gcm_context *ctx, const uint8_t *key);
     64 static int serpent_gcm_encrypt(serpent_gcm_context *ctx, const uint8_t *iv, size_t iv_len,
     65                                const uint8_t *aad, size_t aad_len,
     66                                const uint8_t *plaintext, size_t pt_len,
     67                                uint8_t *ciphertext, uint8_t *tag, size_t tag_len);
     68 static int serpent_gcm_decrypt(serpent_gcm_context *ctx, const uint8_t *iv, size_t iv_len,
     69                                const uint8_t *aad, size_t aad_len,
     70                                const uint8_t *ciphertext, size_t ct_len,
     71                                const uint8_t *tag, size_t tag_len, uint8_t *plaintext);
     72 
     73 // CPU feature detection
     74 static void detect_cpu_features(void) {
     75 #ifdef __GNUC__
     76     unsigned int eax, ebx, ecx, edx;
     77     if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
     78         g_has_aesni = (ecx & bit_AES) != 0;
     79         g_has_pclmulqdq = (ecx & bit_PCLMUL) != 0;
     80     }
     81 #endif
     82 }
     83 
     84 // Generate random IV using global CSPRNG
     85 static void generate_random_iv(uint8_t *iv, size_t len) {
     86     random_bytes(iv, len);
     87 }
     88 
     89 // Public API implementation
     90 void easycrypto_init(void) {
     91     if (!g_initialized) {
     92         detect_cpu_features();
     93         g_initialized = 1;
     94     }
     95 }
     96 
     97 void easycrypto_set_key(const uint8_t *key) {
     98     memcpy(EASYCRYPTO_KEY, key, 32);
     99 }
    100 
    101 void easycrypto_generate_key(uint8_t *key) {
    102     generate_random_iv(key, 32);
    103 }
    104 
    105 CryptoResult easycrypto_encrypt(CryptoAlgorithm algo, const uint8_t *plaintext,
    106                                 size_t plaintext_len, const uint8_t *aad, size_t aad_len) {
    107     CryptoResult result = {NULL, 0, 0};
    108 
    109     if (!g_initialized) {
    110         easycrypto_init();
    111     }
    112 
    113     // Check if key is set
    114     int key_is_zero = 1;
    115     for (int i = 0; i < 32; i++) {
    116         if (EASYCRYPTO_KEY[i] != 0) {
    117             key_is_zero = 0;
    118             break;
    119         }
    120     }
    121     if (key_is_zero) {
    122         fprintf(stderr, "Error: Encryption key not set. Call easycrypto_set_key() first.\n");
    123         return result;
    124     }
    125 
    126     // Generate random IV (12 bytes for GCM)
    127     uint8_t iv[12];
    128     generate_random_iv(iv, 12);
    129 
    130     // Allocate output buffer: [1 byte algo][12 bytes iv][plaintext_len bytes ct][16 bytes tag]
    131     size_t output_len = 1 + 12 + plaintext_len + 16;
    132     uint8_t *output = malloc(output_len);
    133     if (!output) {
    134         fprintf(stderr, "Error: Memory allocation failed\n");
    135         return result;
    136     }
    137 
    138     // Write algorithm ID
    139     output[0] = (uint8_t)algo;
    140 
    141     // Write IV
    142     memcpy(output + 1, iv, 12);
    143 
    144     // Encrypt based on algorithm
    145     uint8_t *ciphertext = output + 1 + 12;
    146     uint8_t *tag = output + 1 + 12 + plaintext_len;
    147 
    148     int encrypt_result = -1;
    149 
    150     if (algo == AES_256_GCM) {
    151         if (!g_has_aesni || !g_has_pclmulqdq) {
    152             fprintf(stderr, "Error: CPU does not support AES-NI/PCLMULQDQ\n");
    153             free(output);
    154             return result;
    155         }
    156 
    157         aes256_gcm_context ctx;
    158         if (aes256_gcm_init(&ctx, EASYCRYPTO_KEY) != 0) {
    159             free(output);
    160             return result;
    161         }
    162 
    163         encrypt_result = aes256_gcm_encrypt(&ctx, iv, 12, aad, aad_len,
    164                                            plaintext, plaintext_len,
    165                                            ciphertext, tag, 16);
    166     } else if (algo == SERPENT_256_GCM) {
    167         if (!g_has_pclmulqdq) {
    168             fprintf(stderr, "Error: CPU does not support PCLMULQDQ\n");
    169             free(output);
    170             return result;
    171         }
    172 
    173         serpent_gcm_context ctx;
    174         if (serpent_gcm_init(&ctx, EASYCRYPTO_KEY) != 0) {
    175             free(output);
    176             return result;
    177         }
    178 
    179         encrypt_result = serpent_gcm_encrypt(&ctx, iv, 12, aad, aad_len,
    180                                             plaintext, plaintext_len,
    181                                             ciphertext, tag, 16);
    182     } else {
    183         fprintf(stderr, "Error: Unknown algorithm\n");
    184         free(output);
    185         return result;
    186     }
    187 
    188     if (encrypt_result != 0) {
    189         fprintf(stderr, "Error: Encryption failed\n");
    190         free(output);
    191         return result;
    192     }
    193 
    194     result.data = output;
    195     result.length = output_len;
    196     result.success = 1;
    197 
    198     return result;
    199 }
    200 
    201 CryptoResult easycrypto_decrypt(const uint8_t *encrypted, size_t encrypted_len,
    202                                 const uint8_t *aad, size_t aad_len) {
    203     CryptoResult result = {NULL, 0, 0};
    204 
    205     if (!g_initialized) {
    206         easycrypto_init();
    207     }
    208 
    209     // Minimum size: 1 (algo) + 12 (iv) + 0 (plaintext) + 16 (tag) = 29 bytes
    210     if (encrypted_len < 29) {
    211         fprintf(stderr, "Error: Encrypted data too short\n");
    212         return result;
    213     }
    214 
    215     // Extract algorithm
    216     CryptoAlgorithm algo = (CryptoAlgorithm)encrypted[0];
    217 
    218     // Extract IV
    219     const uint8_t *iv = encrypted + 1;
    220 
    221     // Extract ciphertext and tag
    222     size_t ct_len = encrypted_len - 1 - 12 - 16;
    223     const uint8_t *ciphertext = encrypted + 1 + 12;
    224     const uint8_t *tag = encrypted + 1 + 12 + ct_len;
    225 
    226     // Allocate plaintext buffer
    227     uint8_t *plaintext = malloc(ct_len);
    228     if (!plaintext) {
    229         fprintf(stderr, "Error: Memory allocation failed\n");
    230         return result;
    231     }
    232 
    233     int decrypt_result = -1;
    234 
    235     if (algo == AES_256_GCM) {
    236         if (!g_has_aesni || !g_has_pclmulqdq) {
    237             fprintf(stderr, "Error: CPU does not support AES-NI/PCLMULQDQ\n");
    238             free(plaintext);
    239             return result;
    240         }
    241 
    242         aes256_gcm_context ctx;
    243         if (aes256_gcm_init(&ctx, EASYCRYPTO_KEY) != 0) {
    244             free(plaintext);
    245             return result;
    246         }
    247 
    248         decrypt_result = aes256_gcm_decrypt(&ctx, iv, 12, aad, aad_len,
    249                                            ciphertext, ct_len, tag, 16, plaintext);
    250     } else if (algo == SERPENT_256_GCM) {
    251         if (!g_has_pclmulqdq) {
    252             fprintf(stderr, "Error: CPU does not support PCLMULQDQ\n");
    253             free(plaintext);
    254             return result;
    255         }
    256 
    257         serpent_gcm_context ctx;
    258         if (serpent_gcm_init(&ctx, EASYCRYPTO_KEY) != 0) {
    259             free(plaintext);
    260             return result;
    261         }
    262 
    263         decrypt_result = serpent_gcm_decrypt(&ctx, iv, 12, aad, aad_len,
    264                                             ciphertext, ct_len, tag, 16, plaintext);
    265     } else {
    266         fprintf(stderr, "Error: Unknown algorithm: 0x%02x\n", algo);
    267         free(plaintext);
    268         return result;
    269     }
    270 
    271     if (decrypt_result != 0) {
    272         fprintf(stderr, "Error: Decryption/Authentication failed\n");
    273         free(plaintext);
    274         return result;
    275     }
    276 
    277     result.data = plaintext;
    278     result.length = ct_len;
    279     result.success = 1;
    280 
    281     return result;
    282 }
    283 
    284 void easycrypto_free(CryptoResult *result) {
    285     if (result && result->data) {
    286         free(result->data);
    287         result->data = NULL;
    288         result->length = 0;
    289         result->success = 0;
    290     }
    291 }
    292 
    293 void easycrypto_print_hex(const char *label, const uint8_t *data, size_t len) {
    294     printf("%s: ", label);
    295     for (size_t i = 0; i < len; i++) {
    296         printf("%02x", data[i]);
    297         if ((i + 1) % 16 == 0 && i + 1 < len) {
    298             printf("\n%*s", (int)strlen(label) + 2, "");
    299         }
    300     }
    301     printf("\n");
    302 }
    303 
    304 const char* easycrypto_algorithm_name(CryptoAlgorithm algo) {
    305     switch (algo) {
    306         case AES_256_GCM: return "AES-256-GCM";
    307         case SERPENT_256_GCM: return "Serpent-256-GCM";
    308         case TWOFISH_256_GCM: return "Twofish-256-GCM";
    309         default: return "Unknown";
    310     }
    311 }
    312 
    313 // Now include the actual AES and Serpent implementations
    314 // (We need to include the core crypto functions here)
    315 
    316 // This is a placeholder - in a real implementation, you would either:
    317 // 1. Include the full implementations from the other files
    318 // 2. Link against compiled object files
    319 // 3. Create a shared library
    320 
    321 // For now, I'll include minimal implementations that reference the full versions
    322 
    323 // Include marker comment - the full implementations would go here
    324 // To keep this file manageable, we'll link against the compiled versions
    325 
    326 // NOTE: This file needs to be linked with compiled versions of:
    327 // - AES-256-GCM.c (extract just the core functions)
    328 // - Serpent-256-GCM.c (extract just the core functions)
    329 
    330 // For a complete standalone version, we need to extract the crypto core functions
    331 // Let me create a proper modular version in the next file