b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta/*
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta Authors:
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta Jan Cholasta <jcholast@redhat.com>
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta Copyright (C) 2012 Red Hat
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta This program is free software; you can redistribute it and/or modify
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta it under the terms of the GNU General Public License as published by
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta the Free Software Foundation; either version 3 of the License, or
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta (at your option) any later version.
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta This program is distributed in the hope that it will be useful,
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta but WITHOUT ANY WARRANTY; without even the implied warranty of
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta GNU General Public License for more details.
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta You should have received a copy of the GNU General Public License
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta along with this program. If not, see <http://www.gnu.org/licenses/>.
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta*/
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta/*
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta NSS does not provide public API for HMAC, so we implement it ourselves.
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta See RFC 2104 for details on the algorithm.
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta*/
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta#include "util/util.h"
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta#include "util/crypto/sss_crypto.h"
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta#include "util/crypto/nss/nss_util.h"
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta#include <sechash.h>
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta#define HMAC_SHA1_BLOCKSIZE 64
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholastaint sss_hmac_sha1(const unsigned char *key,
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta size_t key_len,
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta const unsigned char *in,
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta size_t in_len,
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta unsigned char *out)
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta{
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta int ret;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta unsigned char ikey[HMAC_SHA1_BLOCKSIZE], okey[HMAC_SHA1_BLOCKSIZE];
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta size_t i;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASHContext *sha1;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta unsigned char hash[SSS_SHA1_LENGTH];
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta unsigned int res_len;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta ret = nspr_nss_init();
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta if (ret != EOK) {
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta return ret;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta }
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta sha1 = HASH_Create(HASH_AlgSHA1);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta if (!sha1) {
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta return ENOMEM;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta }
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta if (key_len > HMAC_SHA1_BLOCKSIZE) {
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta /* keys longer than blocksize are shortened */
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Begin(sha1);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Update(sha1, key, key_len);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_End(sha1, ikey, &res_len, SSS_SHA1_LENGTH);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta memset(ikey + SSS_SHA1_LENGTH, 0, HMAC_SHA1_BLOCKSIZE - SSS_SHA1_LENGTH);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta } else {
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta /* keys shorter than blocksize are zero-padded */
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta memcpy(ikey, key, key_len);
73505920a70e33977e84c69b4c3c598f683b7526Ondrej Kos if (key_len != HMAC_SHA1_BLOCKSIZE) {
73505920a70e33977e84c69b4c3c598f683b7526Ondrej Kos memset(ikey + key_len, 0, HMAC_SHA1_BLOCKSIZE - key_len);
73505920a70e33977e84c69b4c3c598f683b7526Ondrej Kos }
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta }
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta /* HMAC(key, msg) = HASH(key XOR opad, HASH(key XOR ipad, msg)) */
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta for (i = 0; i < HMAC_SHA1_BLOCKSIZE; i++) {
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta okey[i] = ikey[i] ^ 0x5c;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta ikey[i] ^= 0x36;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta }
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Begin(sha1);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Update(sha1, ikey, HMAC_SHA1_BLOCKSIZE);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Update(sha1, in, in_len);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_End(sha1, hash, &res_len, SSS_SHA1_LENGTH);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Begin(sha1);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Update(sha1, okey, HMAC_SHA1_BLOCKSIZE);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Update(sha1, hash, SSS_SHA1_LENGTH);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_End(sha1, out, &res_len, SSS_SHA1_LENGTH);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta HASH_Destroy(sha1);
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta return EOK;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta}