PennMUSH Community

root/1.8.3/trunk/src/funcrypt.c

Revision 1167, 8.0 kB (checked in by shawnw, 9 months ago)

Merge devel into trunk for p6 release

Line 
1 /**
2  * \file funcrypt.c
3  *
4  * \brief Functions for cryptographic stuff in softcode
5  *
6  *
7  */
8 #include "copyrite.h"
9
10 #include "config.h"
11 #include <time.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include "conf.h"
15 #include "case.h"
16 #include "externs.h"
17 #include "version.h"
18 #include "extchat.h"
19 #include "htab.h"
20 #include "flags.h"
21 #include "dbdefs.h"
22 #include "parse.h"
23 #include "function.h"
24 #include "command.h"
25 #include "game.h"
26 #include "attrib.h"
27 #include "ansi.h"
28 #include "match.h"
29 #ifdef HAS_OPENSSL
30 #include <openssl/sha.h>
31 #include <openssl/evp.h>
32 #include <openssl/bio.h>
33 #else
34 #include "shs.h"
35 #endif
36 #include "confmagic.h"
37
38
39 static char *crunch_code(char *code);
40 static char *crypt_code(char *code, char *text, int type);
41 static void safe_sha0(const char *text, size_t len, char *buff, char **bp);
42 static void safe_hexchar(unsigned char c, char *buff, char **bp);
43
44 static bool
45 encode_base64(const char *input, int len, char *buff, char **bp)
46 {
47 #ifdef HAVE_SSL
48   BIO *bio, *b64, *bmem;
49   char *membuf;
50
51   b64 = BIO_new(BIO_f_base64());
52   if (!b64) {
53     safe_str(T("#-1 ALLOCATION ERROR"), buff, bp);
54     return false;
55   }
56
57   BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
58
59   bmem = BIO_new(BIO_s_mem());
60   if (!bmem) {
61     safe_str(T("#-1 ALLOCATION ERROR"), buff, bp);
62     BIO_free(b64);
63     return false;
64   }
65
66   bio = BIO_push(b64, bmem);
67
68   if (BIO_write(bio, input, len) < 0) {
69     safe_str(T("#-1 CONVERSION ERROR"), buff, bp);
70     BIO_free_all(bio);
71     return false;
72   }
73
74   len = BIO_flush(bio);
75
76   len = BIO_get_mem_data(bmem, &membuf);
77
78   safe_strl(membuf, len, buff, bp);
79
80   BIO_free_all(bio);
81
82   return true;
83 #else
84   safe_str(T("#-1 FUNCTION DISABLED"), buff, bp);
85   return false;
86 #endif
87 }
88
89 extern char valid_ansi_codes[UCHAR_MAX + 1];
90
91 static bool
92 decode_base64(char *encoded, int len, char *buff, char **bp)
93 {
94 #ifdef HAVE_SSL
95   BIO *bio, *b64, *bmem;
96   char *sbp;
97
98   b64 = BIO_new(BIO_f_base64());
99   if (!b64) {
100     safe_str(T("#-1 ALLOCATION ERROR"), buff, bp);
101     return false;
102   }
103   BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
104
105   bmem = BIO_new_mem_buf(encoded, len);
106   if (!bmem) {
107     safe_str(T("#-1 ALLOCATION ERROR"), buff, bp);
108     BIO_free(b64);
109     return false;
110   }
111   len = BIO_set_close(bmem, BIO_NOCLOSE);
112
113   bio = BIO_push(b64, bmem);
114
115   sbp = *bp;
116   while (true) {
117     char decoded[BUFFER_LEN];
118     int dlen;
119
120     dlen = BIO_read(bio, decoded, BUFFER_LEN);
121     if (dlen > 0) {
122       int n;
123       for (n = 0; n < dlen; n++) {
124         if (decoded[n] == TAG_START) {
125           int end;
126           n += 1;
127           for (end = n; end < dlen; end++) {
128             if (decoded[end] == TAG_END)
129               break;
130           }
131           if (end == dlen || decoded[n] != MARKUP_COLOR) {
132             BIO_free_all(bio);
133             *bp = sbp;
134             safe_str(T("#-1 CONVERSION ERROR"), buff, bp);
135             return false;
136           }
137           for (; n < end; n++) {
138             if (!valid_ansi_codes[(unsigned char) decoded[n]]) {
139               BIO_free_all(bio);
140               *bp = sbp;
141               safe_str(T("#-1 CONVERSION ERROR"), buff, bp);
142               return false;
143             }
144           }
145           n = end;
146         } else if (!isprint((unsigned char) decoded[n]))
147           decoded[n] = '?';
148       }
149       safe_strl(decoded, dlen, buff, bp);
150     } else if (dlen == 0)
151       break;
152     else {
153       *bp = sbp;
154       safe_str(T("#-1 CONVERSION ERROR"), buff, bp);
155       return false;
156     }
157   }
158
159   BIO_free_all(bio);
160
161   return true;
162 #else
163   safe_str(T("#-1 FUNCTION DISABLED"), buff, bp);
164   return false;
165 #endif
166 }
167
168 /* Encode a string in base64 */
169 FUNCTION(fun_encode64)
170 {
171   encode_base64(args[0], arglens[0], buff, bp);
172 }
173
174 /* Decode a string from base64 */
175 FUNCTION(fun_decode64)
176 {
177   decode_base64(args[0], arglens[0], buff, bp);
178 }
179
180 /* Copy over only alphanumeric chars */
181 static char *
182 crunch_code(char *code)
183 {
184   char *in;
185   char *out;
186   static char output[BUFFER_LEN];
187
188   out = output;
189   in = code;
190   while (*in) {
191     while (*in == ESC_CHAR) {
192       while (*in && *in != 'm')
193         in++;
194       in++;                     /* skip 'm' */
195     }
196     if ((*in >= 32) && (*in <= 126)) {
197       *out++ = *in;
198     }
199     in++;
200   }
201   *out = '\0';
202   return output;
203 }
204
205 static char *
206 crypt_code(char *code, char *text, int type)
207 {
208   static char textbuff[BUFFER_LEN];
209   char codebuff[BUFFER_LEN];
210   int start = 32;
211   int end = 126;
212   int mod = end - start + 1;
213   char *p, *q, *r;
214
215   if (!text && !*text)
216     return (char *) "";
217   if (!code || !*code)
218     return text;
219   mush_strncpy(codebuff, crunch_code(code), BUFFER_LEN);
220   if (!*codebuff)
221     return text;
222   textbuff[0] = '\0';
223
224   p = text;
225   q = codebuff;
226   r = textbuff;
227   /* Encryption: Simply go through each character of the text, get its ascii
228    * value, subtract start, add the ascii value (less start) of the
229    * code, mod the result, add start. Continue  */
230   while (*p) {
231     if ((*p < start) || (*p > end)) {
232       p++;
233       continue;
234     }
235     if (type)
236       *r++ = (((*p++ - start) + (*q++ - start)) % mod) + start;
237     else
238       *r++ = (((*p++ - *q++) + 2 * mod) % mod) + start;
239     if (!*q)
240       q = codebuff;
241   }
242   *r = '\0';
243   return textbuff;
244 }
245
246 static void
247 safe_sha0(const char *text, size_t len, char *buff, char **bp)
248 {
249 #ifdef HAS_OPENSSL
250   unsigned char hash[SHA_DIGEST_LENGTH];
251   int n;
252
253   SHA((unsigned char *) text, len, hash);
254
255   for (n = 0; n < SHA_DIGEST_LENGTH; n++)
256     safe_hexchar(hash[n], buff, bp);
257 #else
258   SHS_INFO shsInfo;
259   shsInfo.reverse_wanted = (BYTE) options.reverse_shs;
260   shsInit(&shsInfo);
261   shsUpdate(&shsInfo, (const BYTE *) text, len);
262   shsFinal(&shsInfo);
263   safe_format(buff, bp, "%0lx%0lx%0lx%0lx%0lx", shsInfo.digest[0],
264               shsInfo.digest[1], shsInfo.digest[2], shsInfo.digest[3],
265               shsInfo.digest[4]);
266 #endif
267 }
268
269 FUNCTION(fun_encrypt)
270 {
271   char tbuff[BUFFER_LEN], *tp;
272   char *pass;
273   size_t len;
274   ansi_string *as = parse_ansi_string(args[0]);
275
276   pass = remove_markup(args[1], &len);
277
278   tp = tbuff;
279   safe_str(crypt_code(pass, as->text, 1), tbuff, &tp);
280   *tp = '\0';
281   memcpy(as->text, tbuff, as->len);
282
283   if (nargs == 3 && parse_boolean(args[2])) {
284     tp = tbuff;
285     safe_ansi_string(as, 0, as->len, tbuff, &tp);
286     if (!encode_base64(tbuff, tp - tbuff, buff, bp)) {
287       free_ansi_string(as);
288       return;
289     }
290   } else
291     safe_ansi_string(as, 0, as->len, buff, bp);
292
293   free_ansi_string(as);
294 }
295
296 FUNCTION(fun_decrypt)
297 {
298   char tbuff[BUFFER_LEN], *tp;
299   char *pass;
300   size_t len;
301   ansi_string *as;
302   char *input;
303
304   if (nargs == 3 && parse_boolean(args[2])) {
305     tp = tbuff;
306     if (!decode_base64(args[0], arglens[0], tbuff, &tp)) {
307       safe_strl(tbuff, tp - tbuff, buff, bp);
308       return;
309     }
310     *tp = '\0';
311     input = tbuff;
312   } else
313     input = args[0];
314
315   as = parse_ansi_string(input);
316
317   pass = remove_markup(args[1], &len);
318
319   tp = tbuff;
320   safe_str(crypt_code(pass, as->text, 0), tbuff, &tp);
321   *tp = '\0';
322   memcpy(as->text, tbuff, as->len + 1);
323   safe_ansi_string(as, 0, as->len, buff, bp);
324   free_ansi_string(as);
325 }
326
327 FUNCTION(fun_checkpass)
328 {
329   dbref it = match_thing(executor, args[0]);
330   if (!(GoodObject(it) && IsPlayer(it))) {
331     safe_str(T("#-1 NO SUCH PLAYER"), buff, bp);
332     return;
333   }
334   safe_boolean(password_check(it, args[1]), buff, bp);
335 }
336
337 FUNCTION(fun_sha0)
338 {
339   safe_sha0(args[0], arglens[0], buff, bp);
340 }
341
342 FUNCTION(fun_digest)
343 {
344 #ifdef HAS_OPENSSL
345   EVP_MD_CTX ctx;
346   const EVP_MD *mp;
347   unsigned char md[EVP_MAX_MD_SIZE];
348   unsigned int n, len = 0;
349
350   if ((mp = EVP_get_digestbyname(args[0])) == NULL) {
351     safe_str(T("#-1 UNSUPPORTED DIGEST TYPE"), buff, bp);
352     return;
353   }
354
355   EVP_DigestInit(&ctx, mp);
356   EVP_DigestUpdate(&ctx, args[1], arglens[1]);
357   EVP_DigestFinal(&ctx, md, &len);
358
359   for (n = 0; n < len; n++) {
360     safe_hexchar(md[n], buff, bp);
361   }
362
363 #else
364   if (strcmp(args[0], "sha") == 0) {
365     safe_sha0(args[1], arglens[1], buff, bp);
366   } else {
367     safe_str(T("#-1 UNSUPPORTED DIGEST TYPE"), buff, bp);
368   }
369 #endif
370 }
371
372 static void
373 safe_hexchar(unsigned char c, char *buff, char **bp)
374 {
375   const char *digits = "0123456789abcdef";
376   if (*bp - buff < BUFFER_LEN - 1) {
377     **bp = digits[c >> 4];
378     (*bp)++;
379   }
380   if (*bp - buff < BUFFER_LEN - 1) {
381     **bp = digits[c & 0x0F];
382     (*bp)++;
383   }
384 }
Note: See TracBrowser for help on using the browser.