| /** @file hmac_sha1.c |
| * |
| * @brief This file defines algorithm for hmac sha1 |
| * |
| * Copyright (C) 2014, 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 |
| ******************************************************/ |
| #include "wltypes.h" |
| #include "wl_macros.h" |
| #include "sha1.h" |
| #include "hostsa_ext_def.h" |
| #include "authenticator.h" |
| |
| void |
| Mrvl_hmac_sha1(void *priv, unsigned char **ppText, |
| int *pTextLen, |
| int textNum, |
| unsigned char *key, |
| int key_len, unsigned char *output, int outputLen) |
| { |
| /* |
| Note- Some of the variables are made static in this function |
| becuase currently this function executes in the idle task. The idle |
| task dosent have enough stack space to accomodate these varables. |
| In the future if this function in executed in a different task or |
| if we increase the stack size of the idle task then we can put |
| these variables on the stack */ |
| // BufferDesc_t * pDesc = NULL; |
| phostsa_private psapriv = (phostsa_private)priv; |
| hostsa_util_fns *util_fns = &psapriv->util_fns; |
| UINT8 buf[400] = { 0 }; |
| Mrvl_SHA1_CTX *context; |
| unsigned char *k_pad; /* padding - key XORd with i/opad */ |
| unsigned char *digest; |
| int i; |
| |
| k_pad = (unsigned char *)buf; |
| digest = k_pad + 64; |
| context = (Mrvl_SHA1_CTX *)(k_pad + 64 + 20); |
| |
| /* if key is longer than 64 bytes reset it to key=SHA1(key) */ |
| if (key_len > 64) { |
| Mrvl_SHA1Init(context); |
| Mrvl_SHA1Update(context, key, key_len); |
| Mrvl_SHA1Final((void *)priv, context, key); |
| |
| 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 |
| */ |
| |
| /* perform inner SHA1 */ |
| /* start out by storing key in pads */ |
| memset(util_fns, k_pad, 0, 64); |
| memcpy(util_fns, k_pad, key, key_len); |
| |
| /* XOR key with ipad and opad values */ |
| for (i = 0; i < 8; i++) { |
| ((UINT64 *)k_pad)[i] ^= 0x3636363636363636; |
| } |
| |
| Mrvl_SHA1Init(context); /* init context for 1st pass */ |
| Mrvl_SHA1Update(context, k_pad, 64); /* start with inner pad */ |
| for (i = 0; i < textNum; i++) { |
| /* then text of datagram */ |
| Mrvl_SHA1Update(context, ppText[i], pTextLen[i]); |
| } |
| |
| Mrvl_SHA1Final((void *)priv, context, digest); /* finish up 1st pass */ |
| |
| /* perform outer SHA1 */ |
| /* start out by storing key in pads */ |
| memset(util_fns, k_pad, 0, 64); |
| memcpy(util_fns, k_pad, key, key_len); |
| |
| /* XOR key with ipad and opad values */ |
| for (i = 0; i < 8; i++) { |
| ((UINT64 *)k_pad)[i] ^= 0x5c5c5c5c5c5c5c5c; |
| } |
| |
| Mrvl_SHA1Init(context); /* init context for 2nd pass */ |
| Mrvl_SHA1Update(context, k_pad, 64); /* start with outer pad */ |
| Mrvl_SHA1Update(context, digest, 20); /* then results of 1st hash */ |
| Mrvl_SHA1Final((void *)priv, context, digest); /* finish up 2nd pass */ |
| memcpy(util_fns, output, digest, outputLen); |
| |
| // bml_FreeBuffer((UINT32)pDesc); |
| } |
| |
| /* |
| * PRF -- Length of output is in octets rather than bits |
| * since length is always a multiple of 8 output array is |
| * organized so first N octets starting from 0 contains PRF output |
| * |
| * supported inputs are 16, 32, 48, 64 |
| * output array must be 80 octets to allow for sha1 overflow |
| */ |
| void |
| Mrvl_PRF(void *priv, unsigned char *key, int key_len, |
| unsigned char *prefix, int prefix_len, |
| unsigned char *data, int data_len, unsigned char *output, int len) |
| { |
| phostsa_private psapriv = (phostsa_private)priv; |
| hostsa_util_fns *util_fns = &psapriv->util_fns; |
| int i; |
| int currentindex = 0; |
| int total_len; |
| UINT8 prf_input[120]; /* concatenated input */ |
| unsigned char *pText = prf_input; |
| SINT8 remain = len; |
| |
| memset(util_fns, prf_input, 0x00, sizeof(prf_input)); |
| |
| if (prefix) { |
| memcpy(util_fns, prf_input, prefix, prefix_len); |
| prf_input[prefix_len] = 0; /* single octet 0 */ |
| memcpy(util_fns, &prf_input[prefix_len + 1], data, data_len); |
| total_len = prefix_len + 1 + data_len; |
| } else { |
| memcpy(util_fns, prf_input, data, data_len); |
| total_len = data_len; |
| } |
| |
| prf_input[total_len] = 0; /* single octet count, starts at 0 */ |
| total_len++; |
| for (i = 0; i < (len + 19) / 20; i++) { |
| Mrvl_hmac_sha1(priv, (UINT8 **)&pText, |
| &total_len, |
| 1, |
| key, |
| key_len, &output[currentindex], MIN(20, remain)); |
| currentindex += MIN(20, remain); /* next concatenation |
| location */ |
| remain -= 20; |
| prf_input[total_len - 1]++; /* increment octet count */ |
| } |
| } |