This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate Digest-1.00 and Digest-MD5-2.13, from Gisle Aas.
[perl5.git] / ext / Digest / MD5 / MD5.xs
CommitLineData
3357b1b1
JH
1/* $Id: MD5.xs,v 1.26 2000/09/18 14:27:44 gisle Exp $ */
2
3/*
4 * This library is free software; you can redistribute it and/or
5 * modify it under the same terms as Perl itself.
6 *
7 * Copyright 1998-2000 Gisle Aas.
8 * Copyright 1995-1996 Neil Winton.
9 * Copyright 1991-1992 RSA Data Security, Inc.
10 *
11 * This code is derived from Neil Winton's MD5-1.7 Perl module, which in
12 * turn is derived from the reference implementation in RFC 1231 which
13 * comes with this message:
14 *
15 * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
16 * rights reserved.
17 *
18 * License to copy and use this software is granted provided that it
19 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
20 * Algorithm" in all material mentioning or referencing this software
21 * or this function.
22 *
23 * License is also granted to make and use derivative works provided
24 * that such works are identified as "derived from the RSA Data
25 * Security, Inc. MD5 Message-Digest Algorithm" in all material
26 * mentioning or referencing the derived work.
27 *
28 * RSA Data Security, Inc. makes no representations concerning either
29 * the merchantability of this software or the suitability of this
30 * software for any particular purpose. It is provided "as is"
31 * without express or implied warranty of any kind.
32 *
33 * These notices must be retained in any copies of any part of this
34 * documentation and/or software.
35 */
36
37#ifdef __cplusplus
38extern "C" {
39#endif
40#include "EXTERN.h"
41#include "perl.h"
42#include "XSUB.h"
43#ifdef __cplusplus
44}
45#endif
46
47/*#define MD5_DEBUG /**/
48
49/* Perl does not guarantee that U32 is exactly 32 bits. Some system
50 * has no integral type with exactly 32 bits. For instance, A Cray has
51 * short, int and long all at 64 bits so we need to apply this macro
52 * to reduce U32 values to 32 bits at appropriate places. If U32
53 * really does have 32 bits then this is a no-op.
54 */
55#if BYTEORDER > 0x4321 || defined(TRUNCATE_U32)
56 #define TO32(x) ((x) & 0xFFFFffff)
57 #define TRUNC32(x) ((x) &= 0xFFFFffff)
58#else
59 #define TO32(x) (x)
60 #define TRUNC32(x) /*nothing*/
61#endif
62
63/* The MD5 algorithm is defined in terms of little endian 32-bit
64 * values. The following macros (and functions) allow us to convert
65 * between native integers and such values.
66 */
67#undef BYTESWAP
68#ifndef U32_ALIGNMENT_REQUIRED
69 #if BYTEORDER == 0x1234 /* 32-bit little endian */
70 #define BYTESWAP(x) (x) /* no-op */
71
72 #elif BYTEORDER == 0x4321 /* 32-bit big endian */
73 #define BYTESWAP(x) ((((x)&0xFF)<<24) \
74 |(((x)>>24)&0xFF) \
75 |(((x)&0x0000FF00)<<8) \
76 |(((x)&0x00FF0000)>>8) )
77 #endif
78#endif
79
80#ifndef BYTESWAP
81static void u2s(U32 u, U8* s)
82{
83 *s++ = u & 0xFF;
84 *s++ = (u >> 8) & 0xFF;
85 *s++ = (u >> 16) & 0xFF;
86 *s = (u >> 24) & 0xFF;
87}
88
89#define s2u(s,u) ((u) = (U32)(*s) | \
90 ((U32)(*(s+1)) << 8) | \
91 ((U32)(*(s+2)) << 16) | \
92 ((U32)(*(s+3)) << 24))
93#endif
94
95#define MD5_CTX_SIGNATURE 200003165
96
97/* This stucture keeps the current state of algorithm.
98 */
99typedef struct {
100 U32 signature; /* safer cast in get_md5_ctx() */
101 U32 A, B, C, D; /* current digest */
102 U32 bytes_low; /* counts bytes in message */
103 U32 bytes_high; /* turn it into a 64-bit counter */
104 U8 buffer[128]; /* collect complete 64 byte blocks */
105} MD5_CTX;
106
107
108/* Padding is added at the end of the message in order to fill a
109 * complete 64 byte block (- 8 bytes for the message length). The
110 * padding is also the reason the buffer in MD5_CTX have to be
111 * 128 bytes.
112 */
113static unsigned char PADDING[64] = {
114 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
117};
118
119/* Constants for MD5Transform routine.
120 */
121#define S11 7
122#define S12 12
123#define S13 17
124#define S14 22
125#define S21 5
126#define S22 9
127#define S23 14
128#define S24 20
129#define S31 4
130#define S32 11
131#define S33 16
132#define S34 23
133#define S41 6
134#define S42 10
135#define S43 15
136#define S44 21
137
138/* F, G, H and I are basic MD5 functions.
139 */
140#define F(x, y, z) (((x) & ((y) ^ (z)) ^ (z)))
141#define G(x, y, z) F(z, x, y)
142#define H(x, y, z) ((x) ^ (y) ^ (z))
143#define I(x, y, z) ((y) ^ ((x) | (~z)))
144
145/* ROTATE_LEFT rotates x left n bits.
146 */
147#define ROTATE_LEFT(x, n) (((x) << (n) | ((x) >> (32-(n)))))
148
149/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
150 * Rotation is separate from addition to prevent recomputation.
151 */
152#define FF(a, b, c, d, s, ac) \
153 (a) += F ((b), (c), (d)) + (NEXTx) + (U32)(ac); \
154 TRUNC32((a)); \
155 (a) = ROTATE_LEFT ((a), (s)); \
156 (a) += (b); \
157 TRUNC32((a));
158
159#define GG(a, b, c, d, x, s, ac) \
160 (a) += G ((b), (c), (d)) + X[x] + (U32)(ac); \
161 TRUNC32((a)); \
162 (a) = ROTATE_LEFT ((a), (s)); \
163 (a) += (b); \
164 TRUNC32((a));
165
166#define HH(a, b, c, d, x, s, ac) \
167 (a) += H ((b), (c), (d)) + X[x] + (U32)(ac); \
168 TRUNC32((a)); \
169 (a) = ROTATE_LEFT ((a), (s)); \
170 (a) += (b); \
171 TRUNC32((a));
172
173#define II(a, b, c, d, x, s, ac) \
174 (a) += I ((b), (c), (d)) + X[x] + (U32)(ac); \
175 TRUNC32((a)); \
176 (a) = ROTATE_LEFT ((a), (s)); \
177 (a) += (b); \
178 TRUNC32((a));
179
180
181static void
182MD5Init(MD5_CTX *ctx)
183{
184 /* Start state */
185 ctx->A = 0x67452301;
186 ctx->B = 0xefcdab89;
187 ctx->C = 0x98badcfe;
188 ctx->D = 0x10325476;
189
190 /* message length */
191 ctx->bytes_low = ctx->bytes_high = 0;
192}
193
194
195static void
196MD5Transform(MD5_CTX* ctx, const U8* buf, STRLEN blocks)
197{
198 static int tcount = 0;
199
200 U32 A = ctx->A;
201 U32 B = ctx->B;
202 U32 C = ctx->C;
203 U32 D = ctx->D;
204
205#ifndef U32_ALIGNMENT_REQUIRED
206 const U32 *x = (U32*)buf; /* really just type casting */
207#endif
208
209 do {
210 U32 a = A;
211 U32 b = B;
212 U32 c = C;
213 U32 d = D;
214
215#if BYTEORDER == 0x1234 && !defined(U32_ALIGNMENT_REQUIRED)
216 const U32 *X = x;
217 #define NEXTx (*x++)
218#else
219 U32 X[16]; /* converted values, used in round 2-4 */
220 U32 *uptr = X;
221 U32 tmp;
222 #ifdef BYTESWAP
223 #define NEXTx (tmp=*x++, *uptr++ = BYTESWAP(tmp))
224 #else
225 #define NEXTx (s2u(buf,tmp), buf += 4, *uptr++ = tmp)
226 #endif
227#endif
228
229#ifdef MD5_DEBUG
230 if (buf == ctx->buffer)
231 fprintf(stderr,"%5d: Transform ctx->buffer", ++tcount);
232 else
233 fprintf(stderr,"%5d: Transform %p (%d)", ++tcount, buf, blocks);
234
235 {
236 int i;
237 fprintf(stderr,"[");
238 for (i = 0; i < 16; i++) {
239 fprintf(stderr,"%x,", x[i]);
240 }
241 fprintf(stderr,"]\n");
242 }
243#endif
244
245 /* Round 1 */
246 FF (a, b, c, d, S11, 0xd76aa478); /* 1 */
247 FF (d, a, b, c, S12, 0xe8c7b756); /* 2 */
248 FF (c, d, a, b, S13, 0x242070db); /* 3 */
249 FF (b, c, d, a, S14, 0xc1bdceee); /* 4 */
250 FF (a, b, c, d, S11, 0xf57c0faf); /* 5 */
251 FF (d, a, b, c, S12, 0x4787c62a); /* 6 */
252 FF (c, d, a, b, S13, 0xa8304613); /* 7 */
253 FF (b, c, d, a, S14, 0xfd469501); /* 8 */
254 FF (a, b, c, d, S11, 0x698098d8); /* 9 */
255 FF (d, a, b, c, S12, 0x8b44f7af); /* 10 */
256 FF (c, d, a, b, S13, 0xffff5bb1); /* 11 */
257 FF (b, c, d, a, S14, 0x895cd7be); /* 12 */
258 FF (a, b, c, d, S11, 0x6b901122); /* 13 */
259 FF (d, a, b, c, S12, 0xfd987193); /* 14 */
260 FF (c, d, a, b, S13, 0xa679438e); /* 15 */
261 FF (b, c, d, a, S14, 0x49b40821); /* 16 */
262
263 /* Round 2 */
264 GG (a, b, c, d, 1, S21, 0xf61e2562); /* 17 */
265 GG (d, a, b, c, 6, S22, 0xc040b340); /* 18 */
266 GG (c, d, a, b, 11, S23, 0x265e5a51); /* 19 */
267 GG (b, c, d, a, 0, S24, 0xe9b6c7aa); /* 20 */
268 GG (a, b, c, d, 5, S21, 0xd62f105d); /* 21 */
269 GG (d, a, b, c, 10, S22, 0x2441453); /* 22 */
270 GG (c, d, a, b, 15, S23, 0xd8a1e681); /* 23 */
271 GG (b, c, d, a, 4, S24, 0xe7d3fbc8); /* 24 */
272 GG (a, b, c, d, 9, S21, 0x21e1cde6); /* 25 */
273 GG (d, a, b, c, 14, S22, 0xc33707d6); /* 26 */
274 GG (c, d, a, b, 3, S23, 0xf4d50d87); /* 27 */
275 GG (b, c, d, a, 8, S24, 0x455a14ed); /* 28 */
276 GG (a, b, c, d, 13, S21, 0xa9e3e905); /* 29 */
277 GG (d, a, b, c, 2, S22, 0xfcefa3f8); /* 30 */
278 GG (c, d, a, b, 7, S23, 0x676f02d9); /* 31 */
279 GG (b, c, d, a, 12, S24, 0x8d2a4c8a); /* 32 */
280
281 /* Round 3 */
282 HH (a, b, c, d, 5, S31, 0xfffa3942); /* 33 */
283 HH (d, a, b, c, 8, S32, 0x8771f681); /* 34 */
284 HH (c, d, a, b, 11, S33, 0x6d9d6122); /* 35 */
285 HH (b, c, d, a, 14, S34, 0xfde5380c); /* 36 */
286 HH (a, b, c, d, 1, S31, 0xa4beea44); /* 37 */
287 HH (d, a, b, c, 4, S32, 0x4bdecfa9); /* 38 */
288 HH (c, d, a, b, 7, S33, 0xf6bb4b60); /* 39 */
289 HH (b, c, d, a, 10, S34, 0xbebfbc70); /* 40 */
290 HH (a, b, c, d, 13, S31, 0x289b7ec6); /* 41 */
291 HH (d, a, b, c, 0, S32, 0xeaa127fa); /* 42 */
292 HH (c, d, a, b, 3, S33, 0xd4ef3085); /* 43 */
293 HH (b, c, d, a, 6, S34, 0x4881d05); /* 44 */
294 HH (a, b, c, d, 9, S31, 0xd9d4d039); /* 45 */
295 HH (d, a, b, c, 12, S32, 0xe6db99e5); /* 46 */
296 HH (c, d, a, b, 15, S33, 0x1fa27cf8); /* 47 */
297 HH (b, c, d, a, 2, S34, 0xc4ac5665); /* 48 */
298
299 /* Round 4 */
300 II (a, b, c, d, 0, S41, 0xf4292244); /* 49 */
301 II (d, a, b, c, 7, S42, 0x432aff97); /* 50 */
302 II (c, d, a, b, 14, S43, 0xab9423a7); /* 51 */
303 II (b, c, d, a, 5, S44, 0xfc93a039); /* 52 */
304 II (a, b, c, d, 12, S41, 0x655b59c3); /* 53 */
305 II (d, a, b, c, 3, S42, 0x8f0ccc92); /* 54 */
306 II (c, d, a, b, 10, S43, 0xffeff47d); /* 55 */
307 II (b, c, d, a, 1, S44, 0x85845dd1); /* 56 */
308 II (a, b, c, d, 8, S41, 0x6fa87e4f); /* 57 */
309 II (d, a, b, c, 15, S42, 0xfe2ce6e0); /* 58 */
310 II (c, d, a, b, 6, S43, 0xa3014314); /* 59 */
311 II (b, c, d, a, 13, S44, 0x4e0811a1); /* 60 */
312 II (a, b, c, d, 4, S41, 0xf7537e82); /* 61 */
313 II (d, a, b, c, 11, S42, 0xbd3af235); /* 62 */
314 II (c, d, a, b, 2, S43, 0x2ad7d2bb); /* 63 */
315 II (b, c, d, a, 9, S44, 0xeb86d391); /* 64 */
316
317 A += a; TRUNC32(A);
318 B += b; TRUNC32(B);
319 C += c; TRUNC32(C);
320 D += d; TRUNC32(D);
321
322 } while (--blocks);
323 ctx->A = A;
324 ctx->B = B;
325 ctx->C = C;
326 ctx->D = D;
327}
328
329
330#ifdef MD5_DEBUG
331static char*
332ctx_dump(MD5_CTX* ctx)
333{
334 static char buf[1024];
335 sprintf(buf, "{A=%x,B=%x,C=%x,D=%x,%d,%d(%d)}",
336 ctx->A, ctx->B, ctx->C, ctx->D,
337 ctx->bytes_low, ctx->bytes_high, (ctx->bytes_low&0x3F));
338 return buf;
339}
340#endif
341
342
343static void
344MD5Update(MD5_CTX* ctx, const U8* buf, STRLEN len)
345{
346 STRLEN blocks;
347 STRLEN fill = ctx->bytes_low & 0x3F;
348
349#ifdef MD5_DEBUG
350 static int ucount = 0;
351 fprintf(stderr,"%5i: Update(%s, %p, %d)\n", ++ucount, ctx_dump(ctx),
352 buf, len);
353#endif
354
355 ctx->bytes_low += len;
356 if (ctx->bytes_low < len) /* wrap around */
357 ctx->bytes_high++;
358
359 if (fill) {
360 STRLEN missing = 64 - fill;
361 if (len < missing) {
362 Copy(buf, ctx->buffer + fill, len, U8);
363 return;
364 }
365 Copy(buf, ctx->buffer + fill, missing, U8);
366 MD5Transform(ctx, ctx->buffer, 1);
367 buf += missing;
368 len -= missing;
369 }
370
371 blocks = len >> 6;
372 if (blocks)
373 MD5Transform(ctx, buf, blocks);
374 if ( (len &= 0x3F)) {
375 Copy(buf + (blocks << 6), ctx->buffer, len, U8);
376 }
377}
378
379
380static void
381MD5Final(U8* digest, MD5_CTX *ctx)
382{
383 STRLEN fill = ctx->bytes_low & 0x3F;
384 STRLEN padlen = (fill < 56 ? 56 : 120) - fill;
385 U32 bits_low, bits_high;
386#ifdef MD5_DEBUG
387 fprintf(stderr," Final: %s\n", ctx_dump(ctx));
388#endif
389 Copy(PADDING, ctx->buffer + fill, padlen, U8);
390 fill += padlen;
391
392 bits_low = ctx->bytes_low << 3;
393 bits_high = (ctx->bytes_high << 3) | (ctx->bytes_low >> 29);
394#ifdef BYTESWAP
395 *(U32*)(ctx->buffer + fill) = BYTESWAP(bits_low); fill += 4;
396 *(U32*)(ctx->buffer + fill) = BYTESWAP(bits_high); fill += 4;
397#else
398 u2s(bits_low, ctx->buffer + fill); fill += 4;
399 u2s(bits_high, ctx->buffer + fill); fill += 4;
400#endif
401
402 MD5Transform(ctx, ctx->buffer, fill >> 6);
403#ifdef MD5_DEBUG
404 fprintf(stderr," Result: %s\n", ctx_dump(ctx));
405#endif
406
407#ifdef BYTESWAP
408 *(U32*)digest = BYTESWAP(ctx->A); digest += 4;
409 *(U32*)digest = BYTESWAP(ctx->B); digest += 4;
410 *(U32*)digest = BYTESWAP(ctx->C); digest += 4;
411 *(U32*)digest = BYTESWAP(ctx->D);
412#else
413 u2s(ctx->A, digest);
414 u2s(ctx->B, digest+4);
415 u2s(ctx->C, digest+8);
416 u2s(ctx->D, digest+12);
417#endif
418}
419
420#ifndef INT2PTR
421#define INT2PTR(any,d) (any)(d)
422#endif
423
424static MD5_CTX* get_md5_ctx(SV* sv)
425{
426 if (SvROK(sv)) {
427 sv = SvRV(sv);
428 if (SvIOK(sv)) {
429 MD5_CTX* ctx = INT2PTR(MD5_CTX*, SvIV(sv));
430 if (ctx && ctx->signature == MD5_CTX_SIGNATURE) {
431 return ctx;
432 }
433 }
434 }
435 croak("Not a reference to a Digest::MD5 object");
436 return (MD5_CTX*)0; /* some compilers insist on a return value */
437}
438
439
440static char* hex_16(const unsigned char* from, char* to)
441{
442 static char *hexdigits = "0123456789abcdef";
443 const unsigned char *end = from + 16;
444 char *d = to;
445
446 while (from < end) {
447 *d++ = hexdigits[(*from >> 4)];
448 *d++ = hexdigits[(*from & 0x0F)];
449 from++;
450 }
451 *d = '\0';
452 return to;
453}
454
455static char* base64_16(const unsigned char* from, char* to)
456{
457 static char* base64 =
458 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
459 const unsigned char *end = from + 16;
460 unsigned char c1, c2, c3;
461 char *d = to;
462
463 while (1) {
464 c1 = *from++;
465 *d++ = base64[c1>>2];
466 if (from == end) {
467 *d++ = base64[(c1 & 0x3) << 4];
468 break;
469 }
470 c2 = *from++;
471 c3 = *from++;
472 *d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
473 *d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
474 *d++ = base64[c3 & 0x3F];
475 }
476 *d = '\0';
477 return to;
478}
479
480/* Formats */
481#define F_BIN 0
482#define F_HEX 1
483#define F_B64 2
484
485static SV* make_mortal_sv(const unsigned char *src, int type)
486{
487 STRLEN len;
488 char result[33];
489 char *ret;
490
491 switch (type) {
492 case F_BIN:
493 ret = (char*)src;
494 len = 16;
495 break;
496 case F_HEX:
497 ret = hex_16(src, result);
498 len = 32;
499 break;
500 case F_B64:
501 ret = base64_16(src, result);
502 len = 22;
503 break;
504 default:
505 croak("Bad convertion type (%d)", type);
506 break;
507 }
508 return sv_2mortal(newSVpv(ret,len));
509}
510
511
512/********************************************************************/
513
514typedef PerlIO* InputStream;
515
516MODULE = Digest::MD5 PACKAGE = Digest::MD5
517
518PROTOTYPES: DISABLE
519
520void
521new(xclass)
522 SV* xclass
523 PREINIT:
524 MD5_CTX* context;
525 PPCODE:
526 if (!SvROK(xclass)) {
527 STRLEN my_na;
528 char *sclass = SvPV(xclass, my_na);
529 New(55, context, 1, MD5_CTX);
530 context->signature = MD5_CTX_SIGNATURE;
531 ST(0) = sv_newmortal();
532 sv_setref_pv(ST(0), sclass, (void*)context);
533 SvREADONLY_on(SvRV(ST(0)));
534 } else {
535 context = get_md5_ctx(xclass);
536 }
537 MD5Init(context);
538 XSRETURN(1);
539
540void
541DESTROY(context)
542 MD5_CTX* context
543 CODE:
544 Safefree(context);
545
546void
547add(self, ...)
548 SV* self
549 PREINIT:
550 MD5_CTX* context = get_md5_ctx(self);
551 int i;
552 unsigned char *data;
553 STRLEN len;
554 PPCODE:
555 for (i = 1; i < items; i++) {
556 data = (unsigned char *)(SvPV(ST(i), len));
557 MD5Update(context, data, len);
558 }
559 XSRETURN(1); /* self */
560
561void
562addfile(self, fh)
563 SV* self
564 InputStream fh
565 PREINIT:
566 MD5_CTX* context = get_md5_ctx(self);
567 STRLEN fill = context->bytes_low & 0x3F;
568 unsigned char buffer[4096];
569 int n;
570 CODE:
571 if (fh) {
572 if (fill) {
573 /* The MD5Update() function is faster if it can work with
574 * complete blocks. This will fill up any buffered block
575 * first.
576 */
577 STRLEN missing = 64 - fill;
578 if ( (n = PerlIO_read(fh, buffer, missing)))
579 MD5Update(context, buffer, n);
580 else
581 XSRETURN(1); /* self */
582 }
583
584 /* Process blocks until EOF */
585 while ( (n = PerlIO_read(fh, buffer, sizeof(buffer)))) {
586 MD5Update(context, buffer, n);
587 }
588 }
589 XSRETURN(1); /* self */
590
591void
592digest(context)
593 MD5_CTX* context
594 ALIAS:
595 Digest::MD5::digest = F_BIN
596 Digest::MD5::hexdigest = F_HEX
597 Digest::MD5::b64digest = F_B64
598 PREINIT:
599 unsigned char digeststr[16];
600 PPCODE:
601 MD5Final(digeststr, context);
602 MD5Init(context); /* In case it is reused */
603 ST(0) = make_mortal_sv(digeststr, ix);
604 XSRETURN(1);
605
606void
607md5(...)
608 ALIAS:
609 Digest::MD5::md5 = F_BIN
610 Digest::MD5::md5_hex = F_HEX
611 Digest::MD5::md5_base64 = F_B64
612 PREINIT:
613 MD5_CTX ctx;
614 int i;
615 unsigned char *data;
616 STRLEN len;
617 unsigned char digeststr[16];
618 PPCODE:
619 MD5Init(&ctx);
620 for (i = 0; i < items; i++) {
621 data = (unsigned char *)(SvPV(ST(i), len));
622 MD5Update(&ctx, data, len);
623 }
624 MD5Final(digeststr, &ctx);
625 ST(0) = make_mortal_sv(digeststr, ix);
626 XSRETURN(1);