]> jfr.im git - irc/quakenet/newserv.git/blob - lib/hmac.c
Fix timing attacks in HMAC functions.
[irc/quakenet/newserv.git] / lib / hmac.c
1 #include "hmac.h"
2 #include <string.h>
3
4 void hmacsha256_init(hmacsha256 *c, unsigned char *key, int keylen) {
5 unsigned char realkey[64], outerkey[64], innerkey[64];
6 SHA256_CTX keyc;
7 int i;
8
9 memset(realkey, 0, sizeof(realkey));
10 if(keylen > 64) {
11 SHA256_Init(&keyc);
12 SHA256_Update(&keyc, key, keylen);
13 SHA256_Final(realkey, &keyc);
14 keylen = 32;
15 } else {
16 memcpy(realkey, key, keylen);
17 }
18
19 /* abusing the cache here, if we do sha256 in between that'll erase it */
20 for(i=0;i<64;i++) {
21 int r = realkey[i];
22 innerkey[i] = r ^ 0x36;
23 outerkey[i] = r ^ 0x5c;
24 }
25
26 SHA256_Init(&c->outer);
27 SHA256_Init(&c->inner);
28 SHA256_Update(&c->outer, outerkey, 64);
29 SHA256_Update(&c->inner, innerkey, 64);
30 }
31
32 void hmacsha256_update(hmacsha256 *c, unsigned char *message, int messagelen) {
33 SHA256_Update(&c->inner, message, messagelen);
34 }
35
36 void hmacsha256_final(hmacsha256 *c, unsigned char *digest) {
37 SHA256_Final(digest, &c->inner);
38 SHA256_Update(&c->outer, digest, 32);
39 SHA256_Final(digest, &c->outer);
40 }
41
42 void hmacsha1_init(hmacsha1 *c, unsigned char *key, int keylen) {
43 unsigned char realkey[64], outerkey[64], innerkey[64];
44 SHA1_CTX keyc;
45 int i;
46
47 memset(realkey, 0, sizeof(realkey));
48 if(keylen > 64) {
49 SHA1Init(&keyc);
50 SHA1Update(&keyc, key, keylen);
51 SHA1Final(realkey, &keyc);
52 keylen = 20;
53 } else {
54 memcpy(realkey, key, keylen);
55 }
56
57 /* abusing the cache here, if we do sha1 in between that'll erase it */
58 for(i=0;i<64;i++) {
59 int r = realkey[i];
60 innerkey[i] = r ^ 0x36;
61 outerkey[i] = r ^ 0x5c;
62 }
63
64 SHA1Init(&c->outer);
65 SHA1Init(&c->inner);
66 SHA1Update(&c->outer, outerkey, 64);
67 SHA1Update(&c->inner, innerkey, 64);
68 }
69
70 void hmacsha1_update(hmacsha1 *c, unsigned char *message, int messagelen) {
71 SHA1Update(&c->inner, message, messagelen);
72 }
73
74 void hmacsha1_final(hmacsha1 *c, unsigned char *digest) {
75 SHA1Final(digest, &c->inner);
76 SHA1Update(&c->outer, digest, 20);
77 SHA1Final(digest, &c->outer);
78 }
79
80 void hmacmd5_init(hmacmd5 *c, unsigned char *key, int keylen) {
81 unsigned char realkey[64], outerkey[64], innerkey[64];
82 MD5Context keyc;
83 int i;
84
85 memset(realkey, 0, sizeof(realkey));
86 if(keylen > 64) {
87 MD5Init(&keyc);
88 MD5Update(&keyc, key, keylen);
89 MD5Final(realkey, &keyc);
90 keylen = 16;
91 } else {
92 memcpy(realkey, key, keylen);
93 }
94
95 /* abusing the cache here, if we do sha1 in between that'll erase it */
96 for(i=0;i<64;i++) {
97 int r = realkey[i];
98 innerkey[i] = r ^ 0x36;
99 outerkey[i] = r ^ 0x5c;
100 }
101
102 MD5Init(&c->outer);
103 MD5Init(&c->inner);
104 MD5Update(&c->outer, outerkey, 64);
105 MD5Update(&c->inner, innerkey, 64);
106 }
107
108 void hmacmd5_update(hmacmd5 *c, unsigned char *message, int messagelen) {
109 MD5Update(&c->inner, message, messagelen);
110 }
111
112 void hmacmd5_final(hmacmd5 *c, unsigned char *digest) {
113 MD5Final(digest, &c->inner);
114 MD5Update(&c->outer, digest, 16);
115 MD5Final(digest, &c->outer);
116 }
117
118 static const char *hexdigits = "0123456789abcdef";
119
120 char *hmac_printhex(unsigned char *data, char *out, size_t len) {
121 size_t i;
122 unsigned char *o = (unsigned char *)out;
123
124 for(i=0;i<len;i++) {
125 *o++ = hexdigits[(*data & 0xf0) >> 4];
126 *o++ = hexdigits[*data & 0x0f];
127 data++;
128 }
129
130 *o = '\0';
131 return out;
132 }
133
134 int hmac_strcmp(char *a, char *b) {
135 int result = 1;
136
137 if(!a || !b)
138 return 1;
139
140 if(strlen(a) != strlen(b))
141 return 1;
142
143 while(*a)
144 result&=(tolower(*a++) == tolower(*b++));
145
146 return !result;
147 }
148