From 422fb5ad08b43913c83e4c3ecfc71073cb5bb76e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 May 2014 11:43:42 -0700 Subject: [PATCH] core: Add SHA-1 versions of PBKDF2 and PRF functions --- Makefile.am | 3 +- src/sha1.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sha1.h | 34 ++++++++++ 3 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 src/sha1.c create mode 100644 src/sha1.h diff --git a/Makefile.am b/Makefile.am index 58982dcb..dedcde45 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,7 +29,8 @@ ell_libell_internal_la_SOURCES = $(ell_sources) bin_PROGRAMS = src/iwd client/iwctl -src_iwd_SOURCES = src/main.c +src_iwd_SOURCES = src/main.c \ + src/sha1.h src/sha1.c src_iwd_LDADD = ell/libell-internal.la client_iwctl_SOURCES = client/main.c diff --git a/src/sha1.c b/src/sha1.c new file mode 100644 index 00000000..b2e4be29 --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,185 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "sha1.h" + +#define SHA1_MAC_LEN 20 + +static void __hmac_sha1(struct l_checksum *checksum, + const void *key, size_t key_len, + const void *data, size_t data_len, void *output) +{ + unsigned char ipad[64]; + unsigned char opad[64]; + unsigned char digest[SHA1_MAC_LEN]; + int i; + + /* if key is longer than 64 bytes reset it to key=SHA1(key) */ + if (key_len > 64) { + l_checksum_update(checksum, key, key_len); + l_checksum_get_digest(checksum, digest, SHA1_MAC_LEN); + + l_checksum_reset(checksum); + + key = digest; + key_len = SHA1_MAC_LEN; + } + + /* start out by storing key in pads */ + memset(ipad, 0, sizeof(ipad)); + memset(opad, 0, sizeof(opad)); + memcpy(ipad, key, key_len); + memcpy(opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + /* perform inner SHA1 */ + l_checksum_update(checksum, ipad, sizeof(ipad)); + l_checksum_update(checksum, data, data_len); + l_checksum_get_digest(checksum, digest, SHA1_MAC_LEN); + + l_checksum_reset(checksum); + + /* perform outer SHA1 */ + l_checksum_update(checksum, opad, sizeof(opad)); + l_checksum_update(checksum, digest, SHA1_MAC_LEN); + l_checksum_get_digest(checksum, output, SHA1_MAC_LEN); + + l_checksum_reset(checksum); +} + +bool hmac_sha1(const void *key, size_t key_len, + const void *data, size_t data_len, void *output, size_t size) +{ + struct l_checksum *checksum; + + checksum = l_checksum_new(L_CHECKSUM_SHA1); + + __hmac_sha1(checksum, key, key_len, data, data_len, output); + + l_checksum_free(checksum); + + return true; +} + +static void F(struct l_checksum *checksum, + const char *password, size_t password_len, + const char *salt, size_t salt_len, + unsigned int iterations, unsigned int count, + unsigned char *digest) +{ + unsigned char tmp1[SHA1_MAC_LEN]; + unsigned char tmp2[SHA1_MAC_LEN]; + unsigned char buf[36]; + unsigned int i, j; + + memcpy(buf, salt, salt_len); + buf[salt_len + 0] = (count >> 24) & 0xff; + buf[salt_len + 1] = (count >> 16) & 0xff; + buf[salt_len + 2] = (count >> 8) & 0xff; + buf[salt_len + 3] = count & 0xff; + + __hmac_sha1(checksum, password, password_len, + buf, salt_len + 4, tmp1); + memcpy(digest, tmp1, SHA1_MAC_LEN); + + for (i = 1; i < iterations; i++) { + __hmac_sha1(checksum, password, password_len, + tmp1, SHA1_MAC_LEN, tmp2); + memcpy(tmp1, tmp2, SHA1_MAC_LEN); + + for (j = 0; j < SHA1_MAC_LEN; j++) + digest[j] ^= tmp2[j]; + } +} + +bool pbkdf2_sha1(const void *password, size_t password_len, + const void *salt, size_t salt_len, + unsigned int iterations, void *output, size_t size) +{ + struct l_checksum *checksum; + unsigned char *ptr = output; + unsigned char digest[SHA1_MAC_LEN]; + unsigned int i; + + checksum = l_checksum_new(L_CHECKSUM_SHA1); + + for (i = 1; size > 0; i++) { + size_t len; + + F(checksum, password, password_len, salt, salt_len, + iterations, i, digest); + + len = size > SHA1_MAC_LEN ? SHA1_MAC_LEN : size; + memcpy(ptr, digest, len); + + ptr += len; + size -= len; + } + + l_checksum_free(checksum); + + return true; +} + +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) +{ + struct l_checksum *checksum; + unsigned char input[1024]; + size_t input_len; + unsigned int i, offset = 0; + + checksum = l_checksum_new(L_CHECKSUM_SHA1); + + memcpy(input, prefix, prefix_len); + input[prefix_len] = 0; + + memcpy(input + prefix_len + 1, data, data_len); + input[prefix_len + 1 + data_len] = 0; + + input_len = prefix_len + 1 + data_len + 1; + + for (i = 0; i < (size + 19) / 20; i++) { + __hmac_sha1(checksum, key, key_len, input, input_len, + output + offset); + + offset += 20; + input[input_len - 1]++; + } + + l_checksum_free(checksum); + + return true; +} diff --git a/src/sha1.h b/src/sha1.h new file mode 100644 index 00000000..eb386f69 --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,34 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +bool hmac_sha1(const void *key, size_t key_len, + const void *data, size_t data_len, void *output, size_t size); + +bool pbkdf2_sha1(const void *password, size_t password_len, + const void *salt, size_t salt_len, + unsigned int iterations, 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);