void psHmacFinal(psHmac_t *ctx, unsigned char hash[MAX_HASHLEN]) { switch((psCipherType_e)ctx->type) { #ifdef USE_HMAC_MD5 case HMAC_MD5: psHmacMd5Final(&ctx->u.md5, hash); break; #endif #ifdef USE_HMAC_SHA1 case HMAC_SHA1: psHmacSha1Final(&ctx->u.sha1, hash); break; #endif #ifdef USE_HMAC_SHA256 case HMAC_SHA256: psHmacSha256Final(&ctx->u.sha256, hash); break; #endif #ifdef USE_HMAC_SHA384 case HMAC_SHA384: psHmacSha384Final(&ctx->u.sha384, hash); break; #endif default: break; } ctx->type = 0; }
/* HMAC-MD5 http://www.faqs.org/rfcs/rfc2104.html the HMAC_MD5 transform looks like: MD5(K XOR opad, MD5(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 If the keyLen is > 64 bytes, we hash the key and use it instead */ int32 psHmacMd5(unsigned char *key, uint32 keyLen, const unsigned char *buf, uint32 len, unsigned char *hash, unsigned char *hmacKey, uint32 *hmacKeyLen) { psHmacContext_t ctx; psDigestContext_t md; /* Support for keys larger than 64 bytes. In this case, we take the hash of the key itself and use that instead. Inform the caller by updating the hmacKey and hmacKeyLen outputs */ if (keyLen > 64) { psMd5Init(&md); psMd5Update(&md, key, keyLen); *hmacKeyLen = psMd5Final(&md, hash); memcpy(hmacKey, hash, *hmacKeyLen); } else { hmacKey = key; *hmacKeyLen = keyLen; } psHmacMd5Init(&ctx, hmacKey, *hmacKeyLen); psHmacMd5Update(&ctx, buf, len); return psHmacMd5Final(&ctx, hash); }
/* TLS MD5 HMAC generate/verify */ int32_t tlsHMACMd5(ssl_t *ssl, int32 mode, unsigned char type, unsigned char *data, uint32 len, unsigned char *mac) { psHmacMd5_t ctx; unsigned char *key, *seq; unsigned char majVer, minVer, tmp[5]; int32 i; majVer = ssl->majVer; minVer = ssl->minVer; if (mode == HMAC_CREATE) { key = ssl->sec.writeMAC; seq = ssl->sec.seq; } else { /* HMAC_VERIFY */ key = ssl->sec.readMAC; seq = ssl->sec.remSeq; } /* Sanity */ if (key == NULL) { return PS_FAILURE; } if (psHmacMd5Init(&ctx, key, MD5_HASH_SIZE) < 0) { return PS_FAIL; } #ifdef USE_DTLS if (ssl->flags & SSL_FLAGS_DTLS) { if (mode == HMAC_CREATE) { psHmacMd5Update(&ctx, ssl->epoch, 2); psHmacMd5Update(&ctx, ssl->rsn, 6); } else { /* HMAC_VERIFY */ psHmacMd5Update(&ctx, ssl->rec.epoch, 2); psHmacMd5Update(&ctx, ssl->rec.rsn, 6); } } else { #endif /* USE_DTLS */ psHmacMd5Update(&ctx, seq, 8); for (i = 7; i >= 0; i--) { seq[i]++; if (seq[i] != 0) { break; } } #ifdef USE_DTLS } #endif /* USE_DTLS */ tmp[0] = type; tmp[1] = majVer; tmp[2] = minVer; tmp[3] = (len & 0xFF00) >> 8; tmp[4] = len & 0xFF; psHmacMd5Update(&ctx, tmp, 5); psHmacMd5Update(&ctx, data, len); psHmacMd5Final(&ctx, mac); return PS_SUCCESS; }
/* MD5 portions of the prf */ __inline static int32_t pMd5(const unsigned char *key, uint16_t keyLen, const unsigned char *text, uint16_t textLen, unsigned char *out, uint16_t outLen) { psHmacMd5_t ctx; unsigned char a[MD5_HASH_SIZE]; unsigned char mac[MD5_HASH_SIZE]; unsigned char hmacKey[MD5_HASH_SIZE]; int32_t rc = PS_FAIL; uint16_t hmacKeyLen, i, keyIter; for (keyIter = 1; (uint16_t)(MD5_HASH_SIZE * keyIter) < outLen;) { keyIter++; } if ((rc = psHmacMd5(key, keyLen, text, textLen, a, hmacKey, &hmacKeyLen)) < 0) { goto L_RETURN; } if (hmacKeyLen != keyLen) { /* Support for keys larger than 64 bytes. Must take the hash of the original key in these cases which is indicated by different outgoing values from the passed in key and keyLen values */ psAssert(keyLen > 64); /* Typecast is OK, we don't update key below */ key = (const unsigned char *)hmacKey; keyLen = hmacKeyLen; } for (i = 0; i < keyIter; i++) { if ((rc = psHmacMd5Init(&ctx, key, keyLen)) < 0) { goto L_RETURN; } psHmacMd5Update(&ctx, a, MD5_HASH_SIZE); psHmacMd5Update(&ctx, text, textLen); psHmacMd5Final(&ctx, mac); if (i == keyIter - 1) { memcpy(out + (MD5_HASH_SIZE*i), mac, outLen - (MD5_HASH_SIZE*i)); } else { memcpy(out + (MD5_HASH_SIZE * i), mac, MD5_HASH_SIZE); if ((rc = psHmacMd5(key, keyLen, a, MD5_HASH_SIZE, a, hmacKey, &hmacKeyLen)) < 0) { goto L_RETURN; } } } rc = PS_SUCCESS; L_RETURN: memzero_s(a, MD5_HASH_SIZE); memzero_s(mac, MD5_HASH_SIZE); memzero_s(hmacKey, MD5_HASH_SIZE); if (rc < 0) { memzero_s(out, outLen); /* zero any partial result on error */ } return rc; }
/* MD5 portions of the prf */ static int32 pMd5(unsigned char *key, uint32 keyLen, unsigned char *text, uint32 textLen, unsigned char *out, uint32 outLen) { psHmacContext_t ctx; unsigned char a[MD5_HASH_SIZE]; unsigned char mac[MD5_HASH_SIZE]; unsigned char hmacKey[MD5_HASH_SIZE]; int32 i, keyIter = 1; uint32 hmacKeyLen; while ((uint32)(MD5_HASH_SIZE * keyIter) < outLen) { keyIter++; } psHmacMd5(key, keyLen, text, textLen, a, hmacKey, &hmacKeyLen); if (hmacKeyLen != keyLen) { /* Support for keys larger than 64 bytes. Must take the hash of the original key in these cases which is indicated by different outgoing values from the passed in key and keyLen values */ psAssert(keyLen > 64); key = hmacKey; keyLen = hmacKeyLen; } for (i = 0; i < keyIter; i++) { psHmacMd5Init(&ctx, key, keyLen); psHmacMd5Update(&ctx, a, MD5_HASH_SIZE); psHmacMd5Update(&ctx, text, textLen); psHmacMd5Final(&ctx, mac); if (i == keyIter - 1) { memcpy(out + (MD5_HASH_SIZE*i), mac, outLen - (MD5_HASH_SIZE*i)); } else { memcpy(out + (MD5_HASH_SIZE * i), mac, MD5_HASH_SIZE); psHmacMd5(key, keyLen, a, MD5_HASH_SIZE, a, hmacKey, &hmacKeyLen); } } return 0; }
/* TLS MD5 HMAC generate/verify */ int32 tlsHMACMd5(ssl_t *ssl, int32 mode, unsigned char type, unsigned char *data, uint32 len, unsigned char *mac) { psHmacContext_t ctx; unsigned char *key, *seq; unsigned char majVer, minVer, tmp[5]; int32 i; majVer = ssl->majVer; minVer = ssl->minVer; if (mode == HMAC_CREATE) { key = ssl->sec.writeMAC; seq = ssl->sec.seq; } else { /* HMAC_VERIFY */ key = ssl->sec.readMAC; seq = ssl->sec.remSeq; } psHmacMd5Init(&ctx, key, MD5_HASH_SIZE); psHmacMd5Update(&ctx, seq, 8); for (i = 7; i >= 0; i--) { seq[i]++; if (seq[i] != 0) { break; } } tmp[0] = type; tmp[1] = majVer; tmp[2] = minVer; tmp[3] = (len & 0xFF00) >> 8; tmp[4] = len & 0xFF; psHmacMd5Update(&ctx, tmp, 5); psHmacMd5Update(&ctx, data, len); return psHmacMd5Final(&ctx, mac); }
int32_t psHmacMd5(const unsigned char *key, uint16_t keyLen, const unsigned char *buf, uint32_t len, unsigned char hash[MD5_HASHLEN], unsigned char *hmacKey, uint16_t *hmacKeyLen) { int32_t rc; union { psHmacMd5_t mac; psMd5_t md; } u; psHmacMd5_t *mac = &u.mac; psMd5_t *md = &u.md; /* Support for keys larger than 64 bytes. In this case, we take the hash of the key itself and use that instead. Inform the caller by updating the hmacKey and hmacKeyLen outputs */ if (keyLen > 64) { if ((rc = psMd5Init(md)) < 0) { return rc; } psMd5Update(md, key, keyLen); psMd5Final(md, hash); *hmacKeyLen = MD5_HASHLEN; memcpy(hmacKey, hash, *hmacKeyLen); } else { hmacKey = (unsigned char *)key; /* @note typecasting from const */ *hmacKeyLen = keyLen; } if ((rc = psHmacMd5Init(mac, hmacKey, *hmacKeyLen)) < 0) { return rc; } psHmacMd5Update(mac, buf, len); psHmacMd5Final(mac, hash); return PS_SUCCESS; }