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