File Coverage

MD5.xs
Criterion Covered Total %
statement 0 281 0.0
branch 0 114 0.0
condition n/a
subroutine n/a
pod n/a
total 0 395 0.0


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