luajitos

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

PBKDF2.c (14515B)


      1 /*
      2  * PBKDF2-HMAC-SHA256 Implementation
      3  * RFC 2898 compliant
      4  */
      5 
      6 #include "PBKDF2.h"
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <time.h>
     10 
     11 /* SHA-256 constants and functions */
     12 #define SHA256_BLOCK_SIZE 64
     13 #define SHA256_DIGEST_SIZE 32
     14 
     15 /* SHA-256 K constants */
     16 static const uint32_t K[64] = {
     17     0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
     18     0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
     19     0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
     20     0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
     21     0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
     22     0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
     23     0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
     24     0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
     25     0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
     26     0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
     27     0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
     28     0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
     29     0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
     30     0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
     31     0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
     32     0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
     33 };
     34 
     35 /* SHA-256 context */
     36 typedef struct {
     37     uint32_t state[8];
     38     uint64_t count;
     39     uint8_t buffer[64];
     40 } sha256_ctx;
     41 
     42 /* Rotate right */
     43 #define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
     44 
     45 /* SHA-256 functions */
     46 #define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
     47 #define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
     48 #define EP0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
     49 #define EP1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
     50 #define SIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3))
     51 #define SIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10))
     52 
     53 /* Read 32-bit big-endian */
     54 static inline uint32_t read_be32(const uint8_t *p) {
     55     return ((uint32_t)p[0] << 24) |
     56            ((uint32_t)p[1] << 16) |
     57            ((uint32_t)p[2] << 8) |
     58            ((uint32_t)p[3]);
     59 }
     60 
     61 /* Write 32-bit big-endian */
     62 static inline void write_be32(uint8_t *p, uint32_t v) {
     63     p[0] = (v >> 24) & 0xff;
     64     p[1] = (v >> 16) & 0xff;
     65     p[2] = (v >> 8) & 0xff;
     66     p[3] = v & 0xff;
     67 }
     68 
     69 /* Write 64-bit big-endian */
     70 static inline void write_be64(uint8_t *p, uint64_t v) {
     71     p[0] = (v >> 56) & 0xff;
     72     p[1] = (v >> 48) & 0xff;
     73     p[2] = (v >> 40) & 0xff;
     74     p[3] = (v >> 32) & 0xff;
     75     p[4] = (v >> 24) & 0xff;
     76     p[5] = (v >> 16) & 0xff;
     77     p[6] = (v >> 8) & 0xff;
     78     p[7] = v & 0xff;
     79 }
     80 
     81 /* SHA-256 transform */
     82 static void sha256_transform(sha256_ctx *ctx, const uint8_t *data) {
     83     uint32_t W[64];
     84     uint32_t a, b, c, d, e, f, g, h, t1, t2;
     85     int i;
     86 
     87     /* Prepare message schedule */
     88     for (i = 0; i < 16; i++) {
     89         W[i] = read_be32(data + i * 4);
     90     }
     91     for (i = 16; i < 64; i++) {
     92         W[i] = SIG1(W[i - 2]) + W[i - 7] + SIG0(W[i - 15]) + W[i - 16];
     93     }
     94 
     95     /* Initialize working variables */
     96     a = ctx->state[0];
     97     b = ctx->state[1];
     98     c = ctx->state[2];
     99     d = ctx->state[3];
    100     e = ctx->state[4];
    101     f = ctx->state[5];
    102     g = ctx->state[6];
    103     h = ctx->state[7];
    104 
    105     /* Main loop */
    106     for (i = 0; i < 64; i++) {
    107         t1 = h + EP1(e) + CH(e, f, g) + K[i] + W[i];
    108         t2 = EP0(a) + MAJ(a, b, c);
    109         h = g;
    110         g = f;
    111         f = e;
    112         e = d + t1;
    113         d = c;
    114         c = b;
    115         b = a;
    116         a = t1 + t2;
    117     }
    118 
    119     /* Update state */
    120     ctx->state[0] += a;
    121     ctx->state[1] += b;
    122     ctx->state[2] += c;
    123     ctx->state[3] += d;
    124     ctx->state[4] += e;
    125     ctx->state[5] += f;
    126     ctx->state[6] += g;
    127     ctx->state[7] += h;
    128 }
    129 
    130 /* SHA-256 init */
    131 static void sha256_init(sha256_ctx *ctx) {
    132     ctx->state[0] = 0x6a09e667;
    133     ctx->state[1] = 0xbb67ae85;
    134     ctx->state[2] = 0x3c6ef372;
    135     ctx->state[3] = 0xa54ff53a;
    136     ctx->state[4] = 0x510e527f;
    137     ctx->state[5] = 0x9b05688c;
    138     ctx->state[6] = 0x1f83d9ab;
    139     ctx->state[7] = 0x5be0cd19;
    140     ctx->count = 0;
    141 }
    142 
    143 /* SHA-256 update */
    144 static void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len) {
    145     size_t i;
    146     size_t index = ctx->count % 64;
    147 
    148     ctx->count += len;
    149 
    150     if (index + len >= 64) {
    151         i = 64 - index;
    152         memcpy(ctx->buffer + index, data, i);
    153         sha256_transform(ctx, ctx->buffer);
    154 
    155         while (i + 64 <= len) {
    156             sha256_transform(ctx, data + i);
    157             i += 64;
    158         }
    159 
    160         index = 0;
    161     } else {
    162         i = 0;
    163     }
    164 
    165     if (len - i > 0) {
    166         memcpy(ctx->buffer + index, data + i, len - i);
    167     }
    168 }
    169 
    170 /* SHA-256 final */
    171 static void sha256_final(sha256_ctx *ctx, uint8_t *digest) {
    172     uint8_t bits[8];
    173     size_t index = ctx->count % 64;
    174     size_t padlen = (index < 56) ? (56 - index) : (120 - index);
    175 
    176     write_be64(bits, ctx->count * 8);
    177 
    178     uint8_t padding[64];
    179     padding[0] = 0x80;
    180     memset(padding + 1, 0, sizeof(padding) - 1);
    181 
    182     sha256_update(ctx, padding, padlen);
    183     sha256_update(ctx, bits, 8);
    184 
    185     for (int i = 0; i < 8; i++) {
    186         write_be32(digest + i * 4, ctx->state[i]);
    187     }
    188 }
    189 
    190 /* HMAC-SHA256 */
    191 static void hmac_sha256(const uint8_t *key, size_t key_len,
    192                        const uint8_t *data, size_t data_len,
    193                        uint8_t *output) {
    194     uint8_t k_pad[SHA256_BLOCK_SIZE];
    195     uint8_t tk[SHA256_DIGEST_SIZE];
    196     sha256_ctx ctx;
    197     int i;
    198 
    199     /* If key is longer than block size, hash it first */
    200     if (key_len > SHA256_BLOCK_SIZE) {
    201         sha256_init(&ctx);
    202         sha256_update(&ctx, key, key_len);
    203         sha256_final(&ctx, tk);
    204         key = tk;
    205         key_len = SHA256_DIGEST_SIZE;
    206     }
    207 
    208     /* Prepare padded key */
    209     memset(k_pad, 0, sizeof(k_pad));
    210     memcpy(k_pad, key, key_len);
    211 
    212     /* Inner hash: H((K XOR ipad) || message) */
    213     for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
    214         k_pad[i] ^= 0x36;
    215     }
    216 
    217     sha256_init(&ctx);
    218     sha256_update(&ctx, k_pad, SHA256_BLOCK_SIZE);
    219     sha256_update(&ctx, data, data_len);
    220     sha256_final(&ctx, output);
    221 
    222     /* Outer hash: H((K XOR opad) || inner_hash) */
    223     memset(k_pad, 0, sizeof(k_pad));
    224     memcpy(k_pad, key, key_len);
    225 
    226     for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
    227         k_pad[i] ^= 0x5c;
    228     }
    229 
    230     sha256_init(&ctx);
    231     sha256_update(&ctx, k_pad, SHA256_BLOCK_SIZE);
    232     sha256_update(&ctx, output, SHA256_DIGEST_SIZE);
    233     sha256_final(&ctx, output);
    234 
    235     /* Zero sensitive data */
    236     memset(k_pad, 0, sizeof(k_pad));
    237     memset(tk, 0, sizeof(tk));
    238 }
    239 
    240 /* PBKDF2-HMAC-SHA256 */
    241 int pbkdf2_hmac_sha256(const uint8_t *password, size_t password_len,
    242                        const uint8_t *salt, size_t salt_len,
    243                        uint32_t iterations,
    244                        uint8_t *output, size_t output_len) {
    245     if (!password || !salt || !output || iterations == 0) {
    246         return -1;
    247     }
    248 
    249     uint8_t U[SHA256_DIGEST_SIZE];
    250     uint8_t T[SHA256_DIGEST_SIZE];
    251     uint8_t salt_block[256];  /* salt || block_index */
    252     uint32_t block_index = 1;
    253     size_t blocks_needed = (output_len + SHA256_DIGEST_SIZE - 1) / SHA256_DIGEST_SIZE;
    254 
    255     if (salt_len + 4 > sizeof(salt_block)) {
    256         return -1;
    257     }
    258 
    259     for (size_t block = 0; block < blocks_needed; block++) {
    260         /* Prepare salt || block_index */
    261         memcpy(salt_block, salt, salt_len);
    262         write_be32(salt_block + salt_len, block_index++);
    263 
    264         /* First iteration: U1 = PRF(password, salt || block_index) */
    265         hmac_sha256(password, password_len, salt_block, salt_len + 4, U);
    266         memcpy(T, U, SHA256_DIGEST_SIZE);
    267 
    268         /* Remaining iterations: Ui = PRF(password, Ui-1) */
    269         for (uint32_t i = 1; i < iterations; i++) {
    270             hmac_sha256(password, password_len, U, SHA256_DIGEST_SIZE, U);
    271 
    272             /* XOR into T */
    273             for (int j = 0; j < SHA256_DIGEST_SIZE; j++) {
    274                 T[j] ^= U[j];
    275             }
    276         }
    277 
    278         /* Copy T to output */
    279         size_t to_copy = SHA256_DIGEST_SIZE;
    280         if (block * SHA256_DIGEST_SIZE + to_copy > output_len) {
    281             to_copy = output_len - block * SHA256_DIGEST_SIZE;
    282         }
    283         memcpy(output + block * SHA256_DIGEST_SIZE, T, to_copy);
    284     }
    285 
    286     /* Zero sensitive data */
    287     memset(U, 0, sizeof(U));
    288     memset(T, 0, sizeof(T));
    289     memset(salt_block, 0, sizeof(salt_block));
    290 
    291     return 0;
    292 }
    293 
    294 /* Test program */
    295 #ifdef INCLUDE_MAIN
    296 int main(void) {
    297     printf("╔════════════════════════════════════════════════════╗\n");
    298     printf("║   PBKDF2-HMAC-SHA256 Key Derivation               ║\n");
    299     printf("║   RFC 2898 Compliant                               ║\n");
    300     printf("╚════════════════════════════════════════════════════╝\n\n");
    301 
    302     printf("Features:\n");
    303     printf("• Password-based key derivation\n");
    304     printf("• HMAC-SHA256 based\n");
    305     printf("• Configurable iterations\n");
    306     printf("• Salt support\n");
    307     printf("• Suitable for password storage and key derivation\n\n");
    308 
    309     printf("════════════════════════════════════════════════════\n");
    310     printf("Test 1: Basic Key Derivation\n");
    311     printf("════════════════════════════════════════════════════\n");
    312 
    313     const char *password = "correct horse battery staple";
    314     uint8_t salt[16] = "random salt 123";
    315     uint8_t key[32];
    316 
    317     printf("Password: \"%s\"\n", password);
    318     printf("Salt: \"random salt 123\"\n");
    319     printf("Iterations: %d\n\n", PBKDF2_ITERATIONS_MIN);
    320 
    321     if (pbkdf2_hmac_sha256((const uint8_t*)password, strlen(password),
    322                           salt, 16, PBKDF2_ITERATIONS_MIN,
    323                           key, 32) != 0) {
    324         fprintf(stderr, "✗ Key derivation failed\n");
    325         return 1;
    326     }
    327 
    328     printf("✓ Derived key (32 bytes):\n  ");
    329     for (int i = 0; i < 32; i++) {
    330         printf("%02x", key[i]);
    331     }
    332     printf("\n\n");
    333 
    334     printf("════════════════════════════════════════════════════\n");
    335     printf("Test 2: Different Iteration Counts\n");
    336     printf("════════════════════════════════════════════════════\n");
    337 
    338     uint32_t iteration_counts[] = {10000, 100000, 600000};
    339     const char *labels[] = {"Low (10k)", "Min (100k)", "Recommended (600k)"};
    340 
    341     for (int i = 0; i < 3; i++) {
    342         printf("\n%s iterations:\n", labels[i]);
    343 
    344         struct timespec start, end;
    345         clock_gettime(CLOCK_MONOTONIC, &start);
    346 
    347         pbkdf2_hmac_sha256((const uint8_t*)password, strlen(password),
    348                           salt, 16, iteration_counts[i], key, 32);
    349 
    350         clock_gettime(CLOCK_MONOTONIC, &end);
    351         double elapsed = (end.tv_sec - start.tv_sec) +
    352                         (end.tv_nsec - start.tv_nsec) / 1e9;
    353 
    354         printf("  Key: ");
    355         for (int j = 0; j < 16; j++) {
    356             printf("%02x", key[j]);
    357         }
    358         printf("...\n");
    359         printf("  Time: %.3f seconds\n", elapsed);
    360     }
    361 
    362     printf("\n════════════════════════════════════════════════════\n");
    363     printf("Test 3: Salt Matters\n");
    364     printf("════════════════════════════════════════════════════\n");
    365 
    366     uint8_t salt1[16] = "salt version 1 ";
    367     uint8_t salt2[16] = "salt version 2 ";
    368     uint8_t key1[32], key2[32];
    369 
    370     pbkdf2_hmac_sha256((const uint8_t*)password, strlen(password),
    371                       salt1, 16, PBKDF2_ITERATIONS_MIN, key1, 32);
    372 
    373     pbkdf2_hmac_sha256((const uint8_t*)password, strlen(password),
    374                       salt2, 16, PBKDF2_ITERATIONS_MIN, key2, 32);
    375 
    376     printf("Same password, salt1: ");
    377     for (int i = 0; i < 16; i++) printf("%02x", key1[i]);
    378     printf("...\n");
    379 
    380     printf("Same password, salt2: ");
    381     for (int i = 0; i < 16; i++) printf("%02x", key2[i]);
    382     printf("...\n");
    383 
    384     if (memcmp(key1, key2, 32) == 0) {
    385         printf("✗ Keys are the same (BAD!)\n");
    386     } else {
    387         printf("✓ Keys are different (GOOD!)\n");
    388     }
    389 
    390     printf("\n════════════════════════════════════════════════════\n");
    391     printf("Test 4: RFC 2898 Test Vector\n");
    392     printf("════════════════════════════════════════════════════\n");
    393 
    394     /* RFC 6070 test vector */
    395     const char *test_pass = "password";
    396     const char *test_salt = "salt";
    397     uint8_t test_key[32];
    398     uint8_t expected[32] = {
    399         0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c,
    400         0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37,
    401         0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48,
    402         0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b
    403     };
    404 
    405     pbkdf2_hmac_sha256((const uint8_t*)test_pass, 8,
    406                       (const uint8_t*)test_salt, 4,
    407                       1, test_key, 32);
    408 
    409     printf("Input: password=\"password\", salt=\"salt\", iterations=1\n");
    410     printf("Output: ");
    411     for (int i = 0; i < 32; i++) printf("%02x", test_key[i]);
    412     printf("\n");
    413 
    414     if (memcmp(test_key, expected, 32) == 0) {
    415         printf("✓ Test vector matches!\n");
    416     } else {
    417         printf("✗ Test vector mismatch\n");
    418     }
    419 
    420     printf("\n════════════════════════════════════════════════════\n");
    421     printf("Security Recommendations:\n");
    422     printf("════════════════════════════════════════════════════\n");
    423     printf("• Minimum 100,000 iterations (as of 2024)\n");
    424     printf("• Recommended 600,000 iterations for sensitive data\n");
    425     printf("• Use unique random salt for each password\n");
    426     printf("• Store salt with hash (salt is not secret)\n");
    427     printf("• For new applications, consider Argon2\n");
    428     printf("• PBKDF2 is CPU-only (not memory-hard)\n");
    429 
    430     return 0;
    431 }
    432 #endif