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