/* * SHA1 hash implementation and interface functions * Copyright (c) 2003-2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include "includes.h" #include "common.h" #include "sha1.h" #include "md5.h" #include "crypto.h" /** * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @num_elem: Number of elements in the data vector * @addr: Pointers to the data areas * @len: Lengths of the data blocks * @mac: Buffer for the hash (20 bytes) */ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[20]; const u8 *_addr[6]; size_t _len[6], i; if (num_elem > 5) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). */ return; } /* if key is longer than 64 bytes reset it to key = SHA1(key) */ if (key_len > 64) { sha1_vector(1, &key, &key_len, tk); key = tk; key_len = 20; } /* the HMAC_SHA1 transform looks like: * * SHA1(K XOR opad, SHA1(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in ipad */ os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with ipad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x36; /* perform inner SHA1 */ _addr[0] = k_pad; _len[0] = 64; for (i = 0; i < num_elem; i++) { _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } sha1_vector(1 + num_elem, _addr, _len, mac); os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); /* XOR key with opad values */ for (i = 0; i < 64; i++) k_pad[i] ^= 0x5c; /* perform outer SHA1 */ _addr[0] = k_pad; _len[0] = 64; _addr[1] = mac; _len[1] = SHA1_MAC_LEN; sha1_vector(2, _addr, _len, mac); } /** * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) */ void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); } /** * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * * This function is used to derive new, cryptographically separate keys from a * given key (e.g., PMK in IEEE 802.11i). */ void sha1_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u8 counter = 0; size_t pos, plen; u8 hash[SHA1_MAC_LEN]; size_t label_len = os_strlen(label) + 1; const unsigned char *addr[3]; size_t len[3]; addr[0] = (u8 *) label; len[0] = label_len; addr[1] = data; len[1] = data_len; addr[2] = &counter; len[2] = 1; pos = 0; while (pos < buf_len) { plen = buf_len - pos; if (plen >= SHA1_MAC_LEN) { hmac_sha1_vector(key, key_len, 3, addr, len, &buf[pos]); pos += SHA1_MAC_LEN; } else { hmac_sha1_vector(key, key_len, 3, addr, len, hash); os_memcpy(&buf[pos], hash, plen); break; } counter++; } } #ifndef CONFIG_NO_TLS_PRF /** * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) * @secret: Key for PRF * @secret_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @seed: Seed value to bind into the key * @seed_len: Length of the seed * @out: Buffer for the generated pseudo-random key * @outlen: Number of bytes of key to generate * Returns: 0 on success, -1 on failure. * * This function is used to derive new, cryptographically separate keys from a * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. */ int tls_prf(const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen) { size_t L_S1, L_S2, i; const u8 *S1, *S2; u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; int MD5_pos, SHA1_pos; const u8 *MD5_addr[3]; size_t MD5_len[3]; const unsigned char *SHA1_addr[3]; size_t SHA1_len[3]; if (secret_len & 1) return -1; MD5_addr[0] = A_MD5; MD5_len[0] = MD5_MAC_LEN; MD5_addr[1] = (unsigned char *) label; MD5_len[1] = os_strlen(label); MD5_addr[2] = seed; MD5_len[2] = seed_len; SHA1_addr[0] = A_SHA1; SHA1_len[0] = SHA1_MAC_LEN; SHA1_addr[1] = (unsigned char *) label; SHA1_len[1] = os_strlen(label); SHA1_addr[2] = seed; SHA1_len[2] = seed_len; /* RFC 2246, Chapter 5 * A(0) = seed, A(i) = HMAC(secret, A(i-1)) * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) */ L_S1 = L_S2 = (secret_len + 1) / 2; S1 = secret; S2 = secret + L_S1; if (secret_len & 1) { /* The last byte of S1 will be shared with S2 */ S2--; } hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5); hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); MD5_pos = MD5_MAC_LEN; SHA1_pos = SHA1_MAC_LEN; for (i = 0; i < outlen; i++) { if (MD5_pos == MD5_MAC_LEN) { hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5); MD5_pos = 0; hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5); } if (SHA1_pos == SHA1_MAC_LEN) { hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, P_SHA1); SHA1_pos = 0; hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); } out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; MD5_pos++; SHA1_pos++; } return 0; } #endif /* CONFIG_NO_TLS_PRF */ #ifndef CONFIG_NO_PBKDF2 static void pbkdf2_sha1_f(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, unsigned int count, u8 *digest) { unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; int i, j; unsigned char count_buf[4]; const u8 *addr[2]; size_t len[2]; size_t passphrase_len = os_strlen(passphrase); addr[0] = (u8 *) ssid; len[0] = ssid_len; addr[1] = count_buf; len[1] = 4; /* F(P, S, c, i) = U1 xor U2 xor ... Uc * U1 = PRF(P, S || i) * U2 = PRF(P, U1) * Uc = PRF(P, Uc-1) */ count_buf[0] = (count >> 24) & 0xff; count_buf[1] = (count >> 16) & 0xff; count_buf[2] = (count >> 8) & 0xff; count_buf[3] = count & 0xff; hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp); os_memcpy(digest, tmp, SHA1_MAC_LEN); for (i = 1; i < iterations; i++) { hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN, tmp2); os_memcpy(tmp, tmp2, SHA1_MAC_LEN); for (j = 0; j < SHA1_MAC_LEN; j++) digest[j] ^= tmp2[j]; } } /** * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i * @passphrase: ASCII passphrase * @ssid: SSID * @ssid_len: SSID length in bytes * @iterations: Number of iterations to run * @buf: Buffer for the generated key * @buflen: Length of the buffer in bytes * * This function is used to derive PSK for WPA-PSK. For this protocol, * iterations is set to 4096 and buflen to 32. This function is described in * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. */ void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen) { unsigned int count = 0; unsigned char *pos = buf; size_t left = buflen, plen; unsigned char digest[SHA1_MAC_LEN]; while (left > 0) { count++; pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, digest); plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; os_memcpy(pos, digest, plen); pos += plen; left -= plen; } } #endif /* CONFIG_NO_PBKDF2 */