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