File Coverage

MD5.xs
Criterion Covered Total %
statement 234 278 84.1
branch 57 128 44.5
condition n/a
subroutine n/a
pod n/a
total 291 406 71.6


line stmt bran cond sub pod time code
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-2000 Gisle Aas.
6             * Copyright 1995-1996 Neil Winton.
7             * Copyright 1991-1992 RSA Data Security, Inc.
8             *
9             * This code is derived from Neil Winton's MD5-1.7 Perl module, which in
10             * turn is derived from the reference implementation in RFC 1321 which
11             * comes with this message:
12             *
13             * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
14             * rights reserved.
15             *
16             * License to copy and use this software is granted provided that it
17             * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
18             * Algorithm" in all material mentioning or referencing this software
19             * or this function.
20             *
21             * License is also granted to make and use derivative works provided
22             * that such works are identified as "derived from the RSA Data
23             * Security, Inc. MD5 Message-Digest Algorithm" in all material
24             * mentioning or referencing the derived work.
25             *
26             * RSA Data Security, Inc. makes no representations concerning either
27             * the merchantability of this software or the suitability of this
28             * software for any particular purpose. It is provided "as is"
29             * without express or implied warranty of any kind.
30             *
31             * These notices must be retained in any copies of any part of this
32             * documentation and/or software.
33             */
34              
35             #ifdef __cplusplus
36             extern "C" {
37             #endif
38             #define PERL_NO_GET_CONTEXT /* we want efficiency */
39             #include "EXTERN.h"
40             #include "perl.h"
41             #include "XSUB.h"
42             #ifdef __cplusplus
43             }
44             #endif
45              
46             #ifndef PERL_UNUSED_VAR
47             # define PERL_UNUSED_VAR(x) ((void)x)
48             #endif
49              
50             #ifndef PERL_MAGIC_ext
51             # define PERL_MAGIC_ext '~'
52             #endif
53              
54             #ifndef Newxz
55             # define Newxz(v,n,t) Newz(0,v,n,t)
56             #endif
57              
58             #ifndef SvMAGIC_set
59             # define SvMAGIC_set(sv, mg) (SvMAGIC(sv) = (mg))
60             #endif
61              
62             #ifndef sv_magicext
63             # define sv_magicext(sv, obj, type, vtbl, name, namlen) \
64             THX_sv_magicext(aTHX_ sv, obj, type, vtbl, name, namlen)
65             static MAGIC *THX_sv_magicext(pTHX_ SV *sv, SV *obj, int type,
66             MGVTBL const *vtbl, char const *name, I32 namlen)
67             {
68             MAGIC *mg;
69             if (obj || namlen)
70             /* exceeded intended usage of this reserve implementation */
71             return NULL;
72             Newxz(mg, 1, MAGIC);
73             mg->mg_virtual = (MGVTBL*)vtbl;
74             mg->mg_type = type;
75             mg->mg_ptr = (char *)name;
76             mg->mg_len = -1;
77             (void) SvUPGRADE(sv, SVt_PVMG);
78             mg->mg_moremagic = SvMAGIC(sv);
79             SvMAGIC_set(sv, mg);
80             SvMAGICAL_off(sv);
81             mg_magical(sv);
82             return mg;
83             }
84             #endif
85              
86             #if PERL_VERSION < 8
87             # undef SvPVbyte
88             # define SvPVbyte(sv, lp) (sv_utf8_downgrade((sv), 0), SvPV((sv), (lp)))
89             #endif
90              
91             /* Perl does not guarantee that U32 is exactly 32 bits. Some system
92             * has no integral type with exactly 32 bits. For instance, A Cray has
93             * short, int and long all at 64 bits so we need to apply this macro
94             * to reduce U32 values to 32 bits at appropriate places. If U32
95             * really does have 32 bits then this is a no-op.
96             */
97             #if BYTEORDER > 0x4321 || defined(TRUNCATE_U32)
98             #define TO32(x) ((x) & 0xFFFFffff)
99             #define TRUNC32(x) ((x) &= 0xFFFFffff)
100             #else
101             #define TO32(x) (x)
102             #define TRUNC32(x) /*nothing*/
103             #endif
104              
105             /* The MD5 algorithm is defined in terms of little endian 32-bit
106             * values. The following macros (and functions) allow us to convert
107             * between native integers and such values.
108             */
109 8766           static void u2s(U32 u, U8* s)
110             {
111 8766           *s++ = (U8)(u & 0xFF);
112 8766           *s++ = (U8)((u >> 8) & 0xFF);
113 8766           *s++ = (U8)((u >> 16) & 0xFF);
114 8766           *s = (U8)((u >> 24) & 0xFF);
115 8766           }
116              
117             #define s2u(s,u) ((u) = (U32)(*s) | \
118             ((U32)(*(s+1)) << 8) | \
119             ((U32)(*(s+2)) << 16) | \
120             ((U32)(*(s+3)) << 24))
121              
122             /* This structure keeps the current state of algorithm.
123             */
124             typedef struct {
125             U32 A, B, C, D; /* current digest */
126             U32 bytes_low; /* counts bytes in message */
127             U32 bytes_high; /* turn it into a 64-bit counter */
128             U8 buffer[128]; /* collect complete 64 byte blocks */
129             } MD5_CTX;
130              
131             #if defined(USE_ITHREADS) && defined(MGf_DUP)
132             STATIC int dup_md5_ctx(pTHX_ MAGIC *mg, CLONE_PARAMS *params)
133             {
134             MD5_CTX *new_ctx;
135             PERL_UNUSED_VAR(params);
136             New(55, new_ctx, 1, MD5_CTX);
137             memcpy(new_ctx, mg->mg_ptr, sizeof(MD5_CTX));
138             mg->mg_ptr = (char *)new_ctx;
139             return 0;
140             }
141             #endif
142              
143             #if defined(MGf_DUP) && defined(USE_ITHREADS)
144             STATIC const MGVTBL vtbl_md5 = {
145             NULL, /* get */
146             NULL, /* set */
147             NULL, /* len */
148             NULL, /* clear */
149             NULL, /* free */
150             NULL, /* copy */
151             dup_md5_ctx, /* dup */
152             NULL /* local */
153             };
154             #else
155             /* declare as 5 member, not normal 8 to save image space*/
156             STATIC const struct {
157             int (*svt_get)(SV* sv, MAGIC* mg);
158             int (*svt_set)(SV* sv, MAGIC* mg);
159             U32 (*svt_len)(SV* sv, MAGIC* mg);
160             int (*svt_clear)(SV* sv, MAGIC* mg);
161             int (*svt_free)(SV* sv, MAGIC* mg);
162             } vtbl_md5 = {
163             NULL, NULL, NULL, NULL, NULL
164             };
165             #endif
166              
167              
168             /* Padding is added at the end of the message in order to fill a
169             * complete 64 byte block (- 8 bytes for the message length). The
170             * padding is also the reason the buffer in MD5_CTX have to be
171             * 128 bytes.
172             */
173             static const unsigned char PADDING[64] = {
174             0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
175             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
177             };
178              
179             /* Constants for MD5Transform routine.
180             */
181             #define S11 7
182             #define S12 12
183             #define S13 17
184             #define S14 22
185             #define S21 5
186             #define S22 9
187             #define S23 14
188             #define S24 20
189             #define S31 4
190             #define S32 11
191             #define S33 16
192             #define S34 23
193             #define S41 6
194             #define S42 10
195             #define S43 15
196             #define S44 21
197              
198             /* F, G, H and I are basic MD5 functions.
199             */
200             #define F(x, y, z) ((((x) & ((y) ^ (z))) ^ (z)))
201             #define G(x, y, z) F(z, x, y)
202             #define H(x, y, z) ((x) ^ (y) ^ (z))
203             #define I(x, y, z) ((y) ^ ((x) | (~z)))
204              
205             /* ROTATE_LEFT rotates x left n bits.
206             */
207             #define ROTATE_LEFT(x, n) (((x) << (n) | ((x) >> (32-(n)))))
208              
209             /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
210             * Rotation is separate from addition to prevent recomputation.
211             */
212             #define FF(a, b, c, d, s, ac) \
213             (a) += F ((b), (c), (d)) + (NEXTx) + (U32)(ac); \
214             TRUNC32((a)); \
215             (a) = ROTATE_LEFT ((a), (s)); \
216             (a) += (b); \
217             TRUNC32((a));
218              
219             #define GG(a, b, c, d, x, s, ac) \
220             (a) += G ((b), (c), (d)) + X[x] + (U32)(ac); \
221             TRUNC32((a)); \
222             (a) = ROTATE_LEFT ((a), (s)); \
223             (a) += (b); \
224             TRUNC32((a));
225              
226             #define HH(a, b, c, d, x, s, ac) \
227             (a) += H ((b), (c), (d)) + X[x] + (U32)(ac); \
228             TRUNC32((a)); \
229             (a) = ROTATE_LEFT ((a), (s)); \
230             (a) += (b); \
231             TRUNC32((a));
232              
233             #define II(a, b, c, d, x, s, ac) \
234             (a) += I ((b), (c), (d)) + X[x] + (U32)(ac); \
235             TRUNC32((a)); \
236             (a) = ROTATE_LEFT ((a), (s)); \
237             (a) += (b); \
238             TRUNC32((a));
239              
240              
241             static void
242 2636           MD5Init(MD5_CTX *ctx)
243             {
244             /* Start state */
245 2636           ctx->A = 0x67452301;
246 2636           ctx->B = 0xefcdab89;
247 2636           ctx->C = 0x98badcfe;
248 2636           ctx->D = 0x10325476;
249              
250             /* message length */
251 2636           ctx->bytes_low = ctx->bytes_high = 0;
252 2636           }
253              
254              
255             static void
256 8400           MD5Transform(MD5_CTX* ctx, const U8* buf, STRLEN blocks)
257             {
258             #ifdef MD5_DEBUG
259             static int tcount = 0;
260             #endif
261              
262 8400           U32 A = ctx->A;
263 8400           U32 B = ctx->B;
264 8400           U32 C = ctx->C;
265 8400           U32 D = ctx->D;
266              
267             do {
268 212782           U32 a = A;
269 212782           U32 b = B;
270 212782           U32 c = C;
271 212782           U32 d = D;
272              
273             U32 X[16]; /* little-endian values, used in round 2-4 */
274 212782           U32 *uptr = X;
275             U32 tmp;
276             #define NEXTx (s2u(buf,tmp), buf += 4, *uptr++ = tmp)
277              
278             #ifdef MD5_DEBUG
279             if (buf == ctx->buffer)
280             fprintf(stderr,"%5d: Transform ctx->buffer", ++tcount);
281             else
282             fprintf(stderr,"%5d: Transform %p (%d)", ++tcount, buf, blocks);
283              
284             {
285             int i;
286             fprintf(stderr,"[");
287             for (i = 0; i < 16; i++) {
288             fprintf(stderr,"%x,", x[i]); /* FIXME */
289             }
290             fprintf(stderr,"]\n");
291             }
292             #endif
293              
294             /* Round 1 */
295 212782           FF (a, b, c, d, S11, 0xd76aa478); /* 1 */
296 212782           FF (d, a, b, c, S12, 0xe8c7b756); /* 2 */
297 212782           FF (c, d, a, b, S13, 0x242070db); /* 3 */
298 212782           FF (b, c, d, a, S14, 0xc1bdceee); /* 4 */
299 212782           FF (a, b, c, d, S11, 0xf57c0faf); /* 5 */
300 212782           FF (d, a, b, c, S12, 0x4787c62a); /* 6 */
301 212782           FF (c, d, a, b, S13, 0xa8304613); /* 7 */
302 212782           FF (b, c, d, a, S14, 0xfd469501); /* 8 */
303 212782           FF (a, b, c, d, S11, 0x698098d8); /* 9 */
304 212782           FF (d, a, b, c, S12, 0x8b44f7af); /* 10 */
305 212782           FF (c, d, a, b, S13, 0xffff5bb1); /* 11 */
306 212782           FF (b, c, d, a, S14, 0x895cd7be); /* 12 */
307 212782           FF (a, b, c, d, S11, 0x6b901122); /* 13 */
308 212782           FF (d, a, b, c, S12, 0xfd987193); /* 14 */
309 212782           FF (c, d, a, b, S13, 0xa679438e); /* 15 */
310 212782           FF (b, c, d, a, S14, 0x49b40821); /* 16 */
311              
312             /* Round 2 */
313 212782           GG (a, b, c, d, 1, S21, 0xf61e2562); /* 17 */
314 212782           GG (d, a, b, c, 6, S22, 0xc040b340); /* 18 */
315 212782           GG (c, d, a, b, 11, S23, 0x265e5a51); /* 19 */
316 212782           GG (b, c, d, a, 0, S24, 0xe9b6c7aa); /* 20 */
317 212782           GG (a, b, c, d, 5, S21, 0xd62f105d); /* 21 */
318 212782           GG (d, a, b, c, 10, S22, 0x2441453); /* 22 */
319 212782           GG (c, d, a, b, 15, S23, 0xd8a1e681); /* 23 */
320 212782           GG (b, c, d, a, 4, S24, 0xe7d3fbc8); /* 24 */
321 212782           GG (a, b, c, d, 9, S21, 0x21e1cde6); /* 25 */
322 212782           GG (d, a, b, c, 14, S22, 0xc33707d6); /* 26 */
323 212782           GG (c, d, a, b, 3, S23, 0xf4d50d87); /* 27 */
324 212782           GG (b, c, d, a, 8, S24, 0x455a14ed); /* 28 */
325 212782           GG (a, b, c, d, 13, S21, 0xa9e3e905); /* 29 */
326 212782           GG (d, a, b, c, 2, S22, 0xfcefa3f8); /* 30 */
327 212782           GG (c, d, a, b, 7, S23, 0x676f02d9); /* 31 */
328 212782           GG (b, c, d, a, 12, S24, 0x8d2a4c8a); /* 32 */
329              
330             /* Round 3 */
331 212782           HH (a, b, c, d, 5, S31, 0xfffa3942); /* 33 */
332 212782           HH (d, a, b, c, 8, S32, 0x8771f681); /* 34 */
333 212782           HH (c, d, a, b, 11, S33, 0x6d9d6122); /* 35 */
334 212782           HH (b, c, d, a, 14, S34, 0xfde5380c); /* 36 */
335 212782           HH (a, b, c, d, 1, S31, 0xa4beea44); /* 37 */
336 212782           HH (d, a, b, c, 4, S32, 0x4bdecfa9); /* 38 */
337 212782           HH (c, d, a, b, 7, S33, 0xf6bb4b60); /* 39 */
338 212782           HH (b, c, d, a, 10, S34, 0xbebfbc70); /* 40 */
339 212782           HH (a, b, c, d, 13, S31, 0x289b7ec6); /* 41 */
340 212782           HH (d, a, b, c, 0, S32, 0xeaa127fa); /* 42 */
341 212782           HH (c, d, a, b, 3, S33, 0xd4ef3085); /* 43 */
342 212782           HH (b, c, d, a, 6, S34, 0x4881d05); /* 44 */
343 212782           HH (a, b, c, d, 9, S31, 0xd9d4d039); /* 45 */
344 212782           HH (d, a, b, c, 12, S32, 0xe6db99e5); /* 46 */
345 212782           HH (c, d, a, b, 15, S33, 0x1fa27cf8); /* 47 */
346 212782           HH (b, c, d, a, 2, S34, 0xc4ac5665); /* 48 */
347              
348             /* Round 4 */
349 212782           II (a, b, c, d, 0, S41, 0xf4292244); /* 49 */
350 212782           II (d, a, b, c, 7, S42, 0x432aff97); /* 50 */
351 212782           II (c, d, a, b, 14, S43, 0xab9423a7); /* 51 */
352 212782           II (b, c, d, a, 5, S44, 0xfc93a039); /* 52 */
353 212782           II (a, b, c, d, 12, S41, 0x655b59c3); /* 53 */
354 212782           II (d, a, b, c, 3, S42, 0x8f0ccc92); /* 54 */
355 212782           II (c, d, a, b, 10, S43, 0xffeff47d); /* 55 */
356 212782           II (b, c, d, a, 1, S44, 0x85845dd1); /* 56 */
357 212782           II (a, b, c, d, 8, S41, 0x6fa87e4f); /* 57 */
358 212782           II (d, a, b, c, 15, S42, 0xfe2ce6e0); /* 58 */
359 212782           II (c, d, a, b, 6, S43, 0xa3014314); /* 59 */
360 212782           II (b, c, d, a, 13, S44, 0x4e0811a1); /* 60 */
361 212782           II (a, b, c, d, 4, S41, 0xf7537e82); /* 61 */
362 212782           II (d, a, b, c, 11, S42, 0xbd3af235); /* 62 */
363 212782           II (c, d, a, b, 2, S43, 0x2ad7d2bb); /* 63 */
364 212782           II (b, c, d, a, 9, S44, 0xeb86d391); /* 64 */
365              
366 212782           A += a; TRUNC32(A);
367 212782           B += b; TRUNC32(B);
368 212782           C += c; TRUNC32(C);
369 212782           D += d; TRUNC32(D);
370              
371 212782 100         } while (--blocks);
372 8400           ctx->A = A;
373 8400           ctx->B = B;
374 8400           ctx->C = C;
375 8400           ctx->D = D;
376 8400           }
377              
378              
379             #ifdef MD5_DEBUG
380             static char*
381             ctx_dump(MD5_CTX* ctx)
382             {
383             static char buf[1024];
384             sprintf(buf, "{A=%x,B=%x,C=%x,D=%x,%d,%d(%d)}",
385             ctx->A, ctx->B, ctx->C, ctx->D,
386             ctx->bytes_low, ctx->bytes_high, (ctx->bytes_low&0x3F));
387             return buf;
388             }
389             #endif
390              
391              
392             static void
393 208421           MD5Update(MD5_CTX* ctx, const U8* buf, STRLEN len)
394             {
395             STRLEN blocks;
396 208421           STRLEN fill = ctx->bytes_low & 0x3F;
397              
398             #ifdef MD5_DEBUG
399             static int ucount = 0;
400             fprintf(stderr,"%5i: Update(%s, %p, %d)\n", ++ucount, ctx_dump(ctx),
401             buf, len);
402             #endif
403              
404 208421           ctx->bytes_low += len;
405 208421 50         if (ctx->bytes_low < len) /* wrap around */
406 0           ctx->bytes_high++;
407              
408 208421 100         if (fill) {
409 201140           STRLEN missing = 64 - fill;
410 201140 100         if (len < missing) {
411 198073           Copy(buf, ctx->buffer + fill, len, U8);
412 198073           return;
413             }
414 3067           Copy(buf, ctx->buffer + fill, missing, U8);
415 3067           MD5Transform(ctx, ctx->buffer, 1);
416 3067           buf += missing;
417 3067           len -= missing;
418             }
419              
420 10348           blocks = len >> 6;
421 10348 100         if (blocks)
422 3872           MD5Transform(ctx, buf, blocks);
423 10348 100         if ( (len &= 0x3F)) {
424 4513           Copy(buf + (blocks << 6), ctx->buffer, len, U8);
425             }
426             }
427              
428              
429             static void
430 1461           MD5Final(U8* digest, MD5_CTX *ctx)
431             {
432 1461           STRLEN fill = ctx->bytes_low & 0x3F;
433 1461 100         STRLEN padlen = (fill < 56 ? 56 : 120) - fill;
434             U32 bits_low, bits_high;
435             #ifdef MD5_DEBUG
436             fprintf(stderr," Final: %s\n", ctx_dump(ctx));
437             #endif
438 1461           Copy(PADDING, ctx->buffer + fill, padlen, U8);
439 1461           fill += padlen;
440              
441 1461           bits_low = ctx->bytes_low << 3;
442 1461           bits_high = (ctx->bytes_high << 3) | (ctx->bytes_low >> 29);
443 1461           u2s(bits_low, ctx->buffer + fill); fill += 4;
444 1461           u2s(bits_high, ctx->buffer + fill); fill += 4;
445              
446 1461           MD5Transform(ctx, ctx->buffer, fill >> 6);
447             #ifdef MD5_DEBUG
448             fprintf(stderr," Result: %s\n", ctx_dump(ctx));
449             #endif
450              
451 1461           u2s(ctx->A, digest);
452 1461           u2s(ctx->B, digest+4);
453 1461           u2s(ctx->C, digest+8);
454 1461           u2s(ctx->D, digest+12);
455 1461           }
456              
457             #ifndef INT2PTR
458             #define INT2PTR(any,d) (any)(d)
459             #endif
460              
461 60723           static MD5_CTX* get_md5_ctx(pTHX_ SV* sv)
462             {
463             MAGIC *mg;
464              
465 60723 50         if (!sv_derived_from(sv, "Digest::MD5"))
466 0           croak("Not a reference to a Digest::MD5 object");
467              
468 60723 50         for (mg = SvMAGIC(SvRV(sv)); mg; mg = mg->mg_moremagic) {
469 60723 50         if (mg->mg_type == PERL_MAGIC_ext
470 60723 50         && mg->mg_virtual == (const MGVTBL * const)&vtbl_md5) {
471 60723           return (MD5_CTX *)mg->mg_ptr;
472             }
473             }
474              
475 0           croak("Failed to get MD5_CTX pointer");
476             return (MD5_CTX*)0; /* some compilers insist on a return value */
477             }
478              
479 1179           static SV * new_md5_ctx(pTHX_ MD5_CTX *context, const char *klass)
480             {
481 1179           SV *sv = newSV(0);
482 1179           SV *obj = newRV_noinc(sv);
483             #ifdef USE_ITHREADS
484             MAGIC *mg;
485             #endif
486              
487 1179           sv_bless(obj, gv_stashpv(klass, 0));
488              
489             #ifdef USE_ITHREADS
490             mg =
491             #endif
492 1179           sv_magicext(sv, NULL, PERL_MAGIC_ext, (const MGVTBL * const)&vtbl_md5, (const char *)context, 0);
493              
494             #if defined(USE_ITHREADS) && defined(MGf_DUP)
495             mg->mg_flags |= MGf_DUP;
496             #endif
497              
498 1179           return obj;
499             }
500              
501              
502 1178           static char* hex_16(const unsigned char* from, char* to)
503             {
504             static const char hexdigits[] = "0123456789abcdef";
505 1178           const unsigned char *end = from + 16;
506 1178           char *d = to;
507              
508 20026 100         while (from < end) {
509 18848           *d++ = hexdigits[(*from >> 4)];
510 18848           *d++ = hexdigits[(*from & 0x0F)];
511 18848           from++;
512             }
513 1178           *d = '\0';
514 1178           return to;
515             }
516              
517 9           static char* base64_16(const unsigned char* from, char* to)
518             {
519             static const char base64[] =
520             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
521 9           const unsigned char *end = from + 16;
522             unsigned char c1, c2, c3;
523 9           char *d = to;
524              
525             while (1) {
526 54           c1 = *from++;
527 54           *d++ = base64[c1>>2];
528 54 100         if (from == end) {
529 9           *d++ = base64[(c1 & 0x3) << 4];
530 9           break;
531             }
532 45           c2 = *from++;
533 45           c3 = *from++;
534 45           *d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
535 45           *d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
536 45           *d++ = base64[c3 & 0x3F];
537 45           }
538 9           *d = '\0';
539 9           return to;
540             }
541              
542             /* Formats */
543             #define F_BIN 0
544             #define F_HEX 1
545             #define F_B64 2
546              
547 1461           static SV* make_mortal_sv(pTHX_ const unsigned char *src, int type)
548             {
549             STRLEN len;
550             char result[33];
551             char *ret;
552            
553 1461           switch (type) {
554             case F_BIN:
555 274           ret = (char*)src;
556 274           len = 16;
557 274           break;
558             case F_HEX:
559 1178           ret = hex_16(src, result);
560 1178           len = 32;
561 1178           break;
562             case F_B64:
563 9           ret = base64_16(src, result);
564 9           len = 22;
565 9           break;
566             default:
567 0           croak("Bad conversion type (%d)", type);
568             break;
569             }
570 1461           return sv_2mortal(newSVpv(ret,len));
571             }
572              
573              
574             /********************************************************************/
575              
576             typedef PerlIO* InputStream;
577              
578             MODULE = Digest::MD5 PACKAGE = Digest::MD5
579              
580             PROTOTYPES: DISABLE
581              
582             void
583             new(xclass)
584             SV* xclass
585             PREINIT:
586             MD5_CTX* context;
587             PPCODE:
588 1174 50         if (!SvROK(xclass)) {
589             STRLEN my_na;
590 1174 50         const char *sclass = SvPV(xclass, my_na);
591 1174           New(55, context, 1, MD5_CTX);
592 1174           ST(0) = sv_2mortal(new_md5_ctx(aTHX_ context, sclass));
593             } else {
594 0           context = get_md5_ctx(aTHX_ xclass);
595             }
596 1174           MD5Init(context);
597 1174           XSRETURN(1);
598              
599             void
600             clone(self)
601             SV* self
602             PREINIT:
603 5           MD5_CTX* cont = get_md5_ctx(aTHX_ self);
604 5           const char *myname = sv_reftype(SvRV(self),TRUE);
605             MD5_CTX* context;
606             PPCODE:
607 5           New(55, context, 1, MD5_CTX);
608 5           ST(0) = sv_2mortal(new_md5_ctx(aTHX_ context, myname));
609 5           memcpy(context,cont,sizeof(MD5_CTX));
610 5           XSRETURN(1);
611              
612             void
613             DESTROY(context)
614             MD5_CTX* context
615             CODE:
616 1179           Safefree(context);
617              
618             void
619             add(self, ...)
620             SV* self
621             PREINIT:
622 57462           MD5_CTX* context = get_md5_ctx(aTHX_ self);
623             int i;
624             unsigned char *data;
625             STRLEN len;
626             PPCODE:
627 204748 100         for (i = 1; i < items; i++) {
628 147286           U32 had_utf8 = SvUTF8(ST(i));
629 147286 100         data = (unsigned char *)(SvPVbyte(ST(i), len));
630 147286           MD5Update(context, data, len);
631 147286 50         if (had_utf8) sv_utf8_upgrade(ST(i));
632             }
633 57462           XSRETURN(1); /* self */
634              
635             void
636             addfile(self, fh)
637             SV* self
638             InputStream fh
639             PREINIT:
640 900           MD5_CTX* context = get_md5_ctx(aTHX_ self);
641 900           STRLEN fill = context->bytes_low & 0x3F;
642             #ifdef USE_HEAP_INSTEAD_OF_STACK
643             unsigned char* buffer;
644             #else
645             unsigned char buffer[4096];
646             #endif
647             int n;
648             CODE:
649 900 100         if (fh) {
650             #ifdef USE_HEAP_INSTEAD_OF_STACK
651             New(0, buffer, 4096, unsigned char);
652             assert(buffer);
653             #endif
654 899 50         if (fill) {
655             /* The MD5Update() function is faster if it can work with
656             * complete blocks. This will fill up any buffered block
657             * first.
658             */
659 0           STRLEN missing = 64 - fill;
660 0 0         if ( (n = PerlIO_read(fh, buffer, missing)) > 0)
661 0           MD5Update(context, buffer, n);
662             else
663 0           XSRETURN(1); /* self */
664             }
665              
666             /* Process blocks until EOF or error */
667 4559 100         while ( (n = PerlIO_read(fh, buffer, sizeof(buffer))) > 0) {
668 3660           MD5Update(context, buffer, n);
669             }
670             #ifdef USE_HEAP_INSTEAD_OF_STACK
671             Safefree(buffer);
672             #endif
673 899 50         if (PerlIO_error(fh)) {
674 0           croak("Reading from filehandle failed");
675             }
676             }
677             else {
678 1           croak("No filehandle passed");
679             }
680 899           XSRETURN(1); /* self */
681              
682             void
683             digest(context)
684             MD5_CTX* context
685             ALIAS:
686             Digest::MD5::digest = F_BIN
687             Digest::MD5::hexdigest = F_HEX
688             Digest::MD5::b64digest = F_B64
689             PREINIT:
690             unsigned char digeststr[16];
691             PPCODE:
692 1177           MD5Final(digeststr, context);
693 1177           MD5Init(context); /* In case it is reused */
694 1177           ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
695 1177           XSRETURN(1);
696              
697             void
698             context(ctx, ...)
699             MD5_CTX* ctx
700             PREINIT:
701             char out[16];
702             U32 w;
703             PPCODE:
704 0 0         if (items > 2) {
705             STRLEN len;
706 0 0         unsigned long blocks = SvUV(ST(1));
707 0 0         unsigned char *buf = (unsigned char *)(SvPV(ST(2), len));
708 0           ctx->A = buf[ 0] | (buf[ 1]<<8) | (buf[ 2]<<16) | (buf[ 3]<<24);
709 0           ctx->B = buf[ 4] | (buf[ 5]<<8) | (buf[ 6]<<16) | (buf[ 7]<<24);
710 0           ctx->C = buf[ 8] | (buf[ 9]<<8) | (buf[10]<<16) | (buf[11]<<24);
711 0           ctx->D = buf[12] | (buf[13]<<8) | (buf[14]<<16) | (buf[15]<<24);
712 0           ctx->bytes_low = blocks << 6;
713 0           ctx->bytes_high = blocks >> 26;
714 0 0         if (items == 4) {
715 0 0         buf = (unsigned char *)(SvPV(ST(3), len));
716 0           MD5Update(ctx, buf, len);
717             }
718 0           XSRETURN(1); /* ctx */
719 0 0         } else if (items != 1) {
720 0           XSRETURN(0);
721             }
722              
723 0           w=ctx->A; out[ 0]=(char)w; out[ 1]=(char)(w>>8); out[ 2]=(char)(w>>16); out[ 3]=(char)(w>>24);
724 0           w=ctx->B; out[ 4]=(char)w; out[ 5]=(char)(w>>8); out[ 6]=(char)(w>>16); out[ 7]=(char)(w>>24);
725 0           w=ctx->C; out[ 8]=(char)w; out[ 9]=(char)(w>>8); out[10]=(char)(w>>16); out[11]=(char)(w>>24);
726 0           w=ctx->D; out[12]=(char)w; out[13]=(char)(w>>8); out[14]=(char)(w>>16); out[15]=(char)(w>>24);
727              
728 0 0         EXTEND(SP, 3);
729 0           ST(0) = sv_2mortal(newSVuv(ctx->bytes_high << 26 |
730             ctx->bytes_low >> 6));
731 0           ST(1) = sv_2mortal(newSVpv(out, 16));
732              
733 0 0         if ((ctx->bytes_low & 0x3F) == 0)
734 0           XSRETURN(2);
735              
736 0           ST(2) = sv_2mortal(newSVpv((char *)ctx->buffer,
737             ctx->bytes_low & 0x3F));
738 0           XSRETURN(3);
739              
740             void
741             md5(...)
742             ALIAS:
743             Digest::MD5::md5 = F_BIN
744             Digest::MD5::md5_hex = F_HEX
745             Digest::MD5::md5_base64 = F_B64
746             PREINIT:
747             MD5_CTX ctx;
748             int i;
749             unsigned char *data;
750             STRLEN len;
751             unsigned char digeststr[16];
752             PPCODE:
753 285           MD5Init(&ctx);
754              
755 285 100         if ((PL_dowarn & G_WARN_ON) || ckWARN(WARN_SYNTAX)) {
    100          
756 282           const char *msg = 0;
757 282 100         if (items == 1) {
758 275 50         if (SvROK(ST(0))) {
759 0           SV* sv = SvRV(ST(0));
760             char *name;
761 0 0         if (SvOBJECT(sv) && (name = HvNAME(SvSTASH(sv)))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
762 0 0         && strEQ(name, "Digest::MD5"))
763 0           msg = "probably called as method";
764             else
765 275           msg = "called with reference argument";
766             }
767             }
768 7 50         else if (items > 1) {
769 7 50         data = (unsigned char *)SvPV(ST(0), len);
770 7 100         if (len == 11 && memEQ("Digest::MD5", data, 11)) {
    50          
771 3           msg = "probably called as class method";
772             }
773 4 50         else if (SvROK(ST(0))) {
774 0           SV* sv = SvRV(ST(0));
775             char *name;
776 0 0         if (SvOBJECT(sv) && (name = HvNAME(SvSTASH(sv)))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
777 0 0         && strEQ(name, "Digest::MD5"))
778 0           msg = "probably called as method";
779             }
780             }
781 282 100         if (msg) {
782 3 50         const char *f = (ix == F_BIN) ? "md5" :
    50          
783             (ix == F_HEX) ? "md5_hex" : "md5_base64";
784 3           warn("&Digest::MD5::%s function %s", f, msg);
785             }
786             }
787              
788 57760 100         for (i = 0; i < items; i++) {
789 57476           U32 had_utf8 = SvUTF8(ST(i));
790 57476 100         data = (unsigned char *)(SvPVbyte(ST(i), len));
791 57475           MD5Update(&ctx, data, len);
792 57475 100         if (had_utf8) sv_utf8_upgrade(ST(i));
793             }
794 284           MD5Final(digeststr, &ctx);
795 284           ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
796 284           XSRETURN(1);