1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the same terms as Perl itself.
4 *
5 * Copyright 1998-2003 Gisle Aas.
6 * Copyright 1990-1992 RSA Data Security, Inc.
7 *
8 * This code is derived from the reference implementation in RFC 1231
9 * which comes with this message:
10 *
11 * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
12 * rights reserved.
13 *
14 * License to copy and use this software is granted for
15 * non-commercial Internet Privacy-Enhanced Mail provided that it is
16 * identified as the "RSA Data Security, Inc. MD2 Message Digest
17 * Algorithm" in all material mentioning or referencing this software
18 * or this function.
19 *
20 * RSA Data Security, Inc. makes no representations concerning either
21 * the merchantability of this software or the suitability of this
22 * software for any particular purpose. It is provided "as is"
23 * without express or implied warranty of any kind.
24 *
25 * These notices must be retained in any copies of any part of this
26 * documentation and/or software.
27
28 */
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 #include "EXTERN.h"
34 #include "perl.h"
35 #include "XSUB.h"
36 #ifdef __cplusplus
37 }
38 #endif
39
40 #ifndef PERL_VERSION
41 # include <patchlevel.h>
42 # if !(defined(PERL_VERSION) || (SUBVERSION > 0 && defined(PATCHLEVEL)))
43 # include <could_not_find_Perl_patchlevel.h>
44 # endif
45 # define PERL_REVISION 5
46 # define PERL_VERSION PATCHLEVEL
47 # define PERL_SUBVERSION SUBVERSION
48 #endif
49
50 #if PERL_VERSION <= 4 && !defined(PL_dowarn)
51 #define PL_dowarn dowarn
52 #endif
53
54 #ifdef G_WARN_ON
55 #define DOWARN (PL_dowarn & G_WARN_ON)
56 #else
57 #define DOWARN PL_dowarn
58 #endif
59
60
61 #ifdef SvPVbyte
62 #if PERL_REVISION == 5 && PERL_VERSION < 7
63 /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
64 #undef SvPVbyte
65 #define SvPVbyte(sv, lp) \
66 ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
67 ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
68
69 static char *
my_sv_2pvbyte(pTHX_ register SV * sv,STRLEN * lp)70 my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
71 {
72 sv_utf8_downgrade(sv,0);
73 return SvPV(sv,*lp);
74 }
75 #endif
76 #else
77 #define SvPVbyte SvPV
78 #endif
79
80 typedef struct {
81 unsigned char state[16]; /* state */
82 unsigned char checksum[16]; /* checksum */
83 unsigned int count; /* number of bytes, modulo 16 */
84 unsigned char buffer[16]; /* input buffer */
85 } MD2_CTX;
86
87
88 /* Permutation of 0..255 constructed from the digits of pi. It gives a
89 "random" nonlinear byte substitution operation.
90 */
91 static U8 PI_SUBST[256] = {
92 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
93 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
94 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
95 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
96 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
97 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
98 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
99 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
100 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
101 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
102 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
103 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
104 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
105 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
106 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
107 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
108 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
109 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
110 };
111
112 static U8 *PADDING[] = {
113 (U8 *)"",
114 (U8 *)"\001",
115 (U8 *)"\002\002",
116 (U8 *)"\003\003\003",
117 (U8 *)"\004\004\004\004",
118 (U8 *)"\005\005\005\005\005",
119 (U8 *)"\006\006\006\006\006\006",
120 (U8 *)"\007\007\007\007\007\007\007",
121 (U8 *)"\010\010\010\010\010\010\010\010",
122 (U8 *)"\011\011\011\011\011\011\011\011\011",
123 (U8 *)"\012\012\012\012\012\012\012\012\012\012",
124 (U8 *)"\013\013\013\013\013\013\013\013\013\013\013",
125 (U8 *)"\014\014\014\014\014\014\014\014\014\014\014\014",
126 (U8 *)"\015\015\015\015\015\015\015\015\015\015\015\015\015",
127 (U8 *)"\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
128 (U8 *)"\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
129 (U8 *)"\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
130 };
131
132
133 static void
MD2Init(MD2_CTX * context)134 MD2Init(MD2_CTX* context)
135 {
136 Zero(context, 1, MD2_CTX);
137 context->count = 0;
138 }
139
140
141 static void
MD2Transform(U8 * state,U8 * checksum,U8 * block)142 MD2Transform (U8* state, U8* checksum, U8* block)
143 {
144 unsigned int i, j, t;
145 U8 x[48];
146
147 /* Form encryption block from state, block, state ^ block.
148 */
149 Copy(state, x, 16, char);
150 Copy(block, x+16, 16, char);
151
152 for (i = 0; i < 16; i++)
153 x[i+32] = state[i] ^ block[i];
154
155 /* Encrypt block (18 rounds).
156 */
157 t = 0;
158 for (i = 0; i < 18; i++) {
159 for (j = 0; j < 48; j++)
160 t = x[j] ^= PI_SUBST[t];
161 t = (t + i) & 0xff;
162 }
163
164 Copy(x, state, 16, char); /* Save new state */
165
166 /* Update checksum.
167 */
168 t = checksum[15];
169 for (i = 0; i < 16; i++)
170 t = checksum[i] ^= PI_SUBST[block[i] ^ t];
171
172 Zero(x, 1, x); /* Zeroize sensitive information. */
173 }
174
175
176 static void
MD2Update(MD2_CTX * context,U8 * input,STRLEN inputLen)177 MD2Update (MD2_CTX* context, U8 *input, STRLEN inputLen)
178 {
179 unsigned int i, index, partLen;
180
181 /* Update number of bytes mod 16 */
182 index = context->count;
183 context->count = (index + inputLen) & 0xf;
184
185 partLen = 16 - index;
186
187 /* Transform as many times as possible.
188 */
189 if (inputLen >= partLen) {
190 Copy(input, context->buffer+index, partLen, char);
191 MD2Transform (context->state, context->checksum, context->buffer);
192
193 for (i = partLen; i + 15 < inputLen; i += 16)
194 MD2Transform (context->state, context->checksum, &input[i]);
195
196 index = 0;
197 }
198 else
199 i = 0;
200
201 /* Buffer remaining input */
202 Copy(input+i, context->buffer + index, inputLen-i, char);
203 }
204
205
206 static void
MD2Final(U8 * digest,MD2_CTX * context)207 MD2Final (U8* digest, MD2_CTX *context)
208 {
209 unsigned int index, padLen;
210
211 /* Pad out to multiple of 16 */
212 index = context->count;
213 padLen = 16 - index;
214 MD2Update (context, PADDING[padLen], padLen);
215
216 /* Extend with checksum */
217 MD2Update (context, context->checksum, 16);
218
219 Copy(context->state, digest, 16, char); /* Store state in digest */
220 Zero(context, 1, MD2_CTX); /* Zeroize sensitive information. */
221 }
222
223 /*----------------------------------------------------------------*/
224 #ifndef INT2PTR
225 #define INT2PTR(any,d) (any)(d)
226 #endif
227
228
get_md2_ctx(SV * sv)229 static MD2_CTX* get_md2_ctx(SV* sv)
230 {
231 if (sv_derived_from(sv, "Digest::MD2"))
232 return INT2PTR(MD2_CTX*, SvIV(SvRV(sv)));
233 croak("Not a reference to a Digest::MD2 object");
234 return (MD2_CTX*)0; /* some compilers insist on a return value */
235 }
236
237
hex_16(const unsigned char * from,char * to)238 static char* hex_16(const unsigned char* from, char* to)
239 {
240 static char *hexdigits = "0123456789abcdef";
241 const unsigned char *end = from + 16;
242 char *d = to;
243
244 while (from < end) {
245 *d++ = hexdigits[(*from >> 4)];
246 *d++ = hexdigits[(*from & 0x0F)];
247 from++;
248 }
249 *d = '\0';
250 return to;
251 }
252
base64_16(const unsigned char * from,char * to)253 static char* base64_16(const unsigned char* from, char* to)
254 {
255 static char* base64 =
256 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
257 const unsigned char *end = from + 16;
258 unsigned char c1, c2, c3;
259 char *d = to;
260
261 while (1) {
262 c1 = *from++;
263 *d++ = base64[c1>>2];
264 if (from == end) {
265 *d++ = base64[(c1 & 0x3) << 4];
266 break;
267 }
268 c2 = *from++;
269 c3 = *from++;
270 *d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
271 *d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
272 *d++ = base64[c3 & 0x3F];
273 }
274 *d = '\0';
275 return to;
276 }
277
278 /* Formats */
279 #define F_BIN 0
280 #define F_HEX 1
281 #define F_B64 2
282
make_mortal_sv(const unsigned char * src,int type)283 static SV* make_mortal_sv(const unsigned char *src, int type)
284 {
285 STRLEN len;
286 char result[33];
287 char *ret;
288
289 switch (type) {
290 case F_BIN:
291 ret = (char*)src;
292 len = 16;
293 break;
294 case F_HEX:
295 ret = hex_16(src, result);
296 len = 32;
297 break;
298 case F_B64:
299 ret = base64_16(src, result);
300 len = 22;
301 break;
302 default:
303 croak("Bad convertion type (%d)", type);
304 break;
305 }
306 return sv_2mortal(newSVpv(ret,len));
307 }
308
309
310 /********************************************************************/
311
312 typedef PerlIO* InputStream;
313
314 MODULE = Digest::MD2 PACKAGE = Digest::MD2
315
316 PROTOTYPES: DISABLE
317
318 void
new(xclass)319 new(xclass)
320 SV* xclass
321 PREINIT:
322 MD2_CTX* context;
323 PPCODE:
324 if (!SvROK(xclass)) {
325 STRLEN my_na;
326 char *sclass = SvPV(xclass, my_na);
327 New(55, context, 1, MD2_CTX);
328 ST(0) = sv_newmortal();
329 sv_setref_pv(ST(0), sclass, (void*)context);
330 SvREADONLY_on(SvRV(ST(0)));
331 } else {
332 context = get_md2_ctx(xclass);
333 }
334 MD2Init(context);
335 XSRETURN(1);
336
337 void
338 clone(self)
339 SV* self
340 PREINIT:
341 MD2_CTX* cont = get_md2_ctx(self);
342 char *myname = sv_reftype(SvRV(self),TRUE);
343 MD2_CTX* context;
344 PPCODE:
345 STRLEN my_na;
346 New(55, context, 1, MD2_CTX);
347 ST(0) = sv_newmortal();
348 sv_setref_pv(ST(0), myname , (void*)context);
349 SvREADONLY_on(SvRV(ST(0)));
350 memcpy(context,cont,sizeof(MD2_CTX));
351 XSRETURN(1);
352
353 void
354 DESTROY(context)
355 MD2_CTX* context
356 CODE:
357 Safefree(context);
358
359 void
360 add(self, ...)
361 SV* self
362 PREINIT:
363 MD2_CTX* context = get_md2_ctx(self);
364 int i;
365 unsigned char *data;
366 STRLEN len;
367 PPCODE:
368 for (i = 1; i < items; i++) {
369 data = (unsigned char *)(SvPVbyte(ST(i), len));
370 MD2Update(context, data, len);
371 }
372 XSRETURN(1); /* self */
373
374 void
375 addfile(self, fh)
376 SV* self
377 InputStream fh
378 PREINIT:
379 MD2_CTX* context = get_md2_ctx(self);
380 unsigned char buffer[4096];
381 int n;
382 CODE:
383 if (fh) {
384 /* Process blocks until EOF */
385 while ( (n = PerlIO_read(fh, buffer, sizeof(buffer))) > 0) {
386 MD2Update(context, buffer, n);
387 }
388 if (PerlIO_error(fh)) {
389 croak("Reading from filehandle failed");
390 }
391 }
392 else {
393 croak("No filehandle passed");
394 }
395 XSRETURN(1); /* self */
396
397 void
398 digest(context)
399 MD2_CTX* context
400 ALIAS:
401 Digest::MD2::digest = F_BIN
402 Digest::MD2::hexdigest = F_HEX
403 Digest::MD2::b64digest = F_B64
404 PREINIT:
405 unsigned char digeststr[16];
406 PPCODE:
407 MD2Final(digeststr, context);
408 MD2Init(context); /* In case it is reused */
409 ST(0) = make_mortal_sv(digeststr, ix);
410 XSRETURN(1);
411
412 void
413 md2(...)
414 ALIAS:
415 Digest::MD2::md2 = F_BIN
416 Digest::MD2::md2_hex = F_HEX
417 Digest::MD2::md2_base64 = F_B64
418 PREINIT:
419 MD2_CTX ctx;
420 int i;
421 unsigned char *data;
422 STRLEN len;
423 unsigned char digeststr[16];
424 PPCODE:
425 MD2Init(&ctx);
426
427 if (DOWARN) {
428 char *msg = 0;
429 if (items == 1) {
430 if (SvROK(ST(0))) {
431 SV* sv = SvRV(ST(0));
432 if (SvOBJECT(sv) && strEQ(HvNAME(SvSTASH(sv)), "Digest::MD2"))
433 msg = "probably called as method";
434 else
435 msg = "called with reference argument";
436 }
437 }
438 else if (items > 1) {
439 data = (unsigned char *)SvPVbyte(ST(0), len);
440 if (len == 11 && memEQ("Digest::MD2", data, 11)) {
441 msg = "probably called as class method";
442 }
443 }
444 if (msg) {
445 char *f = (ix == F_BIN) ? "md2" :
446 (ix == F_HEX) ? "md2_hex" : "md2_base64";
447 warn("&Digest::MD2::%s function %s", f, msg);
448 }
449 }
450
451 for (i = 0; i < items; i++) {
452 data = (unsigned char *)(SvPVbyte(ST(i), len));
453 MD2Update(&ctx, data, len);
454 }
455 MD2Final(digeststr, &ctx);
456 ST(0) = make_mortal_sv(digeststr, ix);
457 XSRETURN(1);
458