luajitos

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

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