luajitos

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

HKDF.c (4910B)


      1 /*
      2  * HKDF Implementation
      3  * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function
      4  */
      5 
      6 #include "HKDF.h"
      7 #include <string.h>
      8 
      9 /* Use existing SHA-256 implementation */
     10 typedef struct {
     11     uint32_t state[8];
     12     uint64_t count;
     13     uint8_t buffer[64];
     14 } sha256_context;
     15 
     16 extern void sha256_init(sha256_context *ctx);
     17 extern void sha256_update(sha256_context *ctx, const uint8_t *data, size_t len);
     18 extern void sha256_final(sha256_context *ctx, uint8_t digest[32]);
     19 extern void sha256(const uint8_t *data, size_t len, uint8_t digest[32]);
     20 
     21 #define SHA256_BLOCK_SIZE 64
     22 #define SHA256_DIGEST_SIZE 32
     23 
     24 /* HMAC-SHA256 context for incremental updates */
     25 typedef struct {
     26     sha256_context inner;
     27     uint8_t o_key_pad[SHA256_BLOCK_SIZE];
     28 } hmac_sha256_context;
     29 
     30 static void hmac_sha256_init(hmac_sha256_context *ctx, const uint8_t *key, size_t key_len) {
     31     uint8_t k_pad[SHA256_BLOCK_SIZE];
     32     uint8_t tk[SHA256_DIGEST_SIZE];
     33 
     34     /* If key is longer than block size, hash it first */
     35     if (key_len > SHA256_BLOCK_SIZE) {
     36         sha256(key, key_len, tk);
     37         key = tk;
     38         key_len = SHA256_DIGEST_SIZE;
     39     }
     40 
     41     /* Prepare padded key */
     42     memset(k_pad, 0, sizeof(k_pad));
     43     memcpy(k_pad, key, key_len);
     44 
     45     /* Store outer key pad for finalization */
     46     for (int i = 0; i < SHA256_BLOCK_SIZE; i++) {
     47         ctx->o_key_pad[i] = k_pad[i] ^ 0x5c;
     48         k_pad[i] ^= 0x36;
     49     }
     50 
     51     /* Initialize inner hash with i_key_pad */
     52     sha256_init(&ctx->inner);
     53     sha256_update(&ctx->inner, k_pad, SHA256_BLOCK_SIZE);
     54 
     55     memset(k_pad, 0, sizeof(k_pad));
     56 }
     57 
     58 static void hmac_sha256_update(hmac_sha256_context *ctx, const uint8_t *data, size_t len) {
     59     sha256_update(&ctx->inner, data, len);
     60 }
     61 
     62 static void hmac_sha256_final(hmac_sha256_context *ctx, uint8_t output[32]) {
     63     uint8_t inner_hash[SHA256_DIGEST_SIZE];
     64 
     65     /* Finalize inner hash */
     66     sha256_final(&ctx->inner, inner_hash);
     67 
     68     /* Compute outer hash: H(o_key_pad || inner_hash) */
     69     sha256_context outer;
     70     sha256_init(&outer);
     71     sha256_update(&outer, ctx->o_key_pad, SHA256_BLOCK_SIZE);
     72     sha256_update(&outer, inner_hash, SHA256_DIGEST_SIZE);
     73     sha256_final(&outer, output);
     74 
     75     memset(inner_hash, 0, sizeof(inner_hash));
     76 }
     77 
     78 /* Single-shot HMAC-SHA256 */
     79 static void hmac_sha256(const uint8_t *key, size_t key_len,
     80                         const uint8_t *data, size_t data_len,
     81                         uint8_t output[32]) {
     82     hmac_sha256_context ctx;
     83     hmac_sha256_init(&ctx, key, key_len);
     84     hmac_sha256_update(&ctx, data, data_len);
     85     hmac_sha256_final(&ctx, output);
     86 }
     87 
     88 /* HKDF-Extract using HMAC-SHA256 */
     89 void hkdf_sha256_extract(const uint8_t *salt, size_t salt_len,
     90                          const uint8_t *ikm, size_t ikm_len,
     91                          uint8_t prk[32]) {
     92     /* If no salt provided, use zero salt */
     93     uint8_t zero_salt[32] = {0};
     94     if (!salt || salt_len == 0) {
     95         salt = zero_salt;
     96         salt_len = 32;
     97     }
     98 
     99     /* PRK = HMAC-SHA256(salt, IKM) */
    100     hmac_sha256(salt, salt_len, ikm, ikm_len, prk);
    101 }
    102 
    103 /* HKDF-Expand using HMAC-SHA256 */
    104 int hkdf_sha256_expand(const uint8_t prk[32],
    105                        const uint8_t *info, size_t info_len,
    106                        uint8_t *okm, size_t okm_len) {
    107     /* Max output length: 255 * hash_len = 255 * 32 = 8160 bytes */
    108     if (okm_len > 255 * 32) {
    109         return -1;
    110     }
    111 
    112     if (!info) {
    113         info_len = 0;
    114     }
    115 
    116     uint8_t T[32] = {0};  /* Previous block */
    117     size_t T_len = 0;
    118     uint8_t counter = 1;
    119     size_t offset = 0;
    120 
    121     while (offset < okm_len) {
    122         /* Compute T(i) = HMAC(PRK, T(i-1) | info | i) */
    123         hmac_sha256_context ctx;
    124         hmac_sha256_init(&ctx, prk, 32);
    125 
    126         /* Add T(i-1) if not first iteration */
    127         if (T_len > 0) {
    128             hmac_sha256_update(&ctx, T, T_len);
    129         }
    130 
    131         /* Add info */
    132         if (info_len > 0) {
    133             hmac_sha256_update(&ctx, info, info_len);
    134         }
    135 
    136         /* Add counter */
    137         hmac_sha256_update(&ctx, &counter, 1);
    138 
    139         /* Finalize */
    140         hmac_sha256_final(&ctx, T);
    141         T_len = 32;
    142 
    143         /* Copy to output */
    144         size_t to_copy = okm_len - offset;
    145         if (to_copy > 32) {
    146             to_copy = 32;
    147         }
    148         memcpy(okm + offset, T, to_copy);
    149         offset += to_copy;
    150 
    151         counter++;
    152     }
    153 
    154     /* Clean up */
    155     memset(T, 0, sizeof(T));
    156 
    157     return 0;
    158 }
    159 
    160 /* HKDF (Extract-then-Expand) */
    161 int hkdf_sha256(const uint8_t *salt, size_t salt_len,
    162                 const uint8_t *ikm, size_t ikm_len,
    163                 const uint8_t *info, size_t info_len,
    164                 uint8_t *okm, size_t okm_len) {
    165     uint8_t prk[32];
    166 
    167     /* Extract */
    168     hkdf_sha256_extract(salt, salt_len, ikm, ikm_len, prk);
    169 
    170     /* Expand */
    171     int result = hkdf_sha256_expand(prk, info, info_len, okm, okm_len);
    172 
    173     /* Clean up */
    174     memset(prk, 0, sizeof(prk));
    175 
    176     return result;
    177 }