From 39444ab53201ac1a5e2abd5ec116311705920a2f Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 10 Feb 2016 16:30:22 -0600 Subject: [PATCH] crypto: Add SHA256 based KDF --- src/crypto.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/crypto.h | 3 +++ 2 files changed, 48 insertions(+) diff --git a/src/crypto.c b/src/crypto.c index 164a7783..d11d2dfe 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -339,6 +339,51 @@ bool prf_sha1(const void *key, size_t key_len, return true; } +/* Defined in 802.11-2012, Section 11.6.1.7.2 Key derivation function (KDF) */ +bool kdf_sha256(const void *key, size_t key_len, + const void *prefix, size_t prefix_len, + const void *data, size_t data_len, void *output, size_t size) +{ + struct l_checksum *hmac; + unsigned int i, offset = 0; + unsigned int counter; + uint8_t counter_le[2]; + uint8_t length_le[2]; + struct iovec iov[4] = { + [0] = { .iov_base = counter_le, .iov_len = 2 }, + [1] = { .iov_base = (void *) prefix, .iov_len = prefix_len }, + [2] = { .iov_base = (void *) data, .iov_len = data_len }, + [3] = { .iov_base = length_le, .iov_len = 2 }, + }; + + hmac = l_checksum_new_hmac(L_CHECKSUM_SHA256, key, key_len); + if (!hmac) + return false; + + /* Length is denominated in bits, not bytes */ + l_put_le16(size * 8, length_le); + + /* KDF processes in 256-bit chunks (32 bytes) */ + for (i = 0, counter = 1; i < (size + 31) / 32; i++, counter++) { + size_t len; + + if (size - offset > 32) + len = 32; + else + len = size - offset; + + l_put_le16(counter, counter_le); + + l_checksum_updatev(hmac, iov, 4); + l_checksum_get_digest(hmac, output + offset, len); + + offset += len; + } + + l_checksum_free(hmac); + + return true; +} /* * 802.11, Section 11.6.6.7: * PTK = PRF-X(PMK, "Pairwise key expansion", Min(AA, SA) || Max(AA, SA) || diff --git a/src/crypto.h b/src/crypto.h index 7c79f950..6cd00b5b 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -62,6 +62,9 @@ int crypto_psk_from_passphrase(const char *passphrase, const unsigned char *ssid, size_t ssid_len, unsigned char *out_psk); +bool kdf_sha256(const void *key, size_t key_len, + const void *prefix, size_t prefix_len, + const void *data, size_t data_len, void *output, size_t size); bool prf_sha1(const void *key, size_t key_len, const void *prefix, size_t prefix_len, const void *data, size_t data_len, void *output, size_t size);