EasyHashing.h (10480B)
1 /* 2 * EasyHashing.h - Simple hash API with automatic memory management 3 * 4 * Usage: 5 * // Hash with SHA-256 (default) 6 * HashResult hash = HASH(data, data_len); 7 * 8 * // Hash with specific algorithm 9 * HashResult hash = SHA512(data, data_len); 10 * HashResult hash = SHA256(data, data_len); 11 * HashResult hash = SHA1(data, data_len); 12 * HashResult hash = MD5(data, data_len); 13 * HashResult hash = CRC32(data, data_len); 14 * 15 * // Print result 16 * HASH_PRINT(hash); 17 * 18 * // Get hex string 19 * char *hex = HASH_HEX(hash); 20 * free(hex); 21 * 22 * // Get base64 string 23 * char *b64 = HASH_B64(hash); 24 * free(b64); 25 * 26 * // Free result 27 * HASH_FREE(hash); 28 * 29 * String convenience: 30 * HashResult hash = HASH_STR("hello world"); 31 * HashResult hash = SHA512_STR("password"); 32 * 33 * Base64 output: 34 * char *b64 = HASH_B64_STR("hello"); // Hash string, return base64 35 * char *b64 = HASH_B64_DATA(data, len); // Hash data, return base64 36 */ 37 38 #ifndef EASYHASHING_H 39 #define EASYHASHING_H 40 41 #include <stdint.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <stdio.h> 45 46 // Hash result structure 47 typedef struct { 48 uint8_t *digest; 49 size_t digest_len; 50 const char *algorithm_name; 51 } HashResult; 52 53 // Forward declarations for hash functions 54 void sha256(const uint8_t *data, size_t len, uint8_t digest[32]); 55 void sha512(const uint8_t *data, size_t len, uint8_t digest[64]); 56 void sha1(const uint8_t *data, size_t len, uint8_t digest[20]); 57 void md5(const uint8_t *data, size_t len, uint8_t digest[16]); 58 uint32_t crc32(const uint8_t *data, size_t len); 59 60 // Base64 encoding table 61 static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 62 63 // Base64 encode function 64 static inline char* base64_encode(const uint8_t *data, size_t len) { 65 size_t output_len = 4 * ((len + 2) / 3); 66 char *encoded = (char*)malloc(output_len + 1); 67 if (!encoded) return NULL; 68 69 size_t i, j; 70 for (i = 0, j = 0; i < len;) { 71 uint32_t octet_a = i < len ? data[i++] : 0; 72 uint32_t octet_b = i < len ? data[i++] : 0; 73 uint32_t octet_c = i < len ? data[i++] : 0; 74 75 uint32_t triple = (octet_a << 16) + (octet_b << 8) + octet_c; 76 77 encoded[j++] = base64_table[(triple >> 18) & 0x3F]; 78 encoded[j++] = base64_table[(triple >> 12) & 0x3F]; 79 encoded[j++] = base64_table[(triple >> 6) & 0x3F]; 80 encoded[j++] = base64_table[triple & 0x3F]; 81 } 82 83 // Add padding 84 size_t mod = len % 3; 85 if (mod > 0) { 86 for (size_t k = 0; k < (3 - mod); k++) { 87 encoded[output_len - 1 - k] = '='; 88 } 89 } 90 91 encoded[output_len] = '\0'; 92 return encoded; 93 } 94 95 // Internal helper functions 96 static inline HashResult easyhash_create_result(size_t digest_len, const char *name) { 97 HashResult result; 98 result.digest = (uint8_t*)malloc(digest_len); 99 result.digest_len = digest_len; 100 result.algorithm_name = name; 101 return result; 102 } 103 104 static inline HashResult easyhash_sha256(const uint8_t *data, size_t len) { 105 HashResult result = easyhash_create_result(32, "SHA-256"); 106 if (result.digest) { 107 sha256(data, len, result.digest); 108 } 109 return result; 110 } 111 112 static inline HashResult easyhash_sha512(const uint8_t *data, size_t len) { 113 HashResult result = easyhash_create_result(64, "SHA-512"); 114 if (result.digest) { 115 sha512(data, len, result.digest); 116 } 117 return result; 118 } 119 120 static inline HashResult easyhash_sha1(const uint8_t *data, size_t len) { 121 HashResult result = easyhash_create_result(20, "SHA-1"); 122 if (result.digest) { 123 sha1(data, len, result.digest); 124 } 125 return result; 126 } 127 128 static inline HashResult easyhash_md5(const uint8_t *data, size_t len) { 129 HashResult result = easyhash_create_result(16, "MD5"); 130 if (result.digest) { 131 md5(data, len, result.digest); 132 } 133 return result; 134 } 135 136 static inline HashResult easyhash_crc32(const uint8_t *data, size_t len) { 137 HashResult result = easyhash_create_result(4, "CRC32"); 138 if (result.digest) { 139 uint32_t crc = crc32(data, len); 140 result.digest[0] = (crc >> 24) & 0xFF; 141 result.digest[1] = (crc >> 16) & 0xFF; 142 result.digest[2] = (crc >> 8) & 0xFF; 143 result.digest[3] = crc & 0xFF; 144 } 145 return result; 146 } 147 148 // Main hash macros - explicit algorithms 149 #define SHA256(data, len) easyhash_sha256((const uint8_t*)(data), (size_t)(len)) 150 #define SHA512(data, len) easyhash_sha512((const uint8_t*)(data), (size_t)(len)) 151 #define SHA1(data, len) easyhash_sha1((const uint8_t*)(data), (size_t)(len)) 152 #define MD5(data, len) easyhash_md5((const uint8_t*)(data), (size_t)(len)) 153 #define CRC32(data, len) easyhash_crc32((const uint8_t*)(data), (size_t)(len)) 154 155 // Default hash macro (uses SHA-256) 156 #define HASH(data, len) SHA256(data, len) 157 158 // String convenience macros 159 #define SHA256_STR(str) SHA256(str, strlen(str)) 160 #define SHA512_STR(str) SHA512(str, strlen(str)) 161 #define SHA1_STR(str) SHA1(str, strlen(str)) 162 #define MD5_STR(str) MD5(str, strlen(str)) 163 #define CRC32_STR(str) CRC32(str, strlen(str)) 164 #define HASH_STR(str) HASH(str, strlen(str)) 165 166 // Free hash result 167 #define HASH_FREE(result) do { \ 168 if ((result).digest) { \ 169 free((result).digest); \ 170 (result).digest = NULL; \ 171 (result).digest_len = 0; \ 172 } \ 173 } while(0) 174 175 // Print hash result 176 static inline void easyhash_print(const char *label, const HashResult *result) { 177 if (!result || !result->digest) { 178 printf("%s: (null)\n", label); 179 return; 180 } 181 182 printf("%s (%s): ", label, result->algorithm_name); 183 184 if (strcmp(result->algorithm_name, "CRC32") == 0) { 185 uint32_t crc = ((uint32_t)result->digest[0] << 24) | 186 ((uint32_t)result->digest[1] << 16) | 187 ((uint32_t)result->digest[2] << 8) | 188 ((uint32_t)result->digest[3]); 189 printf("0x%08x\n", crc); 190 } else { 191 for (size_t i = 0; i < result->digest_len; i++) { 192 printf("%02x", result->digest[i]); 193 } 194 printf("\n"); 195 } 196 } 197 198 #define HASH_PRINT(result) easyhash_print(#result, &(result)) 199 #define HASH_PRINT_LABEL(label, result) easyhash_print(label, &(result)) 200 201 // Convert hash to hex string (caller must free) 202 static inline char* easyhash_to_hex(const HashResult *result) { 203 if (!result || !result->digest) { 204 return NULL; 205 } 206 207 size_t hex_len; 208 if (strcmp(result->algorithm_name, "CRC32") == 0) { 209 hex_len = 11; // "0x" + 8 hex digits + null 210 } else { 211 hex_len = result->digest_len * 2 + 1; 212 } 213 214 char *hex = (char*)malloc(hex_len); 215 if (!hex) { 216 return NULL; 217 } 218 219 if (strcmp(result->algorithm_name, "CRC32") == 0) { 220 uint32_t crc = ((uint32_t)result->digest[0] << 24) | 221 ((uint32_t)result->digest[1] << 16) | 222 ((uint32_t)result->digest[2] << 8) | 223 ((uint32_t)result->digest[3]); 224 snprintf(hex, hex_len, "0x%08x", crc); 225 } else { 226 for (size_t i = 0; i < result->digest_len; i++) { 227 snprintf(hex + i * 2, 3, "%02x", result->digest[i]); 228 } 229 } 230 231 return hex; 232 } 233 234 #define HASH_HEX(result) easyhash_to_hex(&(result)) 235 236 // Convert hash to base64 string (caller must free) 237 static inline char* easyhash_to_b64(const HashResult *result) { 238 if (!result || !result->digest) { 239 return NULL; 240 } 241 return base64_encode(result->digest, result->digest_len); 242 } 243 244 #define HASH_B64(result) easyhash_to_b64(&(result)) 245 246 // One-shot: hash string and return base64 (caller must free) 247 #define HASH_B64_STR(str) ({ \ 248 HashResult _tmp = HASH_STR(str); \ 249 char *_b64 = HASH_B64(_tmp); \ 250 HASH_FREE(_tmp); \ 251 _b64; \ 252 }) 253 254 // One-shot: hash data and return base64 (caller must free) 255 #define HASH_B64_DATA(data, len) ({ \ 256 HashResult _tmp = HASH(data, len); \ 257 char *_b64 = HASH_B64(_tmp); \ 258 HASH_FREE(_tmp); \ 259 _b64; \ 260 }) 261 262 // Algorithm-specific base64 macros 263 #define SHA256_B64_STR(str) ({ \ 264 HashResult _tmp = SHA256_STR(str); \ 265 char *_b64 = HASH_B64(_tmp); \ 266 HASH_FREE(_tmp); \ 267 _b64; \ 268 }) 269 270 #define SHA512_B64_STR(str) ({ \ 271 HashResult _tmp = SHA512_STR(str); \ 272 char *_b64 = HASH_B64(_tmp); \ 273 HASH_FREE(_tmp); \ 274 _b64; \ 275 }) 276 277 #define MD5_B64_STR(str) ({ \ 278 HashResult _tmp = MD5_STR(str); \ 279 char *_b64 = HASH_B64(_tmp); \ 280 HASH_FREE(_tmp); \ 281 _b64; \ 282 }) 283 284 #define CRC32_B64_STR(str) ({ \ 285 HashResult _tmp = CRC32_STR(str); \ 286 char *_b64 = HASH_B64(_tmp); \ 287 HASH_FREE(_tmp); \ 288 _b64; \ 289 }) 290 291 #define SHA256_B64_DATA(data, len) ({ \ 292 HashResult _tmp = SHA256(data, len); \ 293 char *_b64 = HASH_B64(_tmp); \ 294 HASH_FREE(_tmp); \ 295 _b64; \ 296 }) 297 298 #define SHA512_B64_DATA(data, len) ({ \ 299 HashResult _tmp = SHA512(data, len); \ 300 char *_b64 = HASH_B64(_tmp); \ 301 HASH_FREE(_tmp); \ 302 _b64; \ 303 }) 304 305 #define MD5_B64_DATA(data, len) ({ \ 306 HashResult _tmp = MD5(data, len); \ 307 char *_b64 = HASH_B64(_tmp); \ 308 HASH_FREE(_tmp); \ 309 _b64; \ 310 }) 311 312 #define CRC32_B64_DATA(data, len) ({ \ 313 HashResult _tmp = CRC32(data, len); \ 314 char *_b64 = HASH_B64(_tmp); \ 315 HASH_FREE(_tmp); \ 316 _b64; \ 317 }) 318 319 // Compare two hash results 320 static inline int easyhash_equals(const HashResult *a, const HashResult *b) { 321 if (!a || !b || !a->digest || !b->digest) return 0; 322 if (a->digest_len != b->digest_len) return 0; 323 return memcmp(a->digest, b->digest, a->digest_len) == 0; 324 } 325 326 #define HASH_EQUALS(a, b) easyhash_equals(&(a), &(b)) 327 328 // Quick hash-and-print (for debugging) 329 #define HASH_QUICK(label, data, len) do { \ 330 HashResult _tmp = HASH(data, len); \ 331 HASH_PRINT_LABEL(label, _tmp); \ 332 HASH_FREE(_tmp); \ 333 } while(0) 334 335 #define HASH_QUICK_STR(label, str) HASH_QUICK(label, str, strlen(str)) 336 337 // Algorithm-specific quick macros 338 #define SHA256_QUICK(label, data, len) do { \ 339 HashResult _tmp = SHA256(data, len); \ 340 HASH_PRINT_LABEL(label, _tmp); \ 341 HASH_FREE(_tmp); \ 342 } while(0) 343 344 #define SHA512_QUICK(label, data, len) do { \ 345 HashResult _tmp = SHA512(data, len); \ 346 HASH_PRINT_LABEL(label, _tmp); \ 347 HASH_FREE(_tmp); \ 348 } while(0) 349 350 #define MD5_QUICK(label, data, len) do { \ 351 HashResult _tmp = MD5(data, len); \ 352 HASH_PRINT_LABEL(label, _tmp); \ 353 HASH_FREE(_tmp); \ 354 } while(0) 355 356 #define CRC32_QUICK(label, data, len) do { \ 357 HashResult _tmp = CRC32(data, len); \ 358 HASH_PRINT_LABEL(label, _tmp); \ 359 HASH_FREE(_tmp); \ 360 } while(0) 361 362 #endif // EASYHASHING_H