1189251Ssam/* 2189251Ssam * SHA-256 hash implementation and interface functions 3189251Ssam * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18189251Ssam#include "sha256.h" 19189251Ssam#include "crypto.h" 20189251Ssam 21189251Ssam 22189251Ssam/** 23189251Ssam * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) 24189251Ssam * @key: Key for HMAC operations 25189251Ssam * @key_len: Length of the key in bytes 26189251Ssam * @num_elem: Number of elements in the data vector 27189251Ssam * @addr: Pointers to the data areas 28189251Ssam * @len: Lengths of the data blocks 29189251Ssam * @mac: Buffer for the hash (32 bytes) 30189251Ssam */ 31189251Ssamvoid hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, 32189251Ssam const u8 *addr[], const size_t *len, u8 *mac) 33189251Ssam{ 34189251Ssam unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ 35189251Ssam unsigned char tk[32]; 36189251Ssam const u8 *_addr[6]; 37189251Ssam size_t _len[6], i; 38189251Ssam 39189251Ssam if (num_elem > 5) { 40189251Ssam /* 41189251Ssam * Fixed limit on the number of fragments to avoid having to 42189251Ssam * allocate memory (which could fail). 43189251Ssam */ 44189251Ssam return; 45189251Ssam } 46189251Ssam 47189251Ssam /* if key is longer than 64 bytes reset it to key = SHA256(key) */ 48189251Ssam if (key_len > 64) { 49189251Ssam sha256_vector(1, &key, &key_len, tk); 50189251Ssam key = tk; 51189251Ssam key_len = 32; 52189251Ssam } 53189251Ssam 54189251Ssam /* the HMAC_SHA256 transform looks like: 55189251Ssam * 56189251Ssam * SHA256(K XOR opad, SHA256(K XOR ipad, text)) 57189251Ssam * 58189251Ssam * where K is an n byte key 59189251Ssam * ipad is the byte 0x36 repeated 64 times 60189251Ssam * opad is the byte 0x5c repeated 64 times 61189251Ssam * and text is the data being protected */ 62189251Ssam 63189251Ssam /* start out by storing key in ipad */ 64189251Ssam os_memset(k_pad, 0, sizeof(k_pad)); 65189251Ssam os_memcpy(k_pad, key, key_len); 66189251Ssam /* XOR key with ipad values */ 67189251Ssam for (i = 0; i < 64; i++) 68189251Ssam k_pad[i] ^= 0x36; 69189251Ssam 70189251Ssam /* perform inner SHA256 */ 71189251Ssam _addr[0] = k_pad; 72189251Ssam _len[0] = 64; 73189251Ssam for (i = 0; i < num_elem; i++) { 74189251Ssam _addr[i + 1] = addr[i]; 75189251Ssam _len[i + 1] = len[i]; 76189251Ssam } 77189251Ssam sha256_vector(1 + num_elem, _addr, _len, mac); 78189251Ssam 79189251Ssam os_memset(k_pad, 0, sizeof(k_pad)); 80189251Ssam os_memcpy(k_pad, key, key_len); 81189251Ssam /* XOR key with opad values */ 82189251Ssam for (i = 0; i < 64; i++) 83189251Ssam k_pad[i] ^= 0x5c; 84189251Ssam 85189251Ssam /* perform outer SHA256 */ 86189251Ssam _addr[0] = k_pad; 87189251Ssam _len[0] = 64; 88189251Ssam _addr[1] = mac; 89189251Ssam _len[1] = SHA256_MAC_LEN; 90189251Ssam sha256_vector(2, _addr, _len, mac); 91189251Ssam} 92189251Ssam 93189251Ssam 94189251Ssam/** 95189251Ssam * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) 96189251Ssam * @key: Key for HMAC operations 97189251Ssam * @key_len: Length of the key in bytes 98189251Ssam * @data: Pointers to the data area 99189251Ssam * @data_len: Length of the data area 100189251Ssam * @mac: Buffer for the hash (20 bytes) 101189251Ssam */ 102189251Ssamvoid hmac_sha256(const u8 *key, size_t key_len, const u8 *data, 103189251Ssam size_t data_len, u8 *mac) 104189251Ssam{ 105189251Ssam hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); 106189251Ssam} 107189251Ssam 108189251Ssam 109189251Ssam/** 110189251Ssam * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) 111189251Ssam * @key: Key for PRF 112189251Ssam * @key_len: Length of the key in bytes 113189251Ssam * @label: A unique label for each purpose of the PRF 114189251Ssam * @data: Extra data to bind into the key 115189251Ssam * @data_len: Length of the data 116189251Ssam * @buf: Buffer for the generated pseudo-random key 117189251Ssam * @buf_len: Number of bytes of key to generate 118189251Ssam * 119189251Ssam * This function is used to derive new, cryptographically separate keys from a 120189251Ssam * given key. 121189251Ssam */ 122189251Ssamvoid sha256_prf(const u8 *key, size_t key_len, const char *label, 123189251Ssam const u8 *data, size_t data_len, u8 *buf, size_t buf_len) 124189251Ssam{ 125209158Srpaulo u16 counter = 1; 126189251Ssam size_t pos, plen; 127189251Ssam u8 hash[SHA256_MAC_LEN]; 128189251Ssam const u8 *addr[4]; 129189251Ssam size_t len[4]; 130189251Ssam u8 counter_le[2], length_le[2]; 131189251Ssam 132189251Ssam addr[0] = counter_le; 133189251Ssam len[0] = 2; 134189251Ssam addr[1] = (u8 *) label; 135189251Ssam len[1] = os_strlen(label); 136189251Ssam addr[2] = data; 137189251Ssam len[2] = data_len; 138189251Ssam addr[3] = length_le; 139189251Ssam len[3] = sizeof(length_le); 140189251Ssam 141189251Ssam WPA_PUT_LE16(length_le, buf_len * 8); 142189251Ssam pos = 0; 143189251Ssam while (pos < buf_len) { 144189251Ssam plen = buf_len - pos; 145189251Ssam WPA_PUT_LE16(counter_le, counter); 146189251Ssam if (plen >= SHA256_MAC_LEN) { 147189251Ssam hmac_sha256_vector(key, key_len, 4, addr, len, 148189251Ssam &buf[pos]); 149189251Ssam pos += SHA256_MAC_LEN; 150189251Ssam } else { 151189251Ssam hmac_sha256_vector(key, key_len, 4, addr, len, hash); 152189251Ssam os_memcpy(&buf[pos], hash, plen); 153189251Ssam break; 154189251Ssam } 155189251Ssam counter++; 156189251Ssam } 157189251Ssam} 158