0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz/*
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz * HMAC (RFC-2104) implementation.
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz *
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen * Copyright (c) 2011-2016 Florian Zeitz <florob@babelmonkeys.de>
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz *
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz * This software is released under the MIT license.
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz */
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz#include "lib.h"
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz#include "hmac.h"
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz#include "safe-memset.h"
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi#include "buffer.h"
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
d8361cc8576d9ede93a037f9b96f2a3f9b7e9054Timo Sirainenvoid hmac_init(struct hmac_context *_ctx, const unsigned char *key,
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz size_t key_len, const struct hash_method *meth)
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz{
d8361cc8576d9ede93a037f9b96f2a3f9b7e9054Timo Sirainen struct hmac_context_priv *ctx = &_ctx->u.priv;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz int i;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz unsigned char k_ipad[64];
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz unsigned char k_opad[64];
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz unsigned char hashedkey[meth->digest_size];
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz i_assert(meth->context_size <= HMAC_MAX_CONTEXT_SIZE);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz ctx->hash = meth;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz if (key_len > 64) {
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->init(ctx->ctx);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->loop(ctx->ctx, key, key_len);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->result(ctx->ctx, hashedkey);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz key = hashedkey;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz key_len = meth->digest_size;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz }
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz memcpy(k_ipad, key, key_len);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz memset(k_ipad + key_len, 0, 64 - key_len);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz memcpy(k_opad, k_ipad, 64);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz for (i = 0; i < 64; i++) {
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz k_ipad[i] ^= 0x36;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz k_opad[i] ^= 0x5c;
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz }
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->init(ctx->ctx);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->loop(ctx->ctx, k_ipad, 64);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->init(ctx->ctxo);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz meth->loop(ctx->ctxo, k_opad, 64);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz safe_memset(k_ipad, 0, 64);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz safe_memset(k_opad, 0, 64);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz}
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
d8361cc8576d9ede93a037f9b96f2a3f9b7e9054Timo Sirainenvoid hmac_final(struct hmac_context *_ctx, unsigned char *digest)
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz{
d8361cc8576d9ede93a037f9b96f2a3f9b7e9054Timo Sirainen struct hmac_context_priv *ctx = &_ctx->u.priv;
d8361cc8576d9ede93a037f9b96f2a3f9b7e9054Timo Sirainen
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz ctx->hash->result(ctx->ctx, digest);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz ctx->hash->loop(ctx->ctxo, digest, ctx->hash->digest_size);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz ctx->hash->result(ctx->ctxo, digest);
0a3769a4ef3afbbbd05df38f43ec7382fd65a2b6Florian Zeitz}
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomibuffer_t *t_hmac_data(const struct hash_method *meth,
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi const unsigned char *key, size_t key_len,
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi const void *data, size_t data_len)
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi{
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi struct hmac_context ctx;
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi i_assert(meth != NULL);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi i_assert(key != NULL && key_len > 0);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi i_assert(data != NULL || data_len == 0);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buffer_t *res = t_buffer_create(meth->digest_size);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi hmac_init(&ctx, key, key_len, meth);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi if (data_len > 0)
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi hmac_update(&ctx, data, data_len);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi unsigned char *buf = buffer_get_space_unsafe(res, 0, meth->digest_size);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi hmac_final(&ctx, buf);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi return res;
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi}
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomibuffer_t *t_hmac_buffer(const struct hash_method *meth,
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi const unsigned char *key, size_t key_len,
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi const buffer_t *data)
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi{
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi return t_hmac_data(meth, key, key_len, data->data, data->used);
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi}
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomibuffer_t *t_hmac_str(const struct hash_method *meth,
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi const unsigned char *key, size_t key_len,
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi const char *data)
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi{
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi return t_hmac_data(meth, key, key_len, data, strlen(data));
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi}
ffe51a1969f24d88bbfacb3ba2ec83d5b99ae774Aki Tuomi