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