This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Update File-Fetch to CPAN version 0.38
[perl5.git] / cpan / Digest-MD5 / MD5.xs
CommitLineData
3357b1b1
JH
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
6fb32e20 10 * turn is derived from the reference implementation in RFC 1321 which
3357b1b1
JH
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
36extern "C" {
37#endif
ee7ea0b1 38#define PERL_NO_GET_CONTEXT /* we want efficiency */
3357b1b1
JH
39#include "EXTERN.h"
40#include "perl.h"
41#include "XSUB.h"
42#ifdef __cplusplus
43}
44#endif
45
0a3486ef
CBW
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)
65static 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
3357b1b1
JH
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
123static void u2s(U32 u, U8* s)
124{
7c436af3
GS
125 *s++ = (U8)(u & 0xFF);
126 *s++ = (U8)((u >> 8) & 0xFF);
127 *s++ = (U8)((u >> 16) & 0xFF);
128 *s = (U8)((u >> 24) & 0xFF);
3357b1b1
JH
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
0a3486ef 137/* This structure keeps the current state of algorithm.
3357b1b1
JH
138 */
139typedef struct {
3357b1b1
JH
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
0a3486ef 146#if defined(USE_ITHREADS) && defined(MGf_DUP)
62d37bf0
FR
147STATIC 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
158STATIC 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
3357b1b1
JH
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 */
27da23d5 185static const unsigned char PADDING[64] = {
3357b1b1
JH
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 */
124f80e2 212#define F(x, y, z) ((((x) & ((y) ^ (z))) ^ (z)))
3357b1b1
JH
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
253static void
254MD5Init(MD5_CTX *ctx)
255{
256 /* Start state */
257 ctx->A = 0x67452301;
258 ctx->B = 0xefcdab89;
259 ctx->C = 0x98badcfe;
260 ctx->D = 0x10325476;
261
262 /* message length */
263 ctx->bytes_low = ctx->bytes_high = 0;
264}
265
266
267static void
268MD5Transform(MD5_CTX* ctx, const U8* buf, STRLEN blocks)
269{
516a5887 270#ifdef MD5_DEBUG
3357b1b1 271 static int tcount = 0;
516a5887 272#endif
3357b1b1
JH
273
274 U32 A = ctx->A;
275 U32 B = ctx->B;
276 U32 C = ctx->C;
277 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 FF (a, b, c, d, S11, 0xd76aa478); /* 1 */
321 FF (d, a, b, c, S12, 0xe8c7b756); /* 2 */
322 FF (c, d, a, b, S13, 0x242070db); /* 3 */
323 FF (b, c, d, a, S14, 0xc1bdceee); /* 4 */
324 FF (a, b, c, d, S11, 0xf57c0faf); /* 5 */
325 FF (d, a, b, c, S12, 0x4787c62a); /* 6 */
326 FF (c, d, a, b, S13, 0xa8304613); /* 7 */
327 FF (b, c, d, a, S14, 0xfd469501); /* 8 */
328 FF (a, b, c, d, S11, 0x698098d8); /* 9 */
329 FF (d, a, b, c, S12, 0x8b44f7af); /* 10 */
330 FF (c, d, a, b, S13, 0xffff5bb1); /* 11 */
331 FF (b, c, d, a, S14, 0x895cd7be); /* 12 */
332 FF (a, b, c, d, S11, 0x6b901122); /* 13 */
333 FF (d, a, b, c, S12, 0xfd987193); /* 14 */
334 FF (c, d, a, b, S13, 0xa679438e); /* 15 */
335 FF (b, c, d, a, S14, 0x49b40821); /* 16 */
336
337 /* Round 2 */
338 GG (a, b, c, d, 1, S21, 0xf61e2562); /* 17 */
339 GG (d, a, b, c, 6, S22, 0xc040b340); /* 18 */
340 GG (c, d, a, b, 11, S23, 0x265e5a51); /* 19 */
341 GG (b, c, d, a, 0, S24, 0xe9b6c7aa); /* 20 */
342 GG (a, b, c, d, 5, S21, 0xd62f105d); /* 21 */
343 GG (d, a, b, c, 10, S22, 0x2441453); /* 22 */
344 GG (c, d, a, b, 15, S23, 0xd8a1e681); /* 23 */
345 GG (b, c, d, a, 4, S24, 0xe7d3fbc8); /* 24 */
346 GG (a, b, c, d, 9, S21, 0x21e1cde6); /* 25 */
347 GG (d, a, b, c, 14, S22, 0xc33707d6); /* 26 */
348 GG (c, d, a, b, 3, S23, 0xf4d50d87); /* 27 */
349 GG (b, c, d, a, 8, S24, 0x455a14ed); /* 28 */
350 GG (a, b, c, d, 13, S21, 0xa9e3e905); /* 29 */
351 GG (d, a, b, c, 2, S22, 0xfcefa3f8); /* 30 */
352 GG (c, d, a, b, 7, S23, 0x676f02d9); /* 31 */
353 GG (b, c, d, a, 12, S24, 0x8d2a4c8a); /* 32 */
354
355 /* Round 3 */
356 HH (a, b, c, d, 5, S31, 0xfffa3942); /* 33 */
357 HH (d, a, b, c, 8, S32, 0x8771f681); /* 34 */
358 HH (c, d, a, b, 11, S33, 0x6d9d6122); /* 35 */
359 HH (b, c, d, a, 14, S34, 0xfde5380c); /* 36 */
360 HH (a, b, c, d, 1, S31, 0xa4beea44); /* 37 */
361 HH (d, a, b, c, 4, S32, 0x4bdecfa9); /* 38 */
362 HH (c, d, a, b, 7, S33, 0xf6bb4b60); /* 39 */
363 HH (b, c, d, a, 10, S34, 0xbebfbc70); /* 40 */
364 HH (a, b, c, d, 13, S31, 0x289b7ec6); /* 41 */
365 HH (d, a, b, c, 0, S32, 0xeaa127fa); /* 42 */
366 HH (c, d, a, b, 3, S33, 0xd4ef3085); /* 43 */
367 HH (b, c, d, a, 6, S34, 0x4881d05); /* 44 */
368 HH (a, b, c, d, 9, S31, 0xd9d4d039); /* 45 */
369 HH (d, a, b, c, 12, S32, 0xe6db99e5); /* 46 */
370 HH (c, d, a, b, 15, S33, 0x1fa27cf8); /* 47 */
371 HH (b, c, d, a, 2, S34, 0xc4ac5665); /* 48 */
372
373 /* Round 4 */
374 II (a, b, c, d, 0, S41, 0xf4292244); /* 49 */
375 II (d, a, b, c, 7, S42, 0x432aff97); /* 50 */
376 II (c, d, a, b, 14, S43, 0xab9423a7); /* 51 */
377 II (b, c, d, a, 5, S44, 0xfc93a039); /* 52 */
378 II (a, b, c, d, 12, S41, 0x655b59c3); /* 53 */
379 II (d, a, b, c, 3, S42, 0x8f0ccc92); /* 54 */
380 II (c, d, a, b, 10, S43, 0xffeff47d); /* 55 */
381 II (b, c, d, a, 1, S44, 0x85845dd1); /* 56 */
382 II (a, b, c, d, 8, S41, 0x6fa87e4f); /* 57 */
383 II (d, a, b, c, 15, S42, 0xfe2ce6e0); /* 58 */
384 II (c, d, a, b, 6, S43, 0xa3014314); /* 59 */
385 II (b, c, d, a, 13, S44, 0x4e0811a1); /* 60 */
386 II (a, b, c, d, 4, S41, 0xf7537e82); /* 61 */
387 II (d, a, b, c, 11, S42, 0xbd3af235); /* 62 */
388 II (c, d, a, b, 2, S43, 0x2ad7d2bb); /* 63 */
389 II (b, c, d, a, 9, S44, 0xeb86d391); /* 64 */
390
391 A += a; TRUNC32(A);
392 B += b; TRUNC32(B);
393 C += c; TRUNC32(C);
394 D += d; TRUNC32(D);
395
396 } while (--blocks);
397 ctx->A = A;
398 ctx->B = B;
399 ctx->C = C;
400 ctx->D = D;
401}
402
403
404#ifdef MD5_DEBUG
405static char*
406ctx_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
417static void
418MD5Update(MD5_CTX* ctx, const U8* buf, STRLEN len)
419{
420 STRLEN blocks;
421 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 ctx->bytes_low += len;
430 if (ctx->bytes_low < len) /* wrap around */
431 ctx->bytes_high++;
432
433 if (fill) {
434 STRLEN missing = 64 - fill;
435 if (len < missing) {
436 Copy(buf, ctx->buffer + fill, len, U8);
437 return;
438 }
439 Copy(buf, ctx->buffer + fill, missing, U8);
440 MD5Transform(ctx, ctx->buffer, 1);
441 buf += missing;
442 len -= missing;
443 }
444
445 blocks = len >> 6;
446 if (blocks)
447 MD5Transform(ctx, buf, blocks);
448 if ( (len &= 0x3F)) {
449 Copy(buf + (blocks << 6), ctx->buffer, len, U8);
450 }
451}
452
453
454static void
455MD5Final(U8* digest, MD5_CTX *ctx)
456{
457 STRLEN fill = ctx->bytes_low & 0x3F;
458 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 Copy(PADDING, ctx->buffer + fill, padlen, U8);
464 fill += padlen;
465
466 bits_low = ctx->bytes_low << 3;
467 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 u2s(bits_low, ctx->buffer + fill); fill += 4;
473 u2s(bits_high, ctx->buffer + fill); fill += 4;
474#endif
475
476 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 u2s(ctx->A, digest);
488 u2s(ctx->B, digest+4);
489 u2s(ctx->C, digest+8);
490 u2s(ctx->D, digest+12);
491#endif
492}
493
494#ifndef INT2PTR
495#define INT2PTR(any,d) (any)(d)
496#endif
497
ee7ea0b1 498static MD5_CTX* get_md5_ctx(pTHX_ SV* sv)
3357b1b1 499{
62d37bf0
FR
500 MAGIC *mg;
501
502 if (!sv_derived_from(sv, "Digest::MD5"))
503 croak("Not a reference to a Digest::MD5 object");
504
505 for (mg = SvMAGIC(SvRV(sv)); mg; mg = mg->mg_moremagic) {
506 if (mg->mg_type == PERL_MAGIC_ext && mg->mg_virtual == &vtbl_md5) {
507 return (MD5_CTX *)mg->mg_ptr;
508 }
3357b1b1 509 }
62d37bf0
FR
510
511 croak("Failed to get MD5_CTX pointer");
3357b1b1
JH
512 return (MD5_CTX*)0; /* some compilers insist on a return value */
513}
514
62d37bf0
FR
515static SV * new_md5_ctx(pTHX_ MD5_CTX *context, const char *klass)
516{
517 SV *sv = newSV(0);
518 SV *obj = newRV_noinc(sv);
519#ifdef USE_ITHREADS
520 MAGIC *mg;
521#endif
522
523 sv_bless(obj, gv_stashpv(klass, 0));
524
525#ifdef USE_ITHREADS
526 mg =
527#endif
5ec56f72 528 sv_magicext(sv, NULL, PERL_MAGIC_ext, &vtbl_md5, (const char *)context, 0);
62d37bf0 529
0a3486ef 530#if defined(USE_ITHREADS) && defined(MGf_DUP)
62d37bf0
FR
531 mg->mg_flags |= MGf_DUP;
532#endif
533
534 return obj;
535}
536
3357b1b1
JH
537
538static char* hex_16(const unsigned char* from, char* to)
539{
27da23d5 540 static const char hexdigits[] = "0123456789abcdef";
3357b1b1
JH
541 const unsigned char *end = from + 16;
542 char *d = to;
543
544 while (from < end) {
545 *d++ = hexdigits[(*from >> 4)];
546 *d++ = hexdigits[(*from & 0x0F)];
547 from++;
548 }
549 *d = '\0';
550 return to;
551}
552
553static char* base64_16(const unsigned char* from, char* to)
554{
27da23d5 555 static const char base64[] =
3357b1b1
JH
556 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
557 const unsigned char *end = from + 16;
558 unsigned char c1, c2, c3;
559 char *d = to;
560
561 while (1) {
562 c1 = *from++;
563 *d++ = base64[c1>>2];
564 if (from == end) {
565 *d++ = base64[(c1 & 0x3) << 4];
566 break;
567 }
568 c2 = *from++;
569 c3 = *from++;
570 *d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
571 *d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
572 *d++ = base64[c3 & 0x3F];
573 }
574 *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
ee7ea0b1 583static SV* make_mortal_sv(pTHX_ const unsigned char *src, int type)
3357b1b1
JH
584{
585 STRLEN len;
586 char result[33];
587 char *ret;
588
589 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 break;
598 case F_B64:
599 ret = base64_16(src, result);
600 len = 22;
601 break;
602 default:
0a3486ef 603 croak("Bad conversion type (%d)", type);
3357b1b1
JH
604 break;
605 }
606 return sv_2mortal(newSVpv(ret,len));
607}
608
609
610/********************************************************************/
611
612typedef PerlIO* InputStream;
613
614MODULE = Digest::MD5 PACKAGE = Digest::MD5
615
616PROTOTYPES: DISABLE
617
618void
619new(xclass)
620 SV* xclass
621 PREINIT:
622 MD5_CTX* context;
623 PPCODE:
624 if (!SvROK(xclass)) {
625 STRLEN my_na;
62d37bf0 626 const char *sclass = SvPV(xclass, my_na);
3357b1b1 627 New(55, context, 1, MD5_CTX);
62d37bf0 628 ST(0) = sv_2mortal(new_md5_ctx(aTHX_ context, sclass));
3357b1b1 629 } else {
ee7ea0b1 630 context = get_md5_ctx(aTHX_ xclass);
3357b1b1 631 }
62d37bf0 632 MD5Init(context);
3357b1b1
JH
633 XSRETURN(1);
634
635void
f62a1bde
JH
636clone(self)
637 SV* self
638 PREINIT:
ee7ea0b1 639 MD5_CTX* cont = get_md5_ctx(aTHX_ self);
b277e9c1 640 const char *myname = sv_reftype(SvRV(self),TRUE);
f62a1bde
JH
641 MD5_CTX* context;
642 PPCODE:
f62a1bde 643 New(55, context, 1, MD5_CTX);
62d37bf0 644 ST(0) = sv_2mortal(new_md5_ctx(aTHX_ context, myname));
f62a1bde
JH
645 memcpy(context,cont,sizeof(MD5_CTX));
646 XSRETURN(1);
647
648void
3357b1b1
JH
649DESTROY(context)
650 MD5_CTX* context
651 CODE:
652 Safefree(context);
653
654void
655add(self, ...)
656 SV* self
657 PREINIT:
ee7ea0b1 658 MD5_CTX* context = get_md5_ctx(aTHX_ self);
3357b1b1
JH
659 int i;
660 unsigned char *data;
661 STRLEN len;
662 PPCODE:
663 for (i = 1; i < items; i++) {
62d37bf0 664 U32 had_utf8 = SvUTF8(ST(i));
844f0213 665 data = (unsigned char *)(SvPVbyte(ST(i), len));
3357b1b1 666 MD5Update(context, data, len);
62d37bf0 667 if (had_utf8) sv_utf8_upgrade(ST(i));
3357b1b1
JH
668 }
669 XSRETURN(1); /* self */
670
671void
672addfile(self, fh)
673 SV* self
674 InputStream fh
675 PREINIT:
ee7ea0b1 676 MD5_CTX* context = get_md5_ctx(aTHX_ self);
3357b1b1 677 STRLEN fill = context->bytes_low & 0x3F;
27da23d5
JH
678#ifdef USE_HEAP_INSTEAD_OF_STACK
679 unsigned char* buffer;
680#else
3357b1b1 681 unsigned char buffer[4096];
27da23d5 682#endif
263df5f1 683 int n;
3357b1b1
JH
684 CODE:
685 if (fh) {
27da23d5
JH
686#ifdef USE_HEAP_INSTEAD_OF_STACK
687 New(0, buffer, 4096, unsigned char);
688 assert(buffer);
689#endif
3357b1b1
JH
690 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 STRLEN missing = 64 - fill;
1c9948bf 696 if ( (n = PerlIO_read(fh, buffer, missing)) > 0)
3357b1b1 697 MD5Update(context, buffer, n);
ef3aad62 698 else
3357b1b1
JH
699 XSRETURN(1); /* self */
700 }
701
ac70dec1 702 /* Process blocks until EOF or error */
1c9948bf 703 while ( (n = PerlIO_read(fh, buffer, sizeof(buffer))) > 0) {
3357b1b1
JH
704 MD5Update(context, buffer, n);
705 }
27da23d5
JH
706#ifdef USE_HEAP_INSTEAD_OF_STACK
707 Safefree(buffer);
708#endif
263df5f1 709 if (PerlIO_error(fh)) {
ac70dec1
JH
710 croak("Reading from filehandle failed");
711 }
712 }
713 else {
714 croak("No filehandle passed");
3357b1b1
JH
715 }
716 XSRETURN(1); /* self */
717
718void
719digest(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 MD5Final(digeststr, context);
729 MD5Init(context); /* In case it is reused */
ee7ea0b1 730 ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
3357b1b1
JH
731 XSRETURN(1);
732
733void
734md5(...)
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);
5a046520 747
62d37bf0 748 if (PL_dowarn & G_WARN_ON) {
326fafaa 749 const char *msg = 0;
5a046520
JH
750 if (items == 1) {
751 if (SvROK(ST(0))) {
752 SV* sv = SvRV(ST(0));
753 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 else if (items > 1) {
62d37bf0 760 data = (unsigned char *)SvPV(ST(0), len);
5a046520
JH
761 if (len == 11 && memEQ("Digest::MD5", data, 11)) {
762 msg = "probably called as class method";
763 }
47a7661d
GA
764 else if (SvROK(ST(0))) {
765 SV* sv = SvRV(ST(0));
766 if (SvOBJECT(sv) && strEQ(HvNAME(SvSTASH(sv)), "Digest::MD5"))
767 msg = "probably called as method";
768 }
5a046520
JH
769 }
770 if (msg) {
8a722a80
JH
771 const char *f = (ix == F_BIN) ? "md5" :
772 (ix == F_HEX) ? "md5_hex" : "md5_base64";
5a046520
JH
773 warn("&Digest::MD5::%s function %s", f, msg);
774 }
db2a39d5 775 }
5a046520 776
3357b1b1 777 for (i = 0; i < items; i++) {
62d37bf0 778 U32 had_utf8 = SvUTF8(ST(i));
844f0213 779 data = (unsigned char *)(SvPVbyte(ST(i), len));
3357b1b1 780 MD5Update(&ctx, data, len);
62d37bf0 781 if (had_utf8) sv_utf8_upgrade(ST(i));
3357b1b1
JH
782 }
783 MD5Final(digeststr, &ctx);
ee7ea0b1 784 ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
3357b1b1 785 XSRETURN(1);