]> git.ozlabs.org Git - ccan/blob - ccan/crypto/hmac_sha256/hmac_sha256.c
base64: fix for unsigned chars (e.g. ARM).
[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         if (ksize != 0)
39                 memcpy(k_ipad, k, ksize);
40         memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize);
41
42         /*
43          * (2) XOR (bitwise exclusive-OR) the B byte string computed
44          * in step (1) with ipad
45          */
46         xor_block(k_ipad, IPAD);
47
48         /*
49          * We start (4) here, appending text later:
50          *
51          * (3) append the stream of data 'text' to the B byte string resulting
52          * from step (2)
53          * (4) apply H to the stream generated in step (3)
54          */
55         sha256_init(&ctx->sha);
56         sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE);
57
58         /*
59          * (5) XOR (bitwise exclusive-OR) the B byte string computed in
60          * step (1) with opad
61          */
62         xor_block(ctx->k_opad, IPAD^OPAD);
63 }
64
65 void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size)
66 {
67         /* This is the appending-text part of this:
68          *
69          * (3) append the stream of data 'text' to the B byte string resulting
70          * from step (2)
71          * (4) apply H to the stream generated in step (3)
72          */
73         sha256_update(&ctx->sha, p, size);
74 }
75
76 void hmac_sha256_done(struct hmac_sha256_ctx *ctx,
77                       struct hmac_sha256 *hmac)
78 {
79         /* (4) apply H to the stream generated in step (3) */
80         sha256_done(&ctx->sha, &hmac->sha);
81
82         /*
83          * (6) append the H result from step (4) to the B byte string
84          * resulting from step (5)
85          * (7) apply H to the stream generated in step (6) and output
86          * the result
87          */
88         sha256_init(&ctx->sha);
89         sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad));
90         sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha));
91         sha256_done(&ctx->sha, &hmac->sha);
92 }
93
94 #if 1
95 void hmac_sha256(struct hmac_sha256 *hmac,
96                  const void *k, size_t ksize,
97                  const void *d, size_t dsize)
98 {
99         struct hmac_sha256_ctx ctx;
100
101         hmac_sha256_init(&ctx, k, ksize);
102         hmac_sha256_update(&ctx, d, dsize);
103         hmac_sha256_done(&ctx, hmac);
104 }
105 #else
106 /* Direct mapping from MD5 example in RFC2104 */
107 void hmac_sha256(struct hmac_sha256 *hmac,
108                  const void *key, size_t key_len,
109                  const void *text, size_t text_len)
110 {
111         struct sha256_ctx context;
112         unsigned char k_ipad[65];    /* inner padding -
113                                       * key XORd with ipad
114                                       */
115         unsigned char k_opad[65];    /* outer padding -
116                                       * key XORd with opad
117                                       *//* start out by storing key in pads */
118         unsigned char tk[32];
119         int i;
120
121         /* if key is longer than 64 bytes reset it to key=MD5(key) */
122         if (key_len > 64) {
123
124                 struct sha256_ctx      tctx;
125
126                 sha256_init(&tctx);
127                 sha256_update(&tctx, key, key_len);
128                 sha256_done(&tctx, tk);
129
130                 key = tk;
131                 key_len = 32;
132         }
133         bzero( k_ipad, sizeof k_ipad);
134         bzero( k_opad, sizeof k_opad);
135         bcopy( key, k_ipad, key_len);
136         bcopy( key, k_opad, key_len);
137
138         /* XOR key with ipad and opad values */
139         for (i=0; i<64; i++) {
140                 k_ipad[i] ^= 0x36;
141                 k_opad[i] ^= 0x5c;
142         }
143         /*
144          * perform inner MD5
145          */
146         sha256_init(&context);                   /* init context for 1st
147                                               * pass */
148         sha256_update(&context, k_ipad, 64);      /* start with inner pad */
149         sha256_update(&context, text, text_len); /* then text of datagram */
150         sha256_done(&context, &hmac->sha);          /* finish up 1st pass */
151         /*
152          * perform outer MD5
153          */
154         sha256_init(&context);                   /* init context for 2nd
155                                               * pass */
156         sha256_update(&context, k_opad, 64);     /* start with outer pad */
157         sha256_update(&context, &hmac->sha, 32);     /* then results of 1st
158                                               * hash */
159         sha256_done(&context, &hmac->sha);          /* finish up 2nd pass */
160 }
161 #endif