Implement the KDF

This commit is contained in:
Juhani Krekelä 2021-04-08 22:45:08 +03:00
parent c9defbaafe
commit 900c7b4c93
2 changed files with 49 additions and 6 deletions

View File

@ -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 $@ $<

53
puer.c
View File

@ -1,5 +1,6 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
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;
}