File Coverage

cpan/Digest-MD5/MD5.xs
Criterion Covered Total %
statement 200 216 92.6
branch n/a
condition n/a
subroutine n/a
total 200 216 92.6


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