b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta/*
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta Authors:
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta Jan Cholasta <jcholast@redhat.com>
e07a94a66985b674c5df11ca466792902164c4e2George McCollister George McCollister <george.mccollister@gmail.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#include "util/util.h"
e07a94a66985b674c5df11ca466792902164c4e2George McCollister#include "util/crypto/sss_crypto.h"
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
e07a94a66985b674c5df11ca466792902164c4e2George McCollister#include <openssl/evp.h>
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik#include "sss_openssl.h"
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik
e07a94a66985b674c5df11ca466792902164c4e2George McCollister#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{
e07a94a66985b674c5df11ca466792902164c4e2George McCollister int ret;
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_MD_CTX *ctx;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister unsigned char ikey[HMAC_SHA1_BLOCKSIZE], okey[HMAC_SHA1_BLOCKSIZE];
e07a94a66985b674c5df11ca466792902164c4e2George McCollister size_t i;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister unsigned char hash[SSS_SHA1_LENGTH];
e07a94a66985b674c5df11ca466792902164c4e2George McCollister unsigned int res_len;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik ctx = EVP_MD_CTX_new();
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik if (ctx == NULL) {
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik return ENOMEM;
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
e07a94a66985b674c5df11ca466792902164c4e2George McCollister if (key_len > HMAC_SHA1_BLOCKSIZE) {
e07a94a66985b674c5df11ca466792902164c4e2George McCollister /* keys longer than blocksize are shortened */
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik if (!EVP_DigestInit_ex(ctx, EVP_sha1(), NULL)) {
e07a94a66985b674c5df11ca466792902164c4e2George McCollister ret = EIO;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister goto done;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestUpdate(ctx, (const unsigned char *)key, key_len);
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestFinal_ex(ctx, ikey, &res_len);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister memset(ikey + SSS_SHA1_LENGTH, 0, HMAC_SHA1_BLOCKSIZE - SSS_SHA1_LENGTH);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister } else {
e07a94a66985b674c5df11ca466792902164c4e2George McCollister /* keys shorter than blocksize are zero-padded */
e07a94a66985b674c5df11ca466792902164c4e2George McCollister memcpy(ikey, key, key_len);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister memset(ikey + key_len, 0, HMAC_SHA1_BLOCKSIZE - key_len);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
e07a94a66985b674c5df11ca466792902164c4e2George McCollister /* HMAC(key, msg) = HASH(key XOR opad, HASH(key XOR ipad, msg)) */
e07a94a66985b674c5df11ca466792902164c4e2George McCollister for (i = 0; i < HMAC_SHA1_BLOCKSIZE; i++) {
e07a94a66985b674c5df11ca466792902164c4e2George McCollister okey[i] = ikey[i] ^ 0x5c;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister ikey[i] ^= 0x36;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik if (!EVP_DigestInit_ex(ctx, EVP_sha1(), NULL)) {
e07a94a66985b674c5df11ca466792902164c4e2George McCollister ret = EIO;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister goto done;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestUpdate(ctx, (const unsigned char *)ikey, HMAC_SHA1_BLOCKSIZE);
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestUpdate(ctx, (const unsigned char *)in, in_len);
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestFinal_ex(ctx, hash, &res_len);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik if (!EVP_DigestInit_ex(ctx, EVP_sha1(), NULL)) {
e07a94a66985b674c5df11ca466792902164c4e2George McCollister ret = EIO;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister goto done;
e07a94a66985b674c5df11ca466792902164c4e2George McCollister }
e07a94a66985b674c5df11ca466792902164c4e2George McCollister
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestUpdate(ctx, (const unsigned char *)okey, HMAC_SHA1_BLOCKSIZE);
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestUpdate(ctx, (const unsigned char *)hash, SSS_SHA1_LENGTH);
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_DigestFinal_ex(ctx, out, &res_len);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister ret = EOK;
e07a94a66985b674c5df11ca466792902164c4e2George McCollisterdone:
8f1316a0c677f211eaaa1346e21a03446b8c4fb1Lukas Slebodnik EVP_MD_CTX_free(ctx);
e07a94a66985b674c5df11ca466792902164c4e2George McCollister return ret;
b35f20cd8ecdc8308a3201e55752fb0443ec6ae4Jan Cholasta}