]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservcrypto.c
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / chanserv / chanservcrypto.c
1 #include <stdio.h>
2 #include <strings.h>
3
4 #include "chanserv.h"
5 #include "../core/error.h"
6 #include "../core/config.h"
7 #include "../lib/prng.h"
8 #include "../lib/sha1.h"
9 #include "../lib/sha2.h"
10 #include "../lib/md5.h"
11 #include "../lib/hmac.h"
12
13 static prngctx rng;
14 static sstring *secret, *codesecret, *ticketsecret;
15
16 static sstring *combinesecret(char *str) {
17 SHA256_CTX ctx;
18 unsigned char digest[32];
19 char hexbuf[sizeof(digest) * 2 + 1];
20
21 SHA256_Init(&ctx);
22 SHA256_Update(&ctx, (unsigned char *)secret->content, secret->length);
23 SHA256_Update(&ctx, (unsigned char *)":", 1);
24 SHA256_Update(&ctx, (unsigned char *)str, strlen(str));
25 SHA256_Final(digest, &ctx);
26
27 SHA256_Init(&ctx);
28 SHA256_Update(&ctx, digest, sizeof(digest));
29 SHA256_Final(digest, &ctx);
30 hmac_printhex(digest, hexbuf, sizeof(digest));
31
32 return getsstring(hexbuf, strlen(hexbuf));
33 }
34
35 void chanservcryptoinit(void) {
36 int ret;
37
38 FILE *e = fopen(ENTROPYSOURCE, "rb");
39 if(!e) {
40 Error("chanserv",ERR_STOP,"Unable to open entropy source.");
41 /* shouldn't be running now... */
42 }
43
44 ret = fread(rng.randrsl, 1, sizeof(rng.randrsl), e);
45 fclose(e);
46
47 if(ret != sizeof(rng.randrsl)) {
48 Error("chanserv",ERR_STOP,"Unable to read entropy.");
49 /* shouldn't be running now... */
50 }
51
52 prnginit(&rng, 1);
53
54 secret=getcopyconfigitem("chanserv","secret","",128);
55 if(!secret || !secret->content || !secret->content[0]) {
56 unsigned char buf[32];
57 char hexbuf[sizeof(buf) * 2 + 1];
58 freesstring(secret);
59 Error("chanserv",ERR_WARNING,"Shared secret not set, generating a random string...");
60
61 cs_getrandbytes(buf, 32);
62 hmac_printhex(buf, hexbuf, sizeof(buf));
63 secret=getsstring(hexbuf, strlen(hexbuf));
64 }
65 codesecret=combinesecret("codegenerator");
66
67 ticketsecret=getcopyconfigitem("chanserv","ticketsecret","",256);
68 if(!ticketsecret || !ticketsecret->content[0]) {
69 Error("chanserv",ERR_WARNING,"Ticket secret not set, ticketauth disabled.");
70 freesstring(ticketsecret);
71 ticketsecret = NULL;
72 }
73 }
74
75
76 void chanservcryptofree(void) {
77 freesstring(secret);
78 freesstring(codesecret);
79 freesstring(ticketsecret);
80 }
81
82 ub4 cs_getrandint(void) {
83 return prng(&rng);
84 }
85
86 void cs_getrandbytes(unsigned char *buf, size_t bytes) {
87 for(;bytes>0;bytes-=4,buf+=4) {
88 ub4 b = cs_getrandint();
89 memcpy(buf, &b, 4);
90 }
91 }
92
93 const char *cs_cralgorithmlist(void) {
94 return "HMAC-MD5 HMAC-SHA-1 HMAC-SHA-256 LEGACY-MD5";
95 }
96
97 int crsha1(char *username, const char *password, const char *challenge, const char *response) {
98 char buf[1024];
99
100 SHA1_CTX ctx;
101 unsigned char digest[20];
102 char hexbuf[sizeof(digest) * 2 + 1];
103 hmacsha1 hmac;
104
105 /* not sure how this helps but the RFC says to do it... */
106 SHA1Init(&ctx);
107 SHA1Update(&ctx, (unsigned char *)password, strlen(password));
108 SHA1Final(digest, &ctx);
109
110 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
111
112 SHA1Init(&ctx);
113 SHA1Update(&ctx, (unsigned char *)buf, strlen(buf));
114 SHA1Final(digest, &ctx);
115
116 hmacsha1_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
117 hmacsha1_update(&hmac, (unsigned char *)challenge, strlen(challenge));
118 hmacsha1_final(&hmac, digest);
119
120 hmac_printhex(digest, hexbuf, sizeof(digest));
121
122 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
123 return 1;
124
125 return 0;
126 }
127
128 int crsha256(char *username, const char *password, const char *challenge, const char *response) {
129 char buf[1024];
130
131 SHA256_CTX ctx;
132 unsigned char digest[32];
133 char hexbuf[sizeof(digest) * 2 + 1];
134 hmacsha256 hmac;
135
136 /* not sure how this helps but the RFC says to do it... */
137 SHA256_Init(&ctx);
138 SHA256_Update(&ctx, (unsigned char *)password, strlen(password));
139 SHA256_Final(digest, &ctx);
140
141 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
142
143 SHA256_Init(&ctx);
144 SHA256_Update(&ctx, (unsigned char *)buf, strlen(buf));
145 SHA256_Final(digest, &ctx);
146
147 hmacsha256_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
148 hmacsha256_update(&hmac, (unsigned char *)challenge, strlen(challenge));
149 hmacsha256_final(&hmac, digest);
150
151 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
152 return 1;
153
154 return 0;
155 }
156
157 int crmd5(char *username, const char *password, const char *challenge, const char *response) {
158 char buf[1024];
159
160 MD5Context ctx;
161 unsigned char digest[16];
162 char hexbuf[sizeof(digest) * 2 + 1];
163 hmacmd5 hmac;
164
165 /* not sure how this helps but the RFC says to do it... */
166 MD5Init(&ctx);
167 MD5Update(&ctx, (unsigned char *)password, strlen(password));
168 MD5Final(digest, &ctx);
169
170 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
171
172 MD5Init(&ctx);
173 MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
174 MD5Final(digest, &ctx);
175
176 hmacmd5_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
177 hmacmd5_update(&hmac, (unsigned char *)challenge, strlen(challenge));
178 hmacmd5_final(&hmac, digest);
179
180 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
181 return 1;
182
183 return 0;
184 }
185
186 int crlegacymd5(char *username, const char *password, const char *challenge, const char *response) {
187 MD5Context ctx;
188 unsigned char digest[16];
189 char hexbuf[sizeof(digest) * 2 + 1];
190
191 MD5Init(&ctx);
192 MD5Update(&ctx, (unsigned char *)password, strlen(password));
193 MD5Update(&ctx, (unsigned char *)" ", 1);
194 MD5Update(&ctx, (unsigned char *)challenge, strlen(challenge));
195 MD5Final(digest, &ctx);
196
197 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
198 return 1;
199
200 return 0;
201 }
202
203 CRAlgorithm cs_cralgorithm(const char *algorithm) {
204 if(!strcasecmp(algorithm, "hmac-sha-1"))
205 return crsha1;
206
207 if(!strcasecmp(algorithm, "hmac-sha-256"))
208 return crsha256;
209
210 if(!strcasecmp(algorithm, "hmac-md5"))
211 return crmd5;
212
213 if(!strcasecmp(algorithm, "legacy-md5"))
214 return crlegacymd5;
215
216 return 0;
217 }
218
219 char *cs_calcchallenge(const unsigned char *entropy) {
220 unsigned char buf[20];
221 static char hexbuf[sizeof(buf) * 2 + 1];
222 SHA1_CTX ctx;
223
224 SHA1Init(&ctx);
225 /* we can maybe add a salt here in the future */
226 SHA1Update(&ctx, entropy, ENTROPYLEN);
227 SHA1Final(buf, &ctx);
228
229 hmac_printhex(buf, hexbuf, 16);
230
231 return hexbuf;
232 }
233
234 int cs_checkhashpass(const char *username, const char *password, const char *junk, const char *hash) {
235 MD5Context ctx;
236 unsigned char digest[16];
237 char hexbuf[sizeof(digest) * 2 + 1], buf[512];
238
239 snprintf(buf, sizeof(buf), "%s %s%s%s", username, password, junk?" ":"", junk?junk:"");
240
241 MD5Init(&ctx);
242 MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
243 MD5Final(digest, &ctx);
244
245 if(hmac_strcmp(hash, hmac_printhex(digest, hexbuf, sizeof(digest))))
246 return 0;
247
248 return 1;
249 }
250
251 char *csc_generateresetcode(time_t lockuntil, char *username) {
252 unsigned char digest[32];
253 static char hexbuf[sizeof(digest) * 2 + 1];
254 hmacsha256 hmac;
255 SHA256_CTX ctx;
256 char buf[1024];
257
258 snprintf(buf, sizeof(buf), "%s:%lu", username, lockuntil);
259
260 SHA256_Init(&ctx);
261 SHA256_Update(&ctx, (unsigned char *)buf, strlen(buf));
262 SHA256_Final(digest, &ctx);
263
264 hmac_printhex(digest, hexbuf, sizeof(digest));
265
266 hmacsha256_init(&hmac, (unsigned char *)codesecret->content, codesecret->length);
267 hmacsha256_update(&hmac, (unsigned char *)hexbuf, strlen(hexbuf));
268 hmacsha256_final(&hmac, digest);
269
270 hmac_printhex(digest, hexbuf, sizeof(digest));
271
272 return hexbuf;
273 }
274
275 int csc_verifyqticket(char *data, char *digest) {
276 hmacsha256 hmac;
277 unsigned char digestbuf[32];
278 char hexbuf[sizeof(digestbuf) * 2 + 1];
279
280 if(!ticketsecret)
281 return -1;
282
283 hmacsha256_init(&hmac, (unsigned char *)ticketsecret->content, ticketsecret->length);
284 hmacsha256_update(&hmac, (unsigned char *)data, strlen(data));
285 hmacsha256_final(&hmac, digestbuf);
286
287 hmac_printhex(digestbuf, hexbuf, sizeof(digestbuf));
288
289 if(!hmac_strcmp(hexbuf, digest))
290 return 0;
291
292 return 1;
293 }