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