1 /*
2 * cifra - embedded cryptography library
3 * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
4 *
5 * To the extent possible under law, the author(s) have dedicated all
6 * copyright and related and neighboring rights to this software to the
7 * public domain worldwide. This software is distributed without any
8 * warranty.
9 *
10 * You should have received a copy of the CC0 Public Domain Dedication
11 * along with this software. If not, see
12 * <http://creativecommons.org/publicdomain/zero/1.0/>.
13 */
14
15 #include "hmac.h"
16 #include "chash.h"
17 #include "bitops.h"
18 #include "handy.h"
19 #include "tassert.h"
20
21 #include <string.h>
22
cf_hmac_init(cf_hmac_ctx * ctx,const cf_chash * hash,const uint8_t * key,size_t nkey)23 void cf_hmac_init(cf_hmac_ctx *ctx,
24 const cf_chash *hash,
25 const uint8_t *key, size_t nkey)
26 {
27 assert(ctx);
28 assert(hash);
29
30 mem_clean(ctx, sizeof *ctx);
31 ctx->hash = hash;
32
33 /* Prepare key: */
34 uint8_t k[CF_CHASH_MAXBLK];
35
36 /* Shorten long keys. */
37 if (nkey > hash->blocksz)
38 {
39 /* Standard doesn't cover case where blocksz < hashsz.
40 * FIPS186-1 seems to want to append a negative number of zero bytes.
41 * In any case, we only have a k buffer of CF_CHASH_MAXBLK! */
42 assert(hash->hashsz <= hash->blocksz);
43
44 cf_hash(hash, key, nkey, k);
45 key = k;
46 nkey = hash->hashsz;
47 }
48
49 /* Right zero-pad short keys. */
50 if (k != key)
51 memcpy(k, key, nkey);
52 if (hash->blocksz > nkey)
53 memset(k + nkey, 0, hash->blocksz - nkey);
54
55 /* Start inner hash computation */
56 uint8_t blk[CF_CHASH_MAXBLK];
57
58 xor_b8(blk, k, 0x36, hash->blocksz);
59 hash->init(&ctx->inner);
60 hash->update(&ctx->inner, blk, hash->blocksz);
61
62 /* And outer. */
63 xor_b8(blk, k, 0x5c, hash->blocksz);
64 hash->init(&ctx->outer);
65 hash->update(&ctx->outer, blk, hash->blocksz);
66
67 mem_clean(blk, sizeof blk);
68 mem_clean(k, sizeof k);
69 }
70
cf_hmac_update(cf_hmac_ctx * ctx,const void * data,size_t ndata)71 void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata)
72 {
73 assert(ctx && ctx->hash);
74
75 ctx->hash->update(&ctx->inner, data, ndata);
76 }
77
cf_hmac_finish(cf_hmac_ctx * ctx,uint8_t * out)78 void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out)
79 {
80 assert(ctx && ctx->hash);
81 assert(out);
82
83 uint8_t innerh[CF_MAXHASH];
84 ctx->hash->digest(&ctx->inner, innerh);
85
86 ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz);
87 ctx->hash->digest(&ctx->outer, out);
88
89 mem_clean(ctx, sizeof *ctx);
90 }
91
cf_hmac(const uint8_t * key,size_t nkey,const uint8_t * msg,size_t nmsg,uint8_t * out,const cf_chash * hash)92 void cf_hmac(const uint8_t *key, size_t nkey,
93 const uint8_t *msg, size_t nmsg,
94 uint8_t *out,
95 const cf_chash *hash)
96 {
97 cf_hmac_ctx ctx;
98
99 assert(out);
100 assert(hash);
101
102 cf_hmac_init(&ctx, hash, key, nkey);
103 cf_hmac_update(&ctx, msg, nmsg);
104 cf_hmac_finish(&ctx, out);
105 }
106
107