/* * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "hmac.h" #include #include #include typedef struct private_mac_t private_mac_t; /** * Private data of a mac_t object. * * The variable names are the same as in the RFC. */ struct private_mac_t { /** * Implements mac_t interface */ mac_t public; /** * Block size, as in RFC. */ uint8_t b; /** * Hash function. */ hasher_t *h; /** * Previously xor'ed key using opad. */ chunk_t opaded_key; /** * Previously xor'ed key using ipad. */ chunk_t ipaded_key; }; METHOD(mac_t, get_mac, bool, private_mac_t *this, chunk_t data, uint8_t *out) { /* H(K XOR opad, H(K XOR ipad, text)) * * if out is NULL, we append text to the inner hash. * else, we complete the inner and do the outer. * */ uint8_t buffer[this->h->get_hash_size(this->h)]; chunk_t inner; if (out == NULL) { /* append data to inner */ return this->h->get_hash(this->h, data, NULL); } /* append and do outer hash */ inner.ptr = buffer; inner.len = this->h->get_hash_size(this->h); /* complete inner, do outer and reinit for next call */ return this->h->get_hash(this->h, data, buffer) && this->h->get_hash(this->h, this->opaded_key, NULL) && this->h->get_hash(this->h, inner, out) && this->h->get_hash(this->h, this->ipaded_key, NULL); } METHOD(mac_t, get_mac_size, size_t, private_mac_t *this) { return this->h->get_hash_size(this->h); } METHOD(mac_t, set_key, bool, private_mac_t *this, chunk_t key) { int i; uint8_t buffer[this->b]; memset(buffer, 0, this->b); if (key.len > this->b) { /* if key is too long, it will be hashed */ if (!this->h->reset(this->h) || !this->h->get_hash(this->h, key, buffer)) { return FALSE; } } else { /* if not, just copy it in our pre-padded k */ memcpy(buffer, key.ptr, key.len); } /* apply ipad and opad to key */ for (i = 0; i < this->b; i++) { this->ipaded_key.ptr[i] = buffer[i] ^ 0x36; this->opaded_key.ptr[i] = buffer[i] ^ 0x5C; } /* begin hashing of inner pad */ return this->h->reset(this->h) && this->h->get_hash(this->h, this->ipaded_key, NULL); } METHOD(mac_t, destroy, void, private_mac_t *this) { this->h->destroy(this->h); chunk_clear(&this->opaded_key); chunk_clear(&this->ipaded_key); free(this); } /* * Creates an mac_t object */ static mac_t *hmac_create(hash_algorithm_t hash_algorithm) { private_mac_t *this; INIT(this, .public = { .get_mac = _get_mac, .get_mac_size = _get_mac_size, .set_key = _set_key, .destroy = _destroy, }, ); /* set b, according to hasher */ switch (hash_algorithm) { case HASH_SHA1: case HASH_MD5: case HASH_SHA256: this->b = 64; break; case HASH_SHA384: case HASH_SHA512: this->b = 128; break; default: free(this); return NULL; } this->h = lib->crypto->create_hasher(lib->crypto, hash_algorithm); if (this->h == NULL) { free(this); return NULL; } /* build ipad and opad */ this->opaded_key.ptr = malloc(this->b); this->opaded_key.len = this->b; this->ipaded_key.ptr = malloc(this->b); this->ipaded_key.len = this->b; return &this->public; } /* * Described in header */ prf_t *hmac_prf_create(pseudo_random_function_t algo) { mac_t *hmac; hmac = hmac_create(hasher_algorithm_from_prf(algo)); if (hmac) { return mac_prf_create(hmac); } return NULL; } /* * Described in header */ signer_t *hmac_signer_create(integrity_algorithm_t algo) { mac_t *hmac; size_t trunc; hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc)); if (hmac) { return mac_signer_create(hmac, trunc); } return NULL; }