]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservcrypto.c
Lua version now excludes "Lua engine", at least for MODULEVERSION.
[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;
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
68
69 void chanservcryptofree(void) {
70 freesstring(secret);
71 freesstring(codesecret);
72 }
73
74 ub4 cs_getrandint(void) {
75 return prng(&rng);
76 }
77
78 void cs_getrandbytes(unsigned char *buf, size_t bytes) {
79 for(;bytes>0;bytes-=4,buf+=4) {
80 ub4 b = cs_getrandint();
81 memcpy(buf, &b, 4);
82 }
83 }
84
85 const char *cs_cralgorithmlist(void) {
86 return "HMAC-MD5 HMAC-SHA-1 HMAC-SHA-256 LEGACY-MD5";
87 }
88
89 int crsha1(char *username, const char *password, const char *challenge, const char *response) {
90 char buf[1024];
91
92 SHA1_CTX ctx;
93 unsigned char digest[20];
94 char hexbuf[sizeof(digest) * 2 + 1];
95 hmacsha1 hmac;
96
97 /* not sure how this helps but the RFC says to do it... */
98 SHA1Init(&ctx);
99 SHA1Update(&ctx, (unsigned char *)password, strlen(password));
100 SHA1Final(digest, &ctx);
101
102 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
103
104 SHA1Init(&ctx);
105 SHA1Update(&ctx, (unsigned char *)buf, strlen(buf));
106 SHA1Final(digest, &ctx);
107
108 hmacsha1_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
109 hmacsha1_update(&hmac, (unsigned char *)challenge, strlen(challenge));
110 hmacsha1_final(&hmac, digest);
111
112 hmac_printhex(digest, hexbuf, sizeof(digest));
113
114 if(!strcasecmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
115 return 1;
116
117 return 0;
118 }
119
120 int crsha256(char *username, const char *password, const char *challenge, const char *response) {
121 char buf[1024];
122
123 SHA256_CTX ctx;
124 unsigned char digest[32];
125 char hexbuf[sizeof(digest) * 2 + 1];
126 hmacsha256 hmac;
127
128 /* not sure how this helps but the RFC says to do it... */
129 SHA256_Init(&ctx);
130 SHA256_Update(&ctx, (unsigned char *)password, strlen(password));
131 SHA256_Final(digest, &ctx);
132
133 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
134
135 SHA256_Init(&ctx);
136 SHA256_Update(&ctx, (unsigned char *)buf, strlen(buf));
137 SHA256_Final(digest, &ctx);
138
139 hmacsha256_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
140 hmacsha256_update(&hmac, (unsigned char *)challenge, strlen(challenge));
141 hmacsha256_final(&hmac, digest);
142
143 if(!strcasecmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
144 return 1;
145
146 return 0;
147 }
148
149 int crmd5(char *username, const char *password, const char *challenge, const char *response) {
150 char buf[1024];
151
152 MD5Context ctx;
153 unsigned char digest[16];
154 char hexbuf[sizeof(digest) * 2 + 1];
155 hmacmd5 hmac;
156
157 /* not sure how this helps but the RFC says to do it... */
158 MD5Init(&ctx);
159 MD5Update(&ctx, (unsigned char *)password, strlen(password));
160 MD5Final(digest, &ctx);
161
162 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
163
164 MD5Init(&ctx);
165 MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
166 MD5Final(digest, &ctx);
167
168 hmacmd5_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
169 hmacmd5_update(&hmac, (unsigned char *)challenge, strlen(challenge));
170 hmacmd5_final(&hmac, digest);
171
172 if(!strcasecmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
173 return 1;
174
175 return 0;
176 }
177
178 int crlegacymd5(char *username, const char *password, const char *challenge, const char *response) {
179 MD5Context ctx;
180 unsigned char digest[16];
181 char hexbuf[sizeof(digest) * 2 + 1];
182
183 MD5Init(&ctx);
184 MD5Update(&ctx, (unsigned char *)password, strlen(password));
185 MD5Update(&ctx, (unsigned char *)" ", 1);
186 MD5Update(&ctx, (unsigned char *)challenge, strlen(challenge));
187 MD5Final(digest, &ctx);
188
189 if(!strcasecmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
190 return 1;
191
192 return 0;
193 }
194
195 CRAlgorithm cs_cralgorithm(const char *algorithm) {
196 if(!strcasecmp(algorithm, "hmac-sha-1"))
197 return crsha1;
198
199 if(!strcasecmp(algorithm, "hmac-sha-256"))
200 return crsha256;
201
202 if(!strcasecmp(algorithm, "hmac-md5"))
203 return crmd5;
204
205 if(!strcasecmp(algorithm, "legacy-md5"))
206 return crlegacymd5;
207
208 return 0;
209 }
210
211 char *cs_calcchallenge(const unsigned char *entropy) {
212 unsigned char buf[20];
213 static char hexbuf[sizeof(buf) * 2 + 1];
214 SHA1_CTX ctx;
215
216 SHA1Init(&ctx);
217 /* we can maybe add a salt here in the future */
218 SHA1Update(&ctx, entropy, ENTROPYLEN);
219 SHA1Final(buf, &ctx);
220
221 hmac_printhex(buf, hexbuf, 16);
222
223 return hexbuf;
224 }
225
226 int cs_checkhashpass(const char *username, const char *password, const char *junk, const char *hash) {
227 MD5Context ctx;
228 unsigned char digest[16];
229 char hexbuf[sizeof(digest) * 2 + 1], buf[512];
230
231 snprintf(buf, sizeof(buf), "%s %s%s%s", username, password, junk?" ":"", junk?junk:"");
232
233 MD5Init(&ctx);
234 MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
235 MD5Final(digest, &ctx);
236
237 if(strcasecmp(hash, hmac_printhex(digest, hexbuf, sizeof(digest))))
238 return 0;
239
240 return 1;
241 }
242
243 char *csc_generateresetcode(time_t lockuntil, char *username) {
244 unsigned char digest[32];
245 static char hexbuf[sizeof(digest) * 2 + 1];
246 hmacsha256 hmac;
247 SHA256_CTX ctx;
248 char buf[1024];
249
250 snprintf(buf, sizeof(buf), "%s:%lu", username, lockuntil);
251
252 SHA256_Init(&ctx);
253 SHA256_Update(&ctx, (unsigned char *)buf, strlen(buf));
254 SHA256_Final(digest, &ctx);
255
256 hmac_printhex(digest, hexbuf, sizeof(digest));
257
258 hmacsha256_init(&hmac, (unsigned char *)codesecret->content, codesecret->length);
259 hmacsha256_update(&hmac, (unsigned char *)hexbuf, strlen(hexbuf));
260 hmacsha256_final(&hmac, digest);
261
262 hmac_printhex(digest, hexbuf, sizeof(digest));
263
264 return hexbuf;
265 }