1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/alghmac.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,165 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifdef FREEBL_NO_DEPEND 1.9 +#include "stubs.h" 1.10 +#endif 1.11 + 1.12 +#include "secport.h" 1.13 +#include "hasht.h" 1.14 +#include "blapit.h" 1.15 +#include "alghmac.h" 1.16 +#include "secerr.h" 1.17 + 1.18 +#define HMAC_PAD_SIZE HASH_BLOCK_LENGTH_MAX 1.19 + 1.20 +struct HMACContextStr { 1.21 + void *hash; 1.22 + const SECHashObject *hashobj; 1.23 + PRBool wasAllocated; 1.24 + unsigned char ipad[HMAC_PAD_SIZE]; 1.25 + unsigned char opad[HMAC_PAD_SIZE]; 1.26 +}; 1.27 + 1.28 +void 1.29 +HMAC_Destroy(HMACContext *cx, PRBool freeit) 1.30 +{ 1.31 + if (cx == NULL) 1.32 + return; 1.33 + 1.34 + PORT_Assert(!freeit == !cx->wasAllocated); 1.35 + if (cx->hash != NULL) { 1.36 + cx->hashobj->destroy(cx->hash, PR_TRUE); 1.37 + PORT_Memset(cx, 0, sizeof *cx); 1.38 + } 1.39 + if (freeit) 1.40 + PORT_Free(cx); 1.41 +} 1.42 + 1.43 +SECStatus 1.44 +HMAC_Init( HMACContext * cx, const SECHashObject *hash_obj, 1.45 + const unsigned char *secret, unsigned int secret_len, PRBool isFIPS) 1.46 +{ 1.47 + unsigned int i; 1.48 + unsigned char hashed_secret[HASH_LENGTH_MAX]; 1.49 + 1.50 + /* required by FIPS 198 Section 3 */ 1.51 + if (isFIPS && secret_len < hash_obj->length/2) { 1.52 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.53 + return SECFailure; 1.54 + } 1.55 + if (cx == NULL) { 1.56 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.57 + return SECFailure; 1.58 + } 1.59 + cx->wasAllocated = PR_FALSE; 1.60 + cx->hashobj = hash_obj; 1.61 + cx->hash = cx->hashobj->create(); 1.62 + if (cx->hash == NULL) 1.63 + goto loser; 1.64 + 1.65 + if (secret_len > cx->hashobj->blocklength) { 1.66 + cx->hashobj->begin( cx->hash); 1.67 + cx->hashobj->update(cx->hash, secret, secret_len); 1.68 + PORT_Assert(cx->hashobj->length <= sizeof hashed_secret); 1.69 + cx->hashobj->end( cx->hash, hashed_secret, &secret_len, 1.70 + sizeof hashed_secret); 1.71 + if (secret_len != cx->hashobj->length) { 1.72 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.73 + goto loser; 1.74 + } 1.75 + secret = (const unsigned char *)&hashed_secret[0]; 1.76 + } 1.77 + 1.78 + PORT_Memset(cx->ipad, 0x36, cx->hashobj->blocklength); 1.79 + PORT_Memset(cx->opad, 0x5c, cx->hashobj->blocklength); 1.80 + 1.81 + /* fold secret into padding */ 1.82 + for (i = 0; i < secret_len; i++) { 1.83 + cx->ipad[i] ^= secret[i]; 1.84 + cx->opad[i] ^= secret[i]; 1.85 + } 1.86 + PORT_Memset(hashed_secret, 0, sizeof hashed_secret); 1.87 + return SECSuccess; 1.88 + 1.89 +loser: 1.90 + PORT_Memset(hashed_secret, 0, sizeof hashed_secret); 1.91 + if (cx->hash != NULL) 1.92 + cx->hashobj->destroy(cx->hash, PR_TRUE); 1.93 + return SECFailure; 1.94 +} 1.95 + 1.96 +HMACContext * 1.97 +HMAC_Create(const SECHashObject *hash_obj, const unsigned char *secret, 1.98 + unsigned int secret_len, PRBool isFIPS) 1.99 +{ 1.100 + SECStatus rv; 1.101 + HMACContext * cx = PORT_ZNew(HMACContext); 1.102 + if (cx == NULL) 1.103 + return NULL; 1.104 + rv = HMAC_Init(cx, hash_obj, secret, secret_len, isFIPS); 1.105 + cx->wasAllocated = PR_TRUE; 1.106 + if (rv != SECSuccess) { 1.107 + PORT_Free(cx); /* contains no secret info */ 1.108 + cx = NULL; 1.109 + } 1.110 + return cx; 1.111 +} 1.112 + 1.113 +void 1.114 +HMAC_Begin(HMACContext *cx) 1.115 +{ 1.116 + /* start inner hash */ 1.117 + cx->hashobj->begin(cx->hash); 1.118 + cx->hashobj->update(cx->hash, cx->ipad, cx->hashobj->blocklength); 1.119 +} 1.120 + 1.121 +void 1.122 +HMAC_Update(HMACContext *cx, const unsigned char *data, unsigned int data_len) 1.123 +{ 1.124 + cx->hashobj->update(cx->hash, data, data_len); 1.125 +} 1.126 + 1.127 +SECStatus 1.128 +HMAC_Finish(HMACContext *cx, unsigned char *result, unsigned int *result_len, 1.129 + unsigned int max_result_len) 1.130 +{ 1.131 + if (max_result_len < cx->hashobj->length) { 1.132 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.133 + return SECFailure; 1.134 + } 1.135 + 1.136 + cx->hashobj->end(cx->hash, result, result_len, max_result_len); 1.137 + if (*result_len != cx->hashobj->length) 1.138 + return SECFailure; 1.139 + 1.140 + cx->hashobj->begin(cx->hash); 1.141 + cx->hashobj->update(cx->hash, cx->opad, cx->hashobj->blocklength); 1.142 + cx->hashobj->update(cx->hash, result, *result_len); 1.143 + cx->hashobj->end(cx->hash, result, result_len, max_result_len); 1.144 + return SECSuccess; 1.145 +} 1.146 + 1.147 +HMACContext * 1.148 +HMAC_Clone(HMACContext *cx) 1.149 +{ 1.150 + HMACContext *newcx; 1.151 + 1.152 + newcx = (HMACContext*)PORT_ZAlloc(sizeof(HMACContext)); 1.153 + if (newcx == NULL) 1.154 + goto loser; 1.155 + 1.156 + newcx->wasAllocated = PR_TRUE; 1.157 + newcx->hashobj = cx->hashobj; 1.158 + newcx->hash = cx->hashobj->clone(cx->hash); 1.159 + if (newcx->hash == NULL) 1.160 + goto loser; 1.161 + PORT_Memcpy(newcx->ipad, cx->ipad, cx->hashobj->blocklength); 1.162 + PORT_Memcpy(newcx->opad, cx->opad, cx->hashobj->blocklength); 1.163 + return newcx; 1.164 + 1.165 +loser: 1.166 + HMAC_Destroy(newcx, PR_TRUE); 1.167 + return NULL; 1.168 +}