d252295521fe270ea72cfb0bfc21c75f66324c39
[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 (64 / 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 #if 1
19 void hmac_sha256(struct hmac_sha256 *hmac,
20                  const void *k, size_t ksize,
21                  const void *d, size_t dsize)
22 {
23         struct sha256_ctx shactx;
24         uint64_t block[BLOCK_U64S];
25         struct sha256 hash, hashed_key;
26
27         /* (keys longer than B bytes are first hashed using H) */
28         if (ksize > sizeof(block)) {
29                 sha256(&hashed_key, k, ksize);
30                 k = &hashed_key;
31                 ksize = sizeof(hashed_key);
32         }
33
34         /* From RFC2104:
35          *
36          * (1) append zeros to the end of K to create a B byte string
37          *  (e.g., if K is of length 20 bytes and B=64, then K will be
38          *   appended with 44 zero bytes 0x00)
39          */
40         memcpy(block, k, ksize);
41         memset((char *)block + ksize, 0, sizeof(block) - ksize);
42
43         /*
44          * (2) XOR (bitwise exclusive-OR) the B byte string computed
45          * in step (1) with ipad
46          */
47         xor_block(block, IPAD);
48
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(&shactx);
55         sha256_update(&shactx, block, sizeof(block));
56         sha256_update(&shactx, d, dsize);
57         sha256_done(&shactx, &hash);
58
59         /*
60          * (5) XOR (bitwise exclusive-OR) the B byte string computed in
61          * step (1) with opad
62          */
63         xor_block(block, IPAD^OPAD);
64
65         /*
66          * (6) append the H result from step (4) to the B byte string
67          * resulting from step (5)
68          * (7) apply H to the stream generated in step (6) and output
69          * the result
70          */
71         sha256_init(&shactx);
72         sha256_update(&shactx, block, sizeof(block));
73         sha256_update(&shactx, &hash, sizeof(hash));
74         sha256_done(&shactx, &hmac->sha);
75 }
76 #else
77 /* Direct mapping from MD5 example in RFC2104 */
78 void hmac_sha256(struct hmac_sha256 *hmac,
79                  const void *key, size_t key_len,
80                  const void *text, size_t text_len)
81 {
82         struct sha256_ctx context;
83         unsigned char k_ipad[65];    /* inner padding -
84                                       * key XORd with ipad
85                                       */
86         unsigned char k_opad[65];    /* outer padding -
87                                       * key XORd with opad
88                                       *//* start out by storing key in pads */
89         unsigned char tk[32];
90         int i;
91
92         /* if key is longer than 64 bytes reset it to key=MD5(key) */
93         if (key_len > 64) {
94
95                 struct sha256_ctx      tctx;
96
97                 sha256_init(&tctx);
98                 sha256_update(&tctx, key, key_len);
99                 sha256_done(&tctx, tk);
100
101                 key = tk;
102                 key_len = 32;
103         }
104         bzero( k_ipad, sizeof k_ipad);
105         bzero( k_opad, sizeof k_opad);
106         bcopy( key, k_ipad, key_len);
107         bcopy( key, k_opad, key_len);
108
109         /* XOR key with ipad and opad values */
110         for (i=0; i<64; i++) {
111                 k_ipad[i] ^= 0x36;
112                 k_opad[i] ^= 0x5c;
113         }
114         /*
115          * perform inner MD5
116          */
117         sha256_init(&context);                   /* init context for 1st
118                                               * pass */
119         sha256_update(&context, k_ipad, 64);      /* start with inner pad */
120         sha256_update(&context, text, text_len); /* then text of datagram */
121         sha256_done(&context, &hmac->sha);          /* finish up 1st pass */
122         /*
123          * perform outer MD5
124          */
125         sha256_init(&context);                   /* init context for 2nd
126                                               * pass */
127         sha256_update(&context, k_opad, 64);     /* start with outer pad */
128         sha256_update(&context, &hmac->sha, 32);     /* then results of 1st
129                                               * hash */
130         sha256_done(&context, &hmac->sha);          /* finish up 2nd pass */
131 }
132 #endif