commit 93c90646bc4e27a65f44424ed2de5fa915d9f69d
Author: finwo <finwo@pm.me>
Date: Thu, 19 Mar 2026 10:58:39 +0100
Project init
Diffstat:
9 files changed, 746 insertions(+), 0 deletions(-)
diff --git a/.dep.export b/.dep.export
@@ -0,0 +1 @@
+include/finwo/pbkdf2.h src/pbkdf2.h
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+/lib/
+/test
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
@@ -0,0 +1,6 @@
+<!-- 46b43825-f791-485e-9445-415ee7bbbf2d -->
+# Contributor Code of Conduct
+
+This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters.
+
+For more information please visit the [No Code of Conduct](https://github.com/domgetter/NCoC) homepage.
diff --git a/LICENSE.md b/LICENSE.md
@@ -0,0 +1,34 @@
+Copyright (c) 2026 finwo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to use, copy,
+modify, and distribute the Software, subject to the following conditions:
+
+ 1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions, and the following disclaimer.
+
+ 2. Redistributions in binary form, or any public offering of the Software
+ (including hosted or managed services), must reproduce the above copyright
+ notice, this list of conditions, and the following disclaimer in the
+ documentation and/or other materials provided.
+
+ 3. Any redistribution or public offering of the Software must clearly attribute
+ the Software to the original copyright holder, reference this License, and
+ include a link to the official project repository or website.
+
+ 4. The Software may not be renamed, rebranded, or marketed in a manner that
+ implies it is an independent or proprietary product. Derivative works must
+ clearly state that they are based on the Software.
+
+ 5. Modifications to copies of the Software must carry prominent notices stating
+ that changes were made, the nature of the modifications, and the date of the
+ modifications.
+
+Any violation of these conditions terminates the permissions granted herein.
+
+THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,29 @@
+SRC=$(wildcard src/*.c)
+
+INCLUDES?=
+INCLUDES+=-I src
+
+CFLAGS?=-Wall -std=c99
+
+include lib/.dep/config.mk
+
+CFLAGS+=$(INCLUDES)
+CFLAGS+=-D_DEFAULT_SOURCE
+
+OBJ=$(SRC:.c=.o)
+
+BIN=\
+ test
+
+LDFLAGS+=-lssl -lcrypto
+
+default: $(BIN)
+
+$(BIN): $(OBJ) $(BIN:=.o)
+ $(CC) $(CFLAGS) $(OBJ) $@.o $(LDFLAGS) -o $@
+
+.PHONY: clean
+clean:
+ rm -f $(OBJ)
+ rm -f $(BIN:=.o)
+ rm -f test
diff --git a/config.mk b/config.mk
@@ -0,0 +1 @@
+SRC+={{module.dirname}}/src/pbkdf2.c
diff --git a/src/pbkdf2.c b/src/pbkdf2.c
@@ -0,0 +1,353 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "pbkdf2.h"
+
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define SHA1_HASH_SIZE 20
+#define SHA256_HASH_SIZE 32
+
+static void sha1_transform(struct sha1_ctx *ctx) {
+ uint32_t a, b, c, d, e, m[80], j;
+
+ for (j = 0; j < 16; j++) {
+ m[j] = (ctx->buffer[j*4] << 24) | (ctx->buffer[j*4+1] << 16) |
+ (ctx->buffer[j*4+2] << 8) | ctx->buffer[j*4+3];
+ }
+ for ( ; j < 80; j++) {
+ m[j] = (m[j-3] ^ m[j-8] ^ m[j-14] ^ m[j-16]);
+ m[j] = (m[j] << 1) | (m[j] >> 31);
+ }
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+
+ for (j = 0; j < 20; j++) {
+ uint32_t t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + 0x5a827999 + m[j];
+ e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t;
+ }
+ for ( ; j < 40; j++) {
+ uint32_t t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + 0x6ed9eba1 + m[j];
+ e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t;
+ }
+ for ( ; j < 60; j++) {
+ uint32_t t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + 0x8f1bbcdc + m[j];
+ e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t;
+ }
+ for ( ; j < 80; j++) {
+ uint32_t t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + 0xca62c1d6 + m[j];
+ e = d; d = c; c = ROTLEFT(b, 30); b = a; a = t;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+}
+
+void sha1_init(struct sha1_ctx *ctx) {
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+}
+
+void sha1_update(struct sha1_ctx *ctx, const uint8_t *data, size_t len) {
+ size_t i;
+ for (i = 0; i < len; i++) {
+ ctx->buffer[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha1_transform(ctx);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void sha1_final(struct sha1_ctx *ctx, uint8_t *hash) {
+ size_t i = ctx->datalen;
+
+ ctx->buffer[i++] = 0x80;
+ if (i > 56) {
+ while (i < 64) ctx->buffer[i++] = 0;
+ sha1_transform(ctx);
+ memset(ctx->buffer, 0, 56);
+ } else {
+ while (i < 56) ctx->buffer[i++] = 0;
+ }
+
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->buffer[63] = (uint8_t)(ctx->bitlen);
+ ctx->buffer[62] = (uint8_t)(ctx->bitlen >> 8);
+ ctx->buffer[61] = (uint8_t)(ctx->bitlen >> 16);
+ ctx->buffer[60] = (uint8_t)(ctx->bitlen >> 24);
+ ctx->buffer[59] = (uint8_t)(ctx->bitlen >> 32);
+ ctx->buffer[58] = (uint8_t)(ctx->bitlen >> 40);
+ ctx->buffer[57] = (uint8_t)(ctx->bitlen >> 48);
+ ctx->buffer[56] = (uint8_t)(ctx->bitlen >> 56);
+ sha1_transform(ctx);
+
+ for (i = 0; i < 4; i++) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
+ }
+}
+
+#define SHA256_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define SHA256_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define SHA256_EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define SHA256_EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SHA256_SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SHA256_SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+static const uint32_t sha256_k[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static void sha256_transform(struct sha256_ctx *ctx) {
+ uint32_t a, b, c, d, e, f, g, h, j, t1, t2, m[64];
+
+ for (j = 0; j < 16; j++) {
+ m[j] = (ctx->buffer[j*4] << 24) | (ctx->buffer[j*4+1] << 16) |
+ (ctx->buffer[j*4+2] << 8) | ctx->buffer[j*4+3];
+ }
+ for ( ; j < 64; j++) {
+ m[j] = SHA256_SIG1(m[j-2]) + m[j-7] + SHA256_SIG0(m[j-15]) + m[j-16];
+ }
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+ f = ctx->state[5];
+ g = ctx->state[6];
+ h = ctx->state[7];
+
+ for (j = 0; j < 64; j++) {
+ t1 = h + SHA256_EP1(e) + SHA256_CH(e, f, g) + sha256_k[j] + m[j];
+ t2 = SHA256_EP0(a) + SHA256_MAJ(a, b, c);
+ h = g; g = f; f = e; e = d + t1;
+ d = c; c = b; b = a; a = t1 + t2;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+ ctx->state[5] += f;
+ ctx->state[6] += g;
+ ctx->state[7] += h;
+}
+
+void sha256_init(struct sha256_ctx *ctx) {
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+}
+
+void sha256_update(struct sha256_ctx *ctx, const uint8_t *data, size_t len) {
+ size_t i;
+ for (i = 0; i < len; i++) {
+ ctx->buffer[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha256_transform(ctx);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void sha256_final(struct sha256_ctx *ctx, uint8_t *hash) {
+ size_t i = ctx->datalen;
+
+ ctx->buffer[i++] = 0x80;
+ if (i > 56) {
+ while (i < 64) ctx->buffer[i++] = 0;
+ sha256_transform(ctx);
+ memset(ctx->buffer, 0, 56);
+ } else {
+ while (i < 56) ctx->buffer[i++] = 0;
+ }
+
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->buffer[63] = (uint8_t)(ctx->bitlen);
+ ctx->buffer[62] = (uint8_t)(ctx->bitlen >> 8);
+ ctx->buffer[61] = (uint8_t)(ctx->bitlen >> 16);
+ ctx->buffer[60] = (uint8_t)(ctx->bitlen >> 24);
+ ctx->buffer[59] = (uint8_t)(ctx->bitlen >> 32);
+ ctx->buffer[58] = (uint8_t)(ctx->bitlen >> 40);
+ ctx->buffer[57] = (uint8_t)(ctx->bitlen >> 48);
+ ctx->buffer[56] = (uint8_t)(ctx->bitlen >> 56);
+ sha256_transform(ctx);
+
+ for (i = 0; i < 4; i++) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff;
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff;
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff;
+ }
+}
+
+void hmac_sha1(
+ const uint8_t *key, size_t key_len,
+ const uint8_t *data, size_t data_len,
+ uint8_t *output
+) {
+ uint8_t k_ipad[64], k_opad[64], tk[20];
+ struct sha1_ctx ctx;
+ size_t i;
+
+ if (key_len > 64) {
+ sha1_init(&ctx);
+ sha1_update(&ctx, key, key_len);
+ sha1_final(&ctx, tk);
+ key = tk;
+ key_len = 20;
+ }
+
+ memset(k_ipad, 0x36, 64);
+ memset(k_opad, 0x5c, 64);
+ for (i = 0; i < key_len; i++) {
+ k_ipad[i] ^= key[i];
+ k_opad[i] ^= key[i];
+ }
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, k_ipad, 64);
+ sha1_update(&ctx, data, data_len);
+ sha1_final(&ctx, output);
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, k_opad, 64);
+ sha1_update(&ctx, output, 20);
+ sha1_final(&ctx, output);
+}
+
+void hmac_sha256(
+ const uint8_t *key, size_t key_len,
+ const uint8_t *data, size_t data_len,
+ uint8_t *output
+) {
+ uint8_t k_ipad[64], k_opad[64], tk[32];
+ struct sha256_ctx ctx;
+ size_t i;
+
+ if (key_len > 64) {
+ sha256_init(&ctx);
+ sha256_update(&ctx, key, key_len);
+ sha256_final(&ctx, tk);
+ key = tk;
+ key_len = 32;
+ }
+
+ memset(k_ipad, 0x36, 64);
+ memset(k_opad, 0x5c, 64);
+ for (i = 0; i < key_len; i++) {
+ k_ipad[i] ^= key[i];
+ k_opad[i] ^= key[i];
+ }
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, k_ipad, 64);
+ sha256_update(&ctx, data, data_len);
+ sha256_final(&ctx, output);
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, k_opad, 64);
+ sha256_update(&ctx, output, 32);
+ sha256_final(&ctx, output);
+}
+
+void pbkdf2(
+ const uint8_t *password, size_t password_len,
+ const uint8_t *salt, size_t salt_len,
+ uint64_t iterations,
+ enum pbkdf2_hash hash,
+ uint8_t *output, size_t output_len
+) {
+ size_t hash_len = (hash == PBKDF2_SHA1) ? SHA1_HASH_SIZE : SHA256_HASH_SIZE;
+ size_t l = (output_len + hash_len - 1) / hash_len;
+ size_t r = output_len - (l - 1) * hash_len;
+
+ uint8_t *salt_block = (uint8_t *)malloc(salt_len + 4);
+ uint8_t *u = (uint8_t *)malloc(hash_len);
+ uint8_t *t = (uint8_t *)malloc(hash_len);
+ uint8_t *result = output;
+ size_t i, j;
+
+ for (i = 1; i <= l; i++) {
+ memcpy(salt_block, salt, salt_len);
+ salt_block[salt_len] = (uint8_t)(i >> 24);
+ salt_block[salt_len + 1] = (uint8_t)(i >> 16);
+ salt_block[salt_len + 2] = (uint8_t)(i >> 8);
+ salt_block[salt_len + 3] = (uint8_t)i;
+
+ if (hash == PBKDF2_SHA1) {
+ hmac_sha1(password, password_len, salt_block, salt_len + 4, t);
+ } else {
+ hmac_sha256(password, password_len, salt_block, salt_len + 4, t);
+ }
+ memcpy(u, t, hash_len);
+
+ for (j = 1; j < iterations; j++) {
+ if (hash == PBKDF2_SHA1) {
+ hmac_sha1(password, password_len, u, hash_len, u);
+ } else {
+ hmac_sha256(password, password_len, u, hash_len, u);
+ }
+ for (size_t k = 0; k < hash_len; k++) {
+ t[k] ^= u[k];
+ }
+ }
+
+ size_t copy_len = (i == l) ? r : hash_len;
+ memcpy(result, t, copy_len);
+ result += copy_len;
+ }
+
+ free(salt_block);
+ free(u);
+ free(t);
+}
diff --git a/src/pbkdf2.h b/src/pbkdf2.h
@@ -0,0 +1,54 @@
+#ifndef __FINWO_PBKDF2_H__
+#define __FINWO_PBKDF2_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum pbkdf2_hash {
+ PBKDF2_SHA1,
+ PBKDF2_SHA256
+};
+
+struct sha1_ctx {
+ uint32_t state[5];
+ size_t datalen;
+ uint64_t bitlen;
+ uint8_t buffer[64];
+};
+
+struct sha256_ctx {
+ uint32_t state[8];
+ size_t datalen;
+ uint64_t bitlen;
+ uint8_t buffer[64];
+};
+
+void sha1_init(struct sha1_ctx *ctx);
+void sha1_update(struct sha1_ctx *ctx, const uint8_t *data, size_t len);
+void sha1_final(struct sha1_ctx *ctx, uint8_t *hash);
+
+void sha256_init(struct sha256_ctx *ctx);
+void sha256_update(struct sha256_ctx *ctx, const uint8_t *data, size_t len);
+void sha256_final(struct sha256_ctx *ctx, uint8_t *hash);
+
+void hmac_sha1(
+ const uint8_t *key, size_t key_len,
+ const uint8_t *data, size_t data_len,
+ uint8_t *output
+);
+
+void hmac_sha256(
+ const uint8_t *key, size_t key_len,
+ const uint8_t *data, size_t data_len,
+ uint8_t *output
+);
+
+void pbkdf2(
+ const uint8_t *password, size_t password_len,
+ const uint8_t *salt, size_t salt_len,
+ uint64_t iterations,
+ enum pbkdf2_hash hash,
+ uint8_t *output, size_t output_len
+);
+
+#endif
diff --git a/test.c b/test.c
@@ -0,0 +1,265 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+
+#include "src/pbkdf2.h"
+
+int passed = 0;
+int failed = 0;
+
+static void print_hex(const uint8_t *data, size_t len) {
+ for (size_t i = 0; i < len; i++) printf("%02x", data[i]);
+}
+
+static int compare_hex(const uint8_t *data, const char *expected, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ unsigned int val;
+ if (sscanf(expected + i * 2, "%2x", &val) != 1) return 0;
+ if (data[i] != val) return 0;
+ }
+ return 1;
+}
+
+void test_sha1(void) {
+ struct sha1_ctx ctx;
+ uint8_t hash[20];
+
+ printf("SHA-1 Tests\n");
+ printf("-----------\n");
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, (uint8_t *)"abc", 3);
+ sha1_final(&ctx, hash);
+ printf(" SHA1(abc): ");
+ if (compare_hex(hash, "a9993e364706816aba3e25717850c26c9cd0d89d", 20)) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n Expected: a9993e364706816aba3e25717850c26c9cd0d89d\n Got: ");
+ print_hex(hash, 20);
+ printf("\n");
+ failed++;
+ }
+
+ sha1_init(&ctx);
+ sha1_final(&ctx, hash);
+ printf(" SHA1(empty): ");
+ if (compare_hex(hash, "da39a3ee5e6b4b0d3255bfef95601890afd80709", 20)) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n");
+ failed++;
+ }
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, (uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56);
+ sha1_final(&ctx, hash);
+ printf(" SHA1(long): ");
+ if (compare_hex(hash, "84983e441c3bd26ebaae4aa1f95129e5e54670f1", 20)) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n");
+ failed++;
+ }
+}
+
+void test_sha256(void) {
+ struct sha256_ctx ctx;
+ uint8_t hash[32];
+
+ printf("\nSHA-256 Tests\n");
+ printf("-------------\n");
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, (uint8_t *)"abc", 3);
+ sha256_final(&ctx, hash);
+ printf(" SHA256(abc): ");
+ if (compare_hex(hash, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 32)) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n");
+ failed++;
+ }
+
+ sha256_init(&ctx);
+ sha256_final(&ctx, hash);
+ printf(" SHA256(empty): ");
+ if (compare_hex(hash, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 32)) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n");
+ failed++;
+ }
+}
+
+void test_hmac_sha1(void) {
+ uint8_t hash[20];
+ uint8_t openssl_hash[20];
+ unsigned int len;
+
+ printf("\nHMAC-SHA1 Tests\n");
+ printf("---------------\n");
+
+ const uint8_t key[] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ const uint8_t data[] = "Hi There";
+
+ HMAC(EVP_sha1(), key, 20, data, 8, openssl_hash, &len);
+ hmac_sha1(key, 20, data, 8, hash);
+
+ printf(" HMAC-SHA1 (vs OpenSSL): ");
+ if (memcmp(hash, openssl_hash, 20) == 0) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n OpenSSL: ");
+ print_hex(openssl_hash, 20);
+ printf("\n Ours: ");
+ print_hex(hash, 20);
+ printf("\n");
+ failed++;
+ }
+
+ const uint8_t key2[] = "key";
+ const uint8_t data2[] = "The quick brown fox jumps over the lazy dog";
+
+ HMAC(EVP_sha1(), key2, 3, data2, 43, openssl_hash, &len);
+ hmac_sha1(key2, 3, data2, 43, hash);
+
+ printf(" HMAC-SHA1 (short key): ");
+ if (memcmp(hash, openssl_hash, 20) == 0) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n");
+ failed++;
+ }
+}
+
+void test_hmac_sha256(void) {
+ uint8_t hash[32];
+ uint8_t openssl_hash[32];
+ unsigned int len;
+
+ printf("\nHMAC-SHA256 Tests\n");
+ printf("-----------------\n");
+
+ const uint8_t key[] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ const uint8_t data[] = "Hi There";
+
+ HMAC(EVP_sha256(), key, 20, data, 8, openssl_hash, &len);
+ hmac_sha256(key, 20, data, 8, hash);
+
+ printf(" HMAC-SHA256 (vs OpenSSL): ");
+ if (memcmp(hash, openssl_hash, 32) == 0) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n OpenSSL: ");
+ print_hex(openssl_hash, 32);
+ printf("\n Ours: ");
+ print_hex(hash, 32);
+ printf("\n");
+ failed++;
+ }
+}
+
+void test_pbkdf2(void) {
+ uint8_t output[128];
+ uint8_t openssl_output[128];
+
+ printf("\nPBKDF2 Tests (vs OpenSSL)\n");
+ printf("-------------------------\n");
+
+ const char *password = "password";
+ const char *salt = "salt";
+ uint64_t iterations = 4096;
+
+ /* PBKDF2-SHA1 */
+ PKCS5_PBKDF2_HMAC(password, 8, (unsigned char *)salt, 4, iterations, EVP_sha1(), 20, openssl_output);
+ pbkdf2((uint8_t *)password, 8, (uint8_t *)salt, 4, iterations, PBKDF2_SHA1, output, 20);
+
+ printf(" PBKDF2-SHA1 (c=4096, dkLen=20): ");
+ if (memcmp(output, openssl_output, 20) == 0) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n OpenSSL: ");
+ print_hex(openssl_output, 20);
+ printf("\n Ours: ");
+ print_hex(output, 20);
+ printf("\n");
+ failed++;
+ }
+
+ /* PBKDF2-SHA256 */
+ PKCS5_PBKDF2_HMAC(password, 8, (unsigned char *)salt, 4, iterations, EVP_sha256(), 32, openssl_output);
+ pbkdf2((uint8_t *)password, 8, (uint8_t *)salt, 4, iterations, PBKDF2_SHA256, output, 32);
+
+ printf(" PBKDF2-SHA256 (c=4096, dkLen=32): ");
+ if (memcmp(output, openssl_output, 32) == 0) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n OpenSSL: ");
+ print_hex(openssl_output, 32);
+ printf("\n Ours: ");
+ print_hex(output, 32);
+ printf("\n");
+ failed++;
+ }
+
+ /* Longer output (block chaining) */
+ const char *password2 = "passwordPASSWORD";
+ const char *salt2 = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
+ size_t dk_len = 25;
+
+ PKCS5_PBKDF2_HMAC(password2, 16, (unsigned char *)salt2, 36, iterations, EVP_sha1(), dk_len, openssl_output);
+ pbkdf2((uint8_t *)password2, 16, (uint8_t *)salt2, 36, iterations, PBKDF2_SHA1, output, dk_len);
+
+ printf(" PBKDF2-SHA1 (dkLen=25, chaining): ");
+ if (memcmp(output, openssl_output, dk_len) == 0) {
+ printf("PASSED\n");
+ passed++;
+ } else {
+ printf("FAILED\n OpenSSL: ");
+ print_hex(openssl_output, dk_len);
+ printf("\n Ours: ");
+ print_hex(output, dk_len);
+ printf("\n");
+ failed++;
+ }
+}
+
+int main() {
+ printf("\n========================================\n");
+ printf(" PBKDF2 Library Test Suite\n");
+ printf("========================================\n\n");
+
+ test_sha1();
+ test_sha256();
+ test_hmac_sha1();
+ test_hmac_sha256();
+ test_pbkdf2();
+
+ printf("\n========================================\n");
+ printf("Results: %d passed, %d failed\n", passed, failed);
+ printf("========================================\n");
+
+ return failed > 0 ? 1 : 0;
+}