crypto/hmac_sha256: add partial progress functions.
[ccan] / ccan / crypto / hmac_sha256 / hmac_sha256.c
1 /* MIT (BSD) license - see LICENSE file for details */
2 #include <ccan/crypto/hmac_sha256/hmac_sha256.h>
3 #include <string.h>
4
5 #define IPAD 0x3636363636363636ULL
6 #define OPAD 0x5C5C5C5C5C5C5C5CULL
7
8 #define BLOCK_U64S (HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t))
9
10 static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad)
11 {
12         size_t i;
13
14         for (i = 0; i < BLOCK_U64S; i++)
15                 block[i] ^= pad;
16 }
17
18 void hmac_sha256_init(struct hmac_sha256_ctx *ctx,
19                       const void *k, size_t ksize)
20 {
21         struct sha256 hashed_key;
22         /* We use k_opad as k_ipad temporarily. */
23         uint64_t *k_ipad = ctx->k_opad;
24
25         /* (keys longer than B bytes are first hashed using H) */
26         if (ksize > HMAC_SHA256_BLOCKSIZE) {
27                 sha256(&hashed_key, k, ksize);
28                 k = &hashed_key;
29                 ksize = sizeof(hashed_key);
30         }
31
32         /* From RFC2104:
33          *
34          * (1) append zeros to the end of K to create a B byte string
35          *  (e.g., if K is of length 20 bytes and B=64, then K will be
36          *   appended with 44 zero bytes 0x00)
37          */
38         memcpy(k_ipad, k, ksize);
39         memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize);
40
41         /*
42          * (2) XOR (bitwise exclusive-OR) the B byte string computed
43          * in step (1) with ipad
44          */
45         xor_block(k_ipad, IPAD);
46
47         /*
48          * We start (4) here, appending text later:
49          *
50          * (3) append the stream of data 'text' to the B byte string resulting
51          * from step (2)
52          * (4) apply H to the stream generated in step (3)
53          */
54         sha256_init(&ctx->sha);
55         sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE);
56
57         /*
58          * (5) XOR (bitwise exclusive-OR) the B byte string computed in
59          * step (1) with opad
60          */
61         xor_block(ctx->k_opad, IPAD^OPAD);
62 }
63
64 void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size)
65 {
66         /* This is the appending-text part of this:
67          *
68          * (3) append the stream of data 'text' to the B byte string resulting
69          * from step (2)
70          * (4) apply H to the stream generated in step (3)
71          */
72         sha256_update(&ctx->sha, p, size);
73 }
74
75 void hmac_sha256_done(struct hmac_sha256_ctx *ctx,
76                       struct hmac_sha256 *hmac)
77 {
78         /* (4) apply H to the stream generated in step (3) */
79         sha256_done(&ctx->sha, &hmac->sha);
80
81         /*
82          * (6) append the H result from step (4) to the B byte string
83          * resulting from step (5)
84          * (7) apply H to the stream generated in step (6) and output
85          * the result
86          */
87         sha256_init(&ctx->sha);
88         sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad));
89         sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha));
90         sha256_done(&ctx->sha, &hmac->sha);
91 }
92
93 #if 1
94 void hmac_sha256(struct hmac_sha256 *hmac,
95                  const void *k, size_t ksize,
96                  const void *d, size_t dsize)
97 {
98         struct hmac_sha256_ctx ctx;
99
100         hmac_sha256_init(&ctx, k, ksize);
101         hmac_sha256_update(&ctx, d, dsize);
102         hmac_sha256_done(&ctx, hmac);
103 }
104 #else
105 /* Direct mapping from MD5 example in RFC2104 */
106 void hmac_sha256(struct hmac_sha256 *hmac,
107                  const void *key, size_t key_len,
108                  const void *text, size_t text_len)
109 {
110         struct sha256_ctx context;
111         unsigned char k_ipad[65];    /* inner padding -
112                                       * key XORd with ipad
113                                       */
114         unsigned char k_opad[65];    /* outer padding -
115                                       * key XORd with opad
116                                       *//* start out by storing key in pads */
117         unsigned char tk[32];
118         int i;
119
120         /* if key is longer than 64 bytes reset it to key=MD5(key) */
121         if (key_len > 64) {
122
123                 struct sha256_ctx      tctx;
124
125                 sha256_init(&tctx);
126                 sha256_update(&tctx, key, key_len);
127                 sha256_done(&tctx, tk);
128
129                 key = tk;
130                 key_len = 32;
131         }
132         bzero( k_ipad, sizeof k_ipad);
133         bzero( k_opad, sizeof k_opad);
134         bcopy( key, k_ipad, key_len);
135         bcopy( key, k_opad, key_len);
136
137         /* XOR key with ipad and opad values */
138         for (i=0; i<64; i++) {
139                 k_ipad[i] ^= 0x36;
140                 k_opad[i] ^= 0x5c;
141         }
142         /*
143          * perform inner MD5
144          */
145         sha256_init(&context);                   /* init context for 1st
146                                               * pass */
147         sha256_update(&context, k_ipad, 64);      /* start with inner pad */
148         sha256_update(&context, text, text_len); /* then text of datagram */
149         sha256_done(&context, &hmac->sha);          /* finish up 1st pass */
150         /*
151          * perform outer MD5
152          */
153         sha256_init(&context);                   /* init context for 2nd
154                                               * pass */
155         sha256_update(&context, k_opad, 64);     /* start with outer pad */
156         sha256_update(&context, &hmac->sha, 32);     /* then results of 1st
157                                               * hash */
158         sha256_done(&context, &hmac->sha);          /* finish up 2nd pass */
159 }
160 #endif