/** @file sha_256.c * * @brief This file defines the SHA256 hash implementation and interface functions * * Copyright (C) 2014-2017, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 * (the "License"). You may use, redistribute and/or modify this File in * accordance with the terms and conditions of the License, a copy of which * is available by writing to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE * ARE EXPRESSLY DISCLAIMED. The License provides additional details about * this warranty disclaimer. */ /****************************************************** Change log: 03/07/2014: Initial version ******************************************************/ /* * SHA-256 hash implementation and interface functions * * Copyright ?2003-2006, Jouni Malinen * * Copyright ?2006-2007, Marvell International Ltd. and its affiliates * All rights reserved. * * 1. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 2. Neither the name of Jouni Malinen, Marvell nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "sha_256.h" #include "hostsa_ext_def.h" #include "authenticator.h" #define WPA_GET_BE32(a) ((((UINT32) (a)[0]) << 24) | \ (((UINT32) (a)[1]) << 16) | \ (((UINT32) (a)[2]) << 8) | \ ((UINT32) (a)[3])) #define WPA_PUT_BE32(a, val) \ do { \ (a)[0] = (UINT8) (((UINT32) (val)) >> 24); \ (a)[1] = (UINT8) (((UINT32) (val)) >> 16); \ (a)[2] = (UINT8) (((UINT32) (val)) >> 8); \ (a)[3] = (UINT8) (((UINT32) (val)) & 0xff); \ } while (0) #define WPA_PUT_BE64(a, val) \ do { \ (a)[0] = (UINT8) (((UINT64) (val)) >> 56); \ (a)[1] = (UINT8) (((UINT64) (val)) >> 48); \ (a)[2] = (UINT8) (((UINT64) (val)) >> 40); \ (a)[3] = (UINT8) (((UINT64) (val)) >> 32); \ (a)[4] = (UINT8) (((UINT64) (val)) >> 24); \ (a)[5] = (UINT8) (((UINT64) (val)) >> 16); \ (a)[6] = (UINT8) (((UINT64) (val)) >> 8); \ (a)[7] = (UINT8) (((UINT64) (val)) & 0xff); \ } while (0) /** * @brief hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) * @param priv pointer to previous element * @param key: Key for HMAC operations * @param key_len: Length of the key in bytes * @param num_elem: Number of elements in the data vector; including [0] spare * @param addr: Pointers to the data areas, [0] element must be left as spare * @param len: Lengths of the data blocks, [0] element must be left as spare * @param mac: Buffer for the hash (32 bytes) * @param pScratchMem: Scratch Memory; At least a 492 byte buffer. */ void hmac_sha256_vector(void *priv, UINT8 *key, size_t key_len, size_t num_elem, UINT8 *addr[], size_t * len, UINT8 *mac, UINT8 *pScratchMem) { phostsa_private psapriv = (phostsa_private)priv; hostsa_util_fns *util_fns = &psapriv->util_fns; size_t i; UINT8 *pKpad; /* was UINT8 k_pad[64], padding - key XORd with ipad/opad */ UINT8 *pTk; /* was UINT8 tk[32] */ UINT8 *pTmpBuf; UINT32 *ptrU32; pKpad = pScratchMem; /* kpad = 64 bytes */ pTk = pKpad + 64; /* tk = 32 bytes */ pTmpBuf = pTk + 32; /* offset into the scratch buf = +96 bytes */ /* if key is longer than 64 bytes reset it to key = SHA256(key) */ if (key_len > 64) { /* pTmpBuf = At least 396 bytes */ sha256_vector(priv, 1, &key, &key_len, pTk, pTmpBuf); key = pTk; key_len = 32; } /* the HMAC_SHA256 transform looks like: * * SHA256(K XOR opad, SHA256(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 */ memset(util_fns, pKpad, 0x00, 64); memcpy(util_fns, pKpad, key, key_len); /* XOR key with ipad values */ ptrU32 = (UINT32 *)pKpad; for (i = 16; i > 0; i--) { *ptrU32++ ^= 0x36363636; } /* perform inner SHA256 */ addr[0] = pKpad; len[0] = 64; /* pTmpBuf = At least 396 bytes */ sha256_vector((void *)priv, num_elem, addr, len, mac, pTmpBuf); memset(util_fns, pKpad, 0x00, 64); memcpy(util_fns, pKpad, key, key_len); /* XOR key with opad values */ ptrU32 = (UINT32 *)pKpad; for (i = 16; i > 0; i--) { *ptrU32++ ^= 0x5C5C5C5C; } /* perform outer SHA256 */ addr[0] = pKpad; len[0] = 64; addr[1] = mac; len[1] = SHA256_MAC_LEN; /* pTmpBuf = At least 396 bytes */ sha256_vector((void *)priv, 2, addr, len, mac, pTmpBuf); } static int sha256_process(void *priv, struct sha256_state *md, const UINT8 *in, unsigned int inlen, UINT8 *pScratchMem); static int sha256_done(void *priv, struct sha256_state *md, UINT8 *out, UINT8 *pScratchMem); /** * @brief sha256_vector - SHA256 hash for data vector * @param priv pointer to previous element * @param num_elem Number of elements in the data vector * @param addr Pointers to the data areas * @param len Lengths of the data blocks * @param mac Buffer for the hash * @param pScratchMem Scratch memory; At least (108 + 288) = 396 bytes */ void sha256_vector(void *priv, size_t num_elem, UINT8 *addr[], size_t * len, UINT8 *mac, UINT8 *pScratchMem) { UINT8 *pTmpBuf; size_t i; struct sha256_state *pCtx; /* ** sizeof(struct sha256_state) ** ** UINT64 length = 8 ** UINT32 state[8], curlen; = (9 * 4) = 36 ** UINT8 buf[64]; = 64 ** ----- ** 108 */ pCtx = (struct sha256_state *)pScratchMem; pTmpBuf = pScratchMem + sizeof(struct sha256_state); sha256_init(pCtx); for (i = 0; i < num_elem; i++) { /* pTmpBuf = At least 288 bytes of memory */ sha256_process((void *)priv, pCtx, addr[i], len[i], pTmpBuf); } sha256_done((void *)priv, pCtx, mac, pTmpBuf); } /* ===== start - public domain SHA256 implementation ===== */ /* This is based on SHA256 implementation in LibTomCrypt that was released into * public domain by Tom St Denis. */ /* the K array */ static const unsigned int K[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Various logical functions */ #define RORc(x, y) \ (((((unsigned int)(x) & 0xFFFFFFFFUL) >> (unsigned int)((y) & 31)) | \ ((unsigned int)(x) << (unsigned int)(32 - ((y) & 31)))) & 0xFFFFFFFFUL) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) RORc((x), (n)) #define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif /** * sha256_compress - Compress 512-bits. * @param md: Pointer to the element holding hash state. * @param msgBuf: Pointer to the buffer containing the data to be hashed. * @param pScratchMem: Scratch memory; At least 288 bytes of free memory * * */ int sha256_compress(void *priv, struct sha256_state *md, UINT8 *msgBuf, UINT8 *pScratchMem) { phostsa_private psapriv = (phostsa_private)priv; hostsa_util_fns *util_fns = &psapriv->util_fns; UINT32 *pW; /* was UINT32 W[64] */ UINT32 *pS; /* was UINT32 S[8] */ UINT32 t0; UINT32 t1; UINT32 t; UINT32 i; UINT32 *ptrU32; /* pW = (64 * 4) = 256 ** pS = (8 * 4) = 32 ** ----- ** 288 */ ptrU32 = pW = (UINT32 *)pScratchMem; pS = pW + 64; /* copy state into S */ memcpy(util_fns, (UINT8 *)pS, (UINT8 *)md->state, 32); /* copy the a message block of 512-bits into pW[0..15] */ for (i = 16; i > 0; i--) { int a0, a1; a0 = *msgBuf++; a1 = *msgBuf++; a0 <<= 8; a0 |= a1; a1 = *msgBuf++; a0 <<= 8; a0 |= a1; a1 = *msgBuf++; a0 <<= 8; *ptrU32++ = a0 | a1; } /* fill pW[16..63] */ for (i = 48; i > 0; i--) { *ptrU32 = (Gamma1(ptrU32[-2]) + ptrU32[-7] + Gamma0(ptrU32[-15]) + ptrU32[-16]); ptrU32++; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i) \ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + pW[i]; \ t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; for (i = 0; i < 64; ++i) { RND(pS[0], pS[1], pS[2], pS[3], pS[4], pS[5], pS[6], pS[7], i); t = pS[7]; pS[7] = pS[6]; pS[6] = pS[5]; pS[5] = pS[4]; pS[4] = pS[3]; pS[3] = pS[2]; pS[2] = pS[1]; pS[1] = pS[0]; pS[0] = t; } /* feedback */ for (i = 0; i < 8; i++) { md->state[i] = md->state[i] + pS[i]; } return 0; } /* Initialize the hash state */ void sha256_init(struct sha256_state *md) { md->curlen = 0; md->length = 0; md->state[0] = 0x6A09E667UL; md->state[1] = 0xBB67AE85UL; md->state[2] = 0x3C6EF372UL; md->state[3] = 0xA54FF53AUL; md->state[4] = 0x510E527FUL; md->state[5] = 0x9B05688CUL; md->state[6] = 0x1F83D9ABUL; md->state[7] = 0x5BE0CD19UL; } /** Process a block of memory though the hash @param md The hash state @param in The data to hash @param inlen The length of the data (octets) @param pScratchMem Temporary Memory Buf; At least 288 bytes. @return CRYPT_OK if successful */ static int sha256_process(void *priv, struct sha256_state *md, const unsigned char *in, unsigned int inlen, UINT8 *pScratchMem) { phostsa_private psapriv = (phostsa_private)priv; hostsa_util_fns *util_fns = &psapriv->util_fns; unsigned int n; #define block_size 64 if (md->curlen > sizeof(md->buf)) { return -1; } while (inlen > 0) { if (md->curlen == 0 && inlen >= block_size) { /* pScratchMem = At least 288 bytes of memory */ if (sha256_compress ((void *)priv, md, (UINT8 *)in, pScratchMem) < 0) { return -1; } md->length += block_size * 8; in += block_size; inlen -= block_size; } else { n = MIN(inlen, (block_size - md->curlen)); memcpy(util_fns, md->buf + md->curlen, in, n); md->curlen += n; in += n; inlen -= n; if (md->curlen == block_size) { /* pScratchMem = At least 288 bytes of memory */ if (sha256_compress ((void *)priv, md, md->buf, pScratchMem) < 0) { return -1; } md->length += 8 * block_size; md->curlen = 0; } } } return 0; } /** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (32 bytes) @param pScratchMem [in] Scratch memory; At least 288 bytes @return CRYPT_OK if successful */ static int sha256_done(void *priv, struct sha256_state *md, UINT8 *out, UINT8 *pScratchMem) { int i; UINT32 *ptrU32; UINT32 tmpU32; if (md->curlen >= sizeof(md->buf)) { return -1; } /* increase the length of the message */ md->length += md->curlen * 8; /* append the '1' bit */ md->buf[md->curlen++] = (unsigned char)0x80; /* if the length is currently above 56 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->curlen > 56) { while (md->curlen < 64) { md->buf[md->curlen++] = (unsigned char)0; } /* pScratchMem = At least 288 bytes of memory */ sha256_compress((void *)priv, md, md->buf, pScratchMem); md->curlen = 0; } /* pad upto 56 bytes of zeroes */ while (md->curlen < 56) { md->buf[md->curlen++] = (unsigned char)0; } /* store length */ ptrU32 = (UINT32 *)&md->length; for (i = 0; i < 2; i++) { tmpU32 = *ptrU32++; WPA_PUT_BE32(md->buf + 60 - 4 * i, tmpU32); } /* pScratchMem = At least 288 bytes of memory */ sha256_compress((void *)priv, md, md->buf, pScratchMem); ptrU32 = md->state; /* copy output */ for (i = 8; i > 0; i--) { tmpU32 = *ptrU32++; WPA_PUT_BE32(out, tmpU32); out += sizeof(UINT32); } return 0; } /* ===== end - public domain SHA256 implementation ===== */