From 900c7b4c93f32cfc8e59b3b7df523ee6af420152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Thu, 8 Apr 2021 22:45:08 +0300 Subject: [PATCH] Implement the KDF --- Makefile | 2 +- puer.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 636aea4..307a6f6 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CFLAGS ?= -std=gnu11 -Os -g -Wall -Wextra -Werror -pedantic .SUFFIXES: .SUFFIXES: .c .o -all: puer.o +all: puer puer: puer.o $(CC) $(LDFLAGS) -o $@ $< diff --git a/puer.c b/puer.c index eb748d3..278fd15 100644 --- a/puer.c +++ b/puer.c @@ -1,5 +1,6 @@ #include #include +#include #include void xxtea128(uint32_t const key[4], uint32_t block[4]) { @@ -249,11 +250,53 @@ void hmac(unsigned char output[32], unsigned char key[], size_t keylen, unsigned finalize_hash(&state, output); } +// KDF_ROUNDS must be at least 2 +#define KDF_ROUNDS 100000 +unsigned char kdf_buf[KDF_ROUNDS * 32]; +void kdf(unsigned char key[16], unsigned char salt[32], unsigned char passphrase[], size_t passphraselen) { + // This is based on the design of PBKDF2 but aims to be memory hard + // This is achieved by storing all the hashes in a buffer and the + // in the end hashing them together in reverse order, instead of + // just xoring together. + // + // The memory-hardness of this scheme rests of the assumption that + // it is not feasible to compute the final hash backwards, that is, + // starting with the first hash and working towards the final hash. + // While I cannot prove this to be the case, the fact that our hash + // is made out of a one-way compression function makes me + // relatively confident in it. + + // Place the hash of the salt at the top of the buffer. We do not + // include the counter i from PBKDF2 since we will ever only + // produce one block of output + size_t index = KDF_ROUNDS*32 - 32; + hmac(&kdf_buf[index], passphrase, passphraselen, salt, 32); + index -= 32; + + // Walk back along the buffer, at each step hashing the previous + // hashes + while (index > 0) { + hmac(&kdf_buf[index], passphrase, passphraselen, &kdf_buf[index+32], 32); + index -= 32; + } + hmac(kdf_buf, passphrase, passphraselen, &kdf_buf[32], 32); + + // Perform the final hash + unsigned char final_hash[32]; + hmac(final_hash, passphrase, passphraselen, kdf_buf, KDF_ROUNDS * 32); + + // Use first 128 bits of final hash as the key + memcpy(key, final_hash, 16); +} + int main(void) { - unsigned char hashed[32]; - unsigned char key[] = "12345678901234567899"; - unsigned char message[] = "barbaz"; - hmac(hashed, key, sizeof(key)-1, message, sizeof(message)-1); - for (size_t i = 0; i < 32; i++) {printf("%02hhx ", hashed[i]);}printf("\n"); //debg + unsigned char key[16] = {0}; + unsigned char salt[32] = "seasaltrocksalt seasaltrocksalt"; + unsigned char passphrase[] = "a quick brown fox jumps over the lazy dog"; + kdf(key, salt, passphrase, sizeof(passphrase) - 1); + for (size_t i = 0; i < 16; i++) { + printf("%02hhx ", key[i]); + } + printf("\n"); return 0; }