Blame MD5.xs

Packit f354a3
/* 
Packit f354a3
 * This library is free software; you can redistribute it and/or
Packit f354a3
 * modify it under the same terms as Perl itself.
Packit f354a3
 * 
Packit f354a3
 *  Copyright 1998-2000 Gisle Aas.
Packit f354a3
 *  Copyright 1995-1996 Neil Winton.
Packit f354a3
 *  Copyright 1991-1992 RSA Data Security, Inc.
Packit f354a3
 *
Packit f354a3
 * This code is derived from Neil Winton's MD5-1.7 Perl module, which in
Packit f354a3
 * turn is derived from the reference implementation in RFC 1321 which
Packit f354a3
 * comes with this message:
Packit f354a3
 *
Packit f354a3
 * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
Packit f354a3
 * rights reserved.
Packit f354a3
 *
Packit f354a3
 * License to copy and use this software is granted provided that it
Packit f354a3
 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Packit f354a3
 * Algorithm" in all material mentioning or referencing this software
Packit f354a3
 * or this function.
Packit f354a3
 *
Packit f354a3
 * License is also granted to make and use derivative works provided
Packit f354a3
 * that such works are identified as "derived from the RSA Data
Packit f354a3
 * Security, Inc. MD5 Message-Digest Algorithm" in all material
Packit f354a3
 * mentioning or referencing the derived work.
Packit f354a3
 *
Packit f354a3
 * RSA Data Security, Inc. makes no representations concerning either
Packit f354a3
 * the merchantability of this software or the suitability of this
Packit f354a3
 * software for any particular purpose. It is provided "as is"
Packit f354a3
 * without express or implied warranty of any kind.
Packit f354a3
 *
Packit f354a3
 * These notices must be retained in any copies of any part of this
Packit f354a3
 * documentation and/or software.
Packit f354a3
 */
Packit f354a3
Packit f354a3
#ifdef __cplusplus
Packit f354a3
extern "C" {
Packit f354a3
#endif
Packit f354a3
#define PERL_NO_GET_CONTEXT     /* we want efficiency */
Packit f354a3
#include "EXTERN.h"
Packit f354a3
#include "perl.h"
Packit f354a3
#include "XSUB.h"
Packit f354a3
#ifdef __cplusplus
Packit f354a3
}
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifndef PERL_UNUSED_VAR
Packit f354a3
# define PERL_UNUSED_VAR(x) ((void)x)
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifndef PERL_MAGIC_ext
Packit f354a3
# define PERL_MAGIC_ext '~'
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifndef Newxz
Packit f354a3
# define Newxz(v,n,t) Newz(0,v,n,t)
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifndef SvMAGIC_set
Packit f354a3
# define SvMAGIC_set(sv, mg) (SvMAGIC(sv) = (mg))
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifndef sv_magicext
Packit f354a3
# define sv_magicext(sv, obj, type, vtbl, name, namlen) \
Packit f354a3
    THX_sv_magicext(aTHX_ sv, obj, type, vtbl, name, namlen)
Packit f354a3
static MAGIC *THX_sv_magicext(pTHX_ SV *sv, SV *obj, int type,
Packit f354a3
    MGVTBL const *vtbl, char const *name, I32 namlen)
Packit f354a3
{
Packit f354a3
    MAGIC *mg;
Packit f354a3
    if (obj || namlen)
Packit f354a3
	/* exceeded intended usage of this reserve implementation */
Packit f354a3
	return NULL;
Packit f354a3
    Newxz(mg, 1, MAGIC);
Packit f354a3
    mg->mg_virtual = (MGVTBL*)vtbl;
Packit f354a3
    mg->mg_type = type;
Packit f354a3
    mg->mg_ptr = (char *)name;
Packit f354a3
    mg->mg_len = -1;
Packit f354a3
    (void) SvUPGRADE(sv, SVt_PVMG);
Packit f354a3
    mg->mg_moremagic = SvMAGIC(sv);
Packit f354a3
    SvMAGIC_set(sv, mg);
Packit f354a3
    SvMAGICAL_off(sv);
Packit f354a3
    mg_magical(sv);
Packit f354a3
    return mg;
Packit f354a3
}
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#if PERL_VERSION < 8
Packit f354a3
# undef SvPVbyte
Packit f354a3
# define SvPVbyte(sv, lp) (sv_utf8_downgrade((sv), 0), SvPV((sv), (lp)))
Packit f354a3
#endif
Packit f354a3
Packit f354a3
/* Perl does not guarantee that U32 is exactly 32 bits.  Some system
Packit f354a3
 * has no integral type with exactly 32 bits.  For instance, A Cray has
Packit f354a3
 * short, int and long all at 64 bits so we need to apply this macro
Packit f354a3
 * to reduce U32 values to 32 bits at appropriate places. If U32
Packit f354a3
 * really does have 32 bits then this is a no-op.
Packit f354a3
 */
Packit f354a3
#if BYTEORDER > 0x4321 || defined(TRUNCATE_U32)
Packit f354a3
  #define TO32(x)    ((x) &  0xFFFFffff)
Packit f354a3
  #define TRUNC32(x) ((x) &= 0xFFFFffff)
Packit f354a3
#else
Packit f354a3
  #define TO32(x)    (x)
Packit f354a3
  #define TRUNC32(x) /*nothing*/
Packit f354a3
#endif
Packit f354a3
Packit f354a3
/* The MD5 algorithm is defined in terms of little endian 32-bit
Packit f354a3
 * values.  The following macros (and functions) allow us to convert
Packit f354a3
 * between native integers and such values.
Packit f354a3
 */
Packit f354a3
#undef BYTESWAP
Packit f354a3
#ifndef U32_ALIGNMENT_REQUIRED
Packit f354a3
 #if BYTEORDER == 0x1234      /* 32-bit little endian */
Packit f354a3
  #define BYTESWAP(x) (x)     /* no-op */
Packit f354a3
Packit f354a3
 #elif BYTEORDER == 0x4321    /* 32-bit big endian */
Packit f354a3
  #define BYTESWAP(x) 	((((x)&0xFF)<<24)	\
Packit f354a3
			|(((x)>>24)&0xFF)	\
Packit f354a3
			|(((x)&0x0000FF00)<<8)	\
Packit f354a3
			|(((x)&0x00FF0000)>>8)	)
Packit f354a3
 #endif
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifndef BYTESWAP
Packit f354a3
static void u2s(U32 u, U8* s)
Packit f354a3
{
Packit f354a3
    *s++ = (U8)(u         & 0xFF);
Packit f354a3
    *s++ = (U8)((u >>  8) & 0xFF);
Packit f354a3
    *s++ = (U8)((u >> 16) & 0xFF);
Packit f354a3
    *s   = (U8)((u >> 24) & 0xFF);
Packit f354a3
}
Packit f354a3
Packit f354a3
#define s2u(s,u) ((u) =  (U32)(*s)            |  \
Packit f354a3
                        ((U32)(*(s+1)) << 8)  |  \
Packit f354a3
                        ((U32)(*(s+2)) << 16) |  \
Packit f354a3
                        ((U32)(*(s+3)) << 24))
Packit f354a3
#endif
Packit f354a3
Packit f354a3
/* This structure keeps the current state of algorithm.
Packit f354a3
 */
Packit f354a3
typedef struct {
Packit f354a3
  U32 A, B, C, D;  /* current digest */
Packit f354a3
  U32 bytes_low;   /* counts bytes in message */
Packit f354a3
  U32 bytes_high;  /* turn it into a 64-bit counter */
Packit f354a3
  U8 buffer[128];  /* collect complete 64 byte blocks */
Packit f354a3
} MD5_CTX;
Packit f354a3
Packit f354a3
#if defined(USE_ITHREADS) && defined(MGf_DUP)
Packit f354a3
STATIC int dup_md5_ctx(pTHX_ MAGIC *mg, CLONE_PARAMS *params)
Packit f354a3
{
Packit f354a3
    MD5_CTX *new_ctx;
Packit f354a3
    PERL_UNUSED_VAR(params);
Packit f354a3
    New(55, new_ctx, 1, MD5_CTX);
Packit f354a3
    memcpy(new_ctx, mg->mg_ptr, sizeof(MD5_CTX));
Packit f354a3
    mg->mg_ptr = (char *)new_ctx;
Packit f354a3
    return 0;
Packit f354a3
}
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#if defined(MGf_DUP) && defined(USE_ITHREADS)
Packit f354a3
STATIC const MGVTBL vtbl_md5 = {
Packit f354a3
    NULL, /* get */
Packit f354a3
    NULL, /* set */
Packit f354a3
    NULL, /* len */
Packit f354a3
    NULL, /* clear */
Packit f354a3
    NULL, /* free */
Packit f354a3
    NULL, /* copy */
Packit f354a3
    dup_md5_ctx, /* dup */
Packit f354a3
    NULL /* local */
Packit f354a3
};
Packit f354a3
#else
Packit f354a3
/* declare as 5 member, not normal 8 to save image space*/
Packit f354a3
STATIC const struct {
Packit f354a3
	int (*svt_get)(SV* sv, MAGIC* mg);
Packit f354a3
	int (*svt_set)(SV* sv, MAGIC* mg);
Packit f354a3
	U32 (*svt_len)(SV* sv, MAGIC* mg);
Packit f354a3
	int (*svt_clear)(SV* sv, MAGIC* mg);
Packit f354a3
	int (*svt_free)(SV* sv, MAGIC* mg);
Packit f354a3
} vtbl_md5 = {
Packit f354a3
	NULL, NULL, NULL, NULL, NULL
Packit f354a3
};
Packit f354a3
#endif
Packit f354a3
Packit f354a3
Packit f354a3
/* Padding is added at the end of the message in order to fill a
Packit f354a3
 * complete 64 byte block (- 8 bytes for the message length).  The
Packit f354a3
 * padding is also the reason the buffer in MD5_CTX have to be
Packit f354a3
 * 128 bytes.
Packit f354a3
 */
Packit f354a3
static const unsigned char PADDING[64] = {
Packit f354a3
  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit f354a3
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit f354a3
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Packit f354a3
};
Packit f354a3
Packit f354a3
/* Constants for MD5Transform routine.
Packit f354a3
 */
Packit f354a3
#define S11 7
Packit f354a3
#define S12 12
Packit f354a3
#define S13 17
Packit f354a3
#define S14 22
Packit f354a3
#define S21 5
Packit f354a3
#define S22 9
Packit f354a3
#define S23 14
Packit f354a3
#define S24 20
Packit f354a3
#define S31 4
Packit f354a3
#define S32 11
Packit f354a3
#define S33 16
Packit f354a3
#define S34 23
Packit f354a3
#define S41 6
Packit f354a3
#define S42 10
Packit f354a3
#define S43 15
Packit f354a3
#define S44 21
Packit f354a3
Packit f354a3
/* F, G, H and I are basic MD5 functions.
Packit f354a3
 */
Packit f354a3
#define F(x, y, z) ((((x) & ((y) ^ (z))) ^ (z)))
Packit f354a3
#define G(x, y, z) F(z, x, y)
Packit f354a3
#define H(x, y, z) ((x) ^ (y) ^ (z))
Packit f354a3
#define I(x, y, z) ((y) ^ ((x) | (~z)))
Packit f354a3
Packit f354a3
/* ROTATE_LEFT rotates x left n bits.
Packit f354a3
 */
Packit f354a3
#define ROTATE_LEFT(x, n) (((x) << (n) | ((x) >> (32-(n)))))
Packit f354a3
Packit f354a3
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Packit f354a3
 * Rotation is separate from addition to prevent recomputation.
Packit f354a3
 */
Packit f354a3
#define FF(a, b, c, d, s, ac)                    \
Packit f354a3
 (a) += F ((b), (c), (d)) + (NEXTx) + (U32)(ac); \
Packit f354a3
 TRUNC32((a));                                   \
Packit f354a3
 (a) = ROTATE_LEFT ((a), (s));                   \
Packit f354a3
 (a) += (b);                                     \
Packit f354a3
 TRUNC32((a));
Packit f354a3
Packit f354a3
#define GG(a, b, c, d, x, s, ac)                 \
Packit f354a3
 (a) += G ((b), (c), (d)) + X[x] + (U32)(ac);    \
Packit f354a3
 TRUNC32((a));                                   \
Packit f354a3
 (a) = ROTATE_LEFT ((a), (s));                   \
Packit f354a3
 (a) += (b);                                     \
Packit f354a3
 TRUNC32((a));
Packit f354a3
Packit f354a3
#define HH(a, b, c, d, x, s, ac)                 \
Packit f354a3
 (a) += H ((b), (c), (d)) + X[x] + (U32)(ac);    \
Packit f354a3
 TRUNC32((a));                                   \
Packit f354a3
 (a) = ROTATE_LEFT ((a), (s));                   \
Packit f354a3
 (a) += (b);                                     \
Packit f354a3
 TRUNC32((a));
Packit f354a3
Packit f354a3
#define II(a, b, c, d, x, s, ac)                 \
Packit f354a3
 (a) += I ((b), (c), (d)) + X[x] + (U32)(ac);    \
Packit f354a3
 TRUNC32((a));                                   \
Packit f354a3
 (a) = ROTATE_LEFT ((a), (s));                   \
Packit f354a3
 (a) += (b);                                     \
Packit f354a3
 TRUNC32((a));
Packit f354a3
Packit f354a3
Packit f354a3
static void
Packit f354a3
MD5Init(MD5_CTX *ctx)
Packit f354a3
{
Packit f354a3
  /* Start state */
Packit f354a3
  ctx->A = 0x67452301;
Packit f354a3
  ctx->B = 0xefcdab89;
Packit f354a3
  ctx->C = 0x98badcfe;
Packit f354a3
  ctx->D = 0x10325476;
Packit f354a3
Packit f354a3
  /* message length */
Packit f354a3
  ctx->bytes_low = ctx->bytes_high = 0;
Packit f354a3
}
Packit f354a3
Packit f354a3
Packit f354a3
static void
Packit f354a3
MD5Transform(MD5_CTX* ctx, const U8* buf, STRLEN blocks)
Packit f354a3
{
Packit f354a3
#ifdef MD5_DEBUG
Packit f354a3
    static int tcount = 0;
Packit f354a3
#endif
Packit f354a3
Packit f354a3
    U32 A = ctx->A;
Packit f354a3
    U32 B = ctx->B;
Packit f354a3
    U32 C = ctx->C;
Packit f354a3
    U32 D = ctx->D;
Packit f354a3
Packit f354a3
#ifndef U32_ALIGNMENT_REQUIRED
Packit f354a3
    const U32 *x = (U32*)buf;  /* really just type casting */
Packit f354a3
#endif
Packit f354a3
Packit f354a3
    do {
Packit f354a3
	U32 a = A;
Packit f354a3
	U32 b = B;
Packit f354a3
	U32 c = C;
Packit f354a3
	U32 d = D;
Packit f354a3
Packit f354a3
#if BYTEORDER == 0x1234 && !defined(U32_ALIGNMENT_REQUIRED)
Packit f354a3
	const U32 *X = x;
Packit f354a3
        #define NEXTx  (*x++)
Packit f354a3
#else
Packit f354a3
	U32 X[16];      /* converted values, used in round 2-4 */
Packit f354a3
	U32 *uptr = X;
Packit f354a3
	U32 tmp;
Packit f354a3
 #ifdef BYTESWAP
Packit f354a3
        #define NEXTx  (tmp=*x++, *uptr++ = BYTESWAP(tmp))
Packit f354a3
 #else
Packit f354a3
        #define NEXTx  (s2u(buf,tmp), buf += 4, *uptr++ = tmp)
Packit f354a3
 #endif
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifdef MD5_DEBUG
Packit f354a3
	if (buf == ctx->buffer)
Packit f354a3
	    fprintf(stderr,"%5d: Transform ctx->buffer", ++tcount);
Packit f354a3
	else 
Packit f354a3
	    fprintf(stderr,"%5d: Transform %p (%d)", ++tcount, buf, blocks);
Packit f354a3
Packit f354a3
	{
Packit f354a3
	    int i;
Packit f354a3
	    fprintf(stderr,"[");
Packit f354a3
	    for (i = 0; i < 16; i++) {
Packit f354a3
		fprintf(stderr,"%x,", x[i]);
Packit f354a3
	    }
Packit f354a3
	    fprintf(stderr,"]\n");
Packit f354a3
	}
Packit f354a3
#endif
Packit f354a3
Packit f354a3
	/* Round 1 */
Packit f354a3
	FF (a, b, c, d, S11, 0xd76aa478); /* 1 */
Packit f354a3
	FF (d, a, b, c, S12, 0xe8c7b756); /* 2 */
Packit f354a3
	FF (c, d, a, b, S13, 0x242070db); /* 3 */
Packit f354a3
	FF (b, c, d, a, S14, 0xc1bdceee); /* 4 */
Packit f354a3
	FF (a, b, c, d, S11, 0xf57c0faf); /* 5 */
Packit f354a3
	FF (d, a, b, c, S12, 0x4787c62a); /* 6 */
Packit f354a3
	FF (c, d, a, b, S13, 0xa8304613); /* 7 */
Packit f354a3
	FF (b, c, d, a, S14, 0xfd469501); /* 8 */
Packit f354a3
	FF (a, b, c, d, S11, 0x698098d8); /* 9 */
Packit f354a3
	FF (d, a, b, c, S12, 0x8b44f7af); /* 10 */
Packit f354a3
	FF (c, d, a, b, S13, 0xffff5bb1); /* 11 */
Packit f354a3
	FF (b, c, d, a, S14, 0x895cd7be); /* 12 */
Packit f354a3
	FF (a, b, c, d, S11, 0x6b901122); /* 13 */
Packit f354a3
	FF (d, a, b, c, S12, 0xfd987193); /* 14 */
Packit f354a3
	FF (c, d, a, b, S13, 0xa679438e); /* 15 */
Packit f354a3
	FF (b, c, d, a, S14, 0x49b40821); /* 16 */
Packit f354a3
Packit f354a3
	/* Round 2 */
Packit f354a3
	GG (a, b, c, d,  1, S21, 0xf61e2562); /* 17 */
Packit f354a3
	GG (d, a, b, c,  6, S22, 0xc040b340); /* 18 */
Packit f354a3
	GG (c, d, a, b, 11, S23, 0x265e5a51); /* 19 */
Packit f354a3
	GG (b, c, d, a,  0, S24, 0xe9b6c7aa); /* 20 */
Packit f354a3
	GG (a, b, c, d,  5, S21, 0xd62f105d); /* 21 */
Packit f354a3
	GG (d, a, b, c, 10, S22,  0x2441453); /* 22 */
Packit f354a3
	GG (c, d, a, b, 15, S23, 0xd8a1e681); /* 23 */
Packit f354a3
	GG (b, c, d, a,  4, S24, 0xe7d3fbc8); /* 24 */
Packit f354a3
	GG (a, b, c, d,  9, S21, 0x21e1cde6); /* 25 */
Packit f354a3
	GG (d, a, b, c, 14, S22, 0xc33707d6); /* 26 */
Packit f354a3
	GG (c, d, a, b,  3, S23, 0xf4d50d87); /* 27 */
Packit f354a3
	GG (b, c, d, a,  8, S24, 0x455a14ed); /* 28 */
Packit f354a3
	GG (a, b, c, d, 13, S21, 0xa9e3e905); /* 29 */
Packit f354a3
	GG (d, a, b, c,  2, S22, 0xfcefa3f8); /* 30 */
Packit f354a3
	GG (c, d, a, b,  7, S23, 0x676f02d9); /* 31 */
Packit f354a3
	GG (b, c, d, a, 12, S24, 0x8d2a4c8a); /* 32 */
Packit f354a3
Packit f354a3
	/* Round 3 */
Packit f354a3
	HH (a, b, c, d,  5, S31, 0xfffa3942); /* 33 */
Packit f354a3
	HH (d, a, b, c,  8, S32, 0x8771f681); /* 34 */
Packit f354a3
	HH (c, d, a, b, 11, S33, 0x6d9d6122); /* 35 */
Packit f354a3
	HH (b, c, d, a, 14, S34, 0xfde5380c); /* 36 */
Packit f354a3
	HH (a, b, c, d,  1, S31, 0xa4beea44); /* 37 */
Packit f354a3
	HH (d, a, b, c,  4, S32, 0x4bdecfa9); /* 38 */
Packit f354a3
	HH (c, d, a, b,  7, S33, 0xf6bb4b60); /* 39 */
Packit f354a3
	HH (b, c, d, a, 10, S34, 0xbebfbc70); /* 40 */
Packit f354a3
	HH (a, b, c, d, 13, S31, 0x289b7ec6); /* 41 */
Packit f354a3
	HH (d, a, b, c,  0, S32, 0xeaa127fa); /* 42 */
Packit f354a3
	HH (c, d, a, b,  3, S33, 0xd4ef3085); /* 43 */
Packit f354a3
	HH (b, c, d, a,  6, S34,  0x4881d05); /* 44 */
Packit f354a3
	HH (a, b, c, d,  9, S31, 0xd9d4d039); /* 45 */
Packit f354a3
	HH (d, a, b, c, 12, S32, 0xe6db99e5); /* 46 */
Packit f354a3
	HH (c, d, a, b, 15, S33, 0x1fa27cf8); /* 47 */
Packit f354a3
	HH (b, c, d, a,  2, S34, 0xc4ac5665); /* 48 */
Packit f354a3
Packit f354a3
	/* Round 4 */
Packit f354a3
	II (a, b, c, d,  0, S41, 0xf4292244); /* 49 */
Packit f354a3
	II (d, a, b, c,  7, S42, 0x432aff97); /* 50 */
Packit f354a3
	II (c, d, a, b, 14, S43, 0xab9423a7); /* 51 */
Packit f354a3
	II (b, c, d, a,  5, S44, 0xfc93a039); /* 52 */
Packit f354a3
	II (a, b, c, d, 12, S41, 0x655b59c3); /* 53 */
Packit f354a3
	II (d, a, b, c,  3, S42, 0x8f0ccc92); /* 54 */
Packit f354a3
	II (c, d, a, b, 10, S43, 0xffeff47d); /* 55 */
Packit f354a3
	II (b, c, d, a,  1, S44, 0x85845dd1); /* 56 */
Packit f354a3
	II (a, b, c, d,  8, S41, 0x6fa87e4f); /* 57 */
Packit f354a3
	II (d, a, b, c, 15, S42, 0xfe2ce6e0); /* 58 */
Packit f354a3
	II (c, d, a, b,  6, S43, 0xa3014314); /* 59 */
Packit f354a3
	II (b, c, d, a, 13, S44, 0x4e0811a1); /* 60 */
Packit f354a3
	II (a, b, c, d,  4, S41, 0xf7537e82); /* 61 */
Packit f354a3
	II (d, a, b, c, 11, S42, 0xbd3af235); /* 62 */
Packit f354a3
	II (c, d, a, b,  2, S43, 0x2ad7d2bb); /* 63 */
Packit f354a3
	II (b, c, d, a,  9, S44, 0xeb86d391); /* 64 */
Packit f354a3
Packit f354a3
	A += a;  TRUNC32(A);
Packit f354a3
	B += b;  TRUNC32(B);
Packit f354a3
	C += c;  TRUNC32(C);
Packit f354a3
	D += d;  TRUNC32(D);
Packit f354a3
Packit f354a3
    } while (--blocks);
Packit f354a3
    ctx->A = A;
Packit f354a3
    ctx->B = B;
Packit f354a3
    ctx->C = C;
Packit f354a3
    ctx->D = D;
Packit f354a3
}
Packit f354a3
Packit f354a3
Packit f354a3
#ifdef MD5_DEBUG
Packit f354a3
static char*
Packit f354a3
ctx_dump(MD5_CTX* ctx)
Packit f354a3
{
Packit f354a3
    static char buf[1024];
Packit f354a3
    sprintf(buf, "{A=%x,B=%x,C=%x,D=%x,%d,%d(%d)}",
Packit f354a3
	    ctx->A, ctx->B, ctx->C, ctx->D,
Packit f354a3
	    ctx->bytes_low, ctx->bytes_high, (ctx->bytes_low&0x3F));
Packit f354a3
    return buf;
Packit f354a3
}
Packit f354a3
#endif
Packit f354a3
Packit f354a3
Packit f354a3
static void
Packit f354a3
MD5Update(MD5_CTX* ctx, const U8* buf, STRLEN len)
Packit f354a3
{
Packit f354a3
    STRLEN blocks;
Packit f354a3
    STRLEN fill = ctx->bytes_low & 0x3F;
Packit f354a3
Packit f354a3
#ifdef MD5_DEBUG  
Packit f354a3
    static int ucount = 0;
Packit f354a3
    fprintf(stderr,"%5i: Update(%s, %p, %d)\n", ++ucount, ctx_dump(ctx),
Packit f354a3
	                                        buf, len);
Packit f354a3
#endif
Packit f354a3
Packit f354a3
    ctx->bytes_low += len;
Packit f354a3
    if (ctx->bytes_low < len) /* wrap around */
Packit f354a3
	ctx->bytes_high++;
Packit f354a3
Packit f354a3
    if (fill) {
Packit f354a3
	STRLEN missing = 64 - fill;
Packit f354a3
	if (len < missing) {
Packit f354a3
	    Copy(buf, ctx->buffer + fill, len, U8);
Packit f354a3
	    return;
Packit f354a3
	}
Packit f354a3
	Copy(buf, ctx->buffer + fill, missing, U8);
Packit f354a3
	MD5Transform(ctx, ctx->buffer, 1);
Packit f354a3
	buf += missing;
Packit f354a3
	len -= missing;
Packit f354a3
    }
Packit f354a3
Packit f354a3
    blocks = len >> 6;
Packit f354a3
    if (blocks)
Packit f354a3
	MD5Transform(ctx, buf, blocks);
Packit f354a3
    if ( (len &= 0x3F)) {
Packit f354a3
	Copy(buf + (blocks << 6), ctx->buffer, len, U8);
Packit f354a3
    }
Packit f354a3
}
Packit f354a3
Packit f354a3
Packit f354a3
static void
Packit f354a3
MD5Final(U8* digest, MD5_CTX *ctx)
Packit f354a3
{
Packit f354a3
    STRLEN fill = ctx->bytes_low & 0x3F;
Packit f354a3
    STRLEN padlen = (fill < 56 ? 56 : 120) - fill;
Packit f354a3
    U32 bits_low, bits_high;
Packit f354a3
#ifdef MD5_DEBUG
Packit f354a3
    fprintf(stderr,"       Final:  %s\n", ctx_dump(ctx));
Packit f354a3
#endif
Packit f354a3
    Copy(PADDING, ctx->buffer + fill, padlen, U8);
Packit f354a3
    fill += padlen;
Packit f354a3
Packit f354a3
    bits_low = ctx->bytes_low << 3;
Packit f354a3
    bits_high = (ctx->bytes_high << 3) | (ctx->bytes_low  >> 29);
Packit f354a3
#ifdef BYTESWAP
Packit f354a3
    *(U32*)(ctx->buffer + fill) = BYTESWAP(bits_low);    fill += 4;
Packit f354a3
    *(U32*)(ctx->buffer + fill) = BYTESWAP(bits_high);   fill += 4;
Packit f354a3
#else
Packit f354a3
    u2s(bits_low,  ctx->buffer + fill);   fill += 4;
Packit f354a3
    u2s(bits_high, ctx->buffer + fill);   fill += 4;
Packit f354a3
#endif
Packit f354a3
Packit f354a3
    MD5Transform(ctx, ctx->buffer, fill >> 6);
Packit f354a3
#ifdef MD5_DEBUG
Packit f354a3
    fprintf(stderr,"       Result: %s\n", ctx_dump(ctx));
Packit f354a3
#endif
Packit f354a3
Packit f354a3
#ifdef BYTESWAP
Packit f354a3
    *(U32*)digest = BYTESWAP(ctx->A);  digest += 4;
Packit f354a3
    *(U32*)digest = BYTESWAP(ctx->B);  digest += 4;
Packit f354a3
    *(U32*)digest = BYTESWAP(ctx->C);  digest += 4;
Packit f354a3
    *(U32*)digest = BYTESWAP(ctx->D);
Packit f354a3
#else
Packit f354a3
    u2s(ctx->A, digest);
Packit f354a3
    u2s(ctx->B, digest+4);
Packit f354a3
    u2s(ctx->C, digest+8);
Packit f354a3
    u2s(ctx->D, digest+12);
Packit f354a3
#endif
Packit f354a3
}
Packit f354a3
Packit f354a3
#ifndef INT2PTR
Packit f354a3
#define INT2PTR(any,d)	(any)(d)
Packit f354a3
#endif
Packit f354a3
Packit f354a3
static MD5_CTX* get_md5_ctx(pTHX_ SV* sv)
Packit f354a3
{
Packit f354a3
    MAGIC *mg;
Packit f354a3
Packit f354a3
    if (!sv_derived_from(sv, "Digest::MD5"))
Packit f354a3
	croak("Not a reference to a Digest::MD5 object");
Packit f354a3
Packit f354a3
    for (mg = SvMAGIC(SvRV(sv)); mg; mg = mg->mg_moremagic) {
Packit f354a3
	if (mg->mg_type == PERL_MAGIC_ext
Packit f354a3
	    && mg->mg_virtual == (const MGVTBL * const)&vtbl_md5) {
Packit f354a3
	    return (MD5_CTX *)mg->mg_ptr;
Packit f354a3
	}
Packit f354a3
    }
Packit f354a3
Packit f354a3
    croak("Failed to get MD5_CTX pointer");
Packit f354a3
    return (MD5_CTX*)0; /* some compilers insist on a return value */
Packit f354a3
}
Packit f354a3
Packit f354a3
static SV * new_md5_ctx(pTHX_ MD5_CTX *context, const char *klass)
Packit f354a3
{
Packit f354a3
    SV *sv = newSV(0);
Packit f354a3
    SV *obj = newRV_noinc(sv);
Packit f354a3
#ifdef USE_ITHREADS
Packit f354a3
    MAGIC *mg;
Packit f354a3
#endif
Packit f354a3
Packit f354a3
    sv_bless(obj, gv_stashpv(klass, 0));
Packit f354a3
Packit f354a3
#ifdef USE_ITHREADS
Packit f354a3
    mg =
Packit f354a3
#endif
Packit f354a3
	sv_magicext(sv, NULL, PERL_MAGIC_ext, (const MGVTBL * const)&vtbl_md5, (const char *)context, 0);
Packit f354a3
Packit f354a3
#if defined(USE_ITHREADS) && defined(MGf_DUP)
Packit f354a3
    mg->mg_flags |= MGf_DUP;
Packit f354a3
#endif
Packit f354a3
Packit f354a3
    return obj;
Packit f354a3
}
Packit f354a3
Packit f354a3
Packit f354a3
static char* hex_16(const unsigned char* from, char* to)
Packit f354a3
{
Packit f354a3
    static const char hexdigits[] = "0123456789abcdef";
Packit f354a3
    const unsigned char *end = from + 16;
Packit f354a3
    char *d = to;
Packit f354a3
Packit f354a3
    while (from < end) {
Packit f354a3
	*d++ = hexdigits[(*from >> 4)];
Packit f354a3
	*d++ = hexdigits[(*from & 0x0F)];
Packit f354a3
	from++;
Packit f354a3
    }
Packit f354a3
    *d = '\0';
Packit f354a3
    return to;
Packit f354a3
}
Packit f354a3
Packit f354a3
static char* base64_16(const unsigned char* from, char* to)
Packit f354a3
{
Packit f354a3
    static const char base64[] =
Packit f354a3
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Packit f354a3
    const unsigned char *end = from + 16;
Packit f354a3
    unsigned char c1, c2, c3;
Packit f354a3
    char *d = to;
Packit f354a3
Packit f354a3
    while (1) {
Packit f354a3
	c1 = *from++;
Packit f354a3
	*d++ = base64[c1>>2];
Packit f354a3
	if (from == end) {
Packit f354a3
	    *d++ = base64[(c1 & 0x3) << 4];
Packit f354a3
	    break;
Packit f354a3
	}
Packit f354a3
	c2 = *from++;
Packit f354a3
	c3 = *from++;
Packit f354a3
	*d++ = base64[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
Packit f354a3
	*d++ = base64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
Packit f354a3
	*d++ = base64[c3 & 0x3F];
Packit f354a3
    }
Packit f354a3
    *d = '\0';
Packit f354a3
    return to;
Packit f354a3
}
Packit f354a3
Packit f354a3
/* Formats */
Packit f354a3
#define F_BIN 0
Packit f354a3
#define F_HEX 1
Packit f354a3
#define F_B64 2
Packit f354a3
Packit f354a3
static SV* make_mortal_sv(pTHX_ const unsigned char *src, int type)
Packit f354a3
{
Packit f354a3
    STRLEN len;
Packit f354a3
    char result[33];
Packit f354a3
    char *ret;
Packit f354a3
    
Packit f354a3
    switch (type) {
Packit f354a3
    case F_BIN:
Packit f354a3
	ret = (char*)src;
Packit f354a3
	len = 16;
Packit f354a3
	break;
Packit f354a3
    case F_HEX:
Packit f354a3
	ret = hex_16(src, result);
Packit f354a3
	len = 32;
Packit f354a3
	break;
Packit f354a3
    case F_B64:
Packit f354a3
	ret = base64_16(src, result);
Packit f354a3
	len = 22;
Packit f354a3
	break;
Packit f354a3
    default:
Packit f354a3
	croak("Bad conversion type (%d)", type);
Packit f354a3
	break;
Packit f354a3
    }
Packit f354a3
    return sv_2mortal(newSVpv(ret,len));
Packit f354a3
}
Packit f354a3
Packit f354a3
Packit f354a3
/********************************************************************/
Packit f354a3
Packit f354a3
typedef PerlIO* InputStream;
Packit f354a3
Packit f354a3
MODULE = Digest::MD5		PACKAGE = Digest::MD5
Packit f354a3
Packit f354a3
PROTOTYPES: DISABLE
Packit f354a3
Packit f354a3
void
Packit f354a3
new(xclass)
Packit f354a3
	SV* xclass
Packit f354a3
    PREINIT:
Packit f354a3
	MD5_CTX* context;
Packit f354a3
    PPCODE:
Packit f354a3
	if (!SvROK(xclass)) {
Packit f354a3
	    STRLEN my_na;
Packit f354a3
	    const char *sclass = SvPV(xclass, my_na);
Packit f354a3
	    New(55, context, 1, MD5_CTX);
Packit f354a3
	    ST(0) = sv_2mortal(new_md5_ctx(aTHX_ context, sclass));
Packit f354a3
	} else {
Packit f354a3
	    context = get_md5_ctx(aTHX_ xclass);
Packit f354a3
	}
Packit f354a3
	MD5Init(context);
Packit f354a3
	XSRETURN(1);
Packit f354a3
Packit f354a3
void
Packit f354a3
clone(self)
Packit f354a3
	SV* self
Packit f354a3
    PREINIT:
Packit f354a3
	MD5_CTX* cont = get_md5_ctx(aTHX_ self);
Packit f354a3
	const char *myname = sv_reftype(SvRV(self),TRUE);
Packit f354a3
	MD5_CTX* context;
Packit f354a3
    PPCODE:
Packit f354a3
	New(55, context, 1, MD5_CTX);
Packit f354a3
	ST(0) = sv_2mortal(new_md5_ctx(aTHX_ context, myname));
Packit f354a3
	memcpy(context,cont,sizeof(MD5_CTX));
Packit f354a3
	XSRETURN(1);
Packit f354a3
Packit f354a3
void
Packit f354a3
DESTROY(context)
Packit f354a3
	MD5_CTX* context
Packit f354a3
    CODE:
Packit f354a3
        Safefree(context);
Packit f354a3
Packit f354a3
void
Packit f354a3
add(self, ...)
Packit f354a3
	SV* self
Packit f354a3
    PREINIT:
Packit f354a3
	MD5_CTX* context = get_md5_ctx(aTHX_ self);
Packit f354a3
	int i;
Packit f354a3
	unsigned char *data;
Packit f354a3
	STRLEN len;
Packit f354a3
    PPCODE:
Packit f354a3
	for (i = 1; i < items; i++) {
Packit f354a3
            U32 had_utf8 = SvUTF8(ST(i));
Packit f354a3
	    data = (unsigned char *)(SvPVbyte(ST(i), len));
Packit f354a3
	    MD5Update(context, data, len);
Packit f354a3
	    if (had_utf8) sv_utf8_upgrade(ST(i));
Packit f354a3
	}
Packit f354a3
	XSRETURN(1);  /* self */
Packit f354a3
Packit f354a3
void
Packit f354a3
addfile(self, fh)
Packit f354a3
	SV* self
Packit f354a3
	InputStream fh
Packit f354a3
    PREINIT:
Packit f354a3
	MD5_CTX* context = get_md5_ctx(aTHX_ self);
Packit f354a3
	STRLEN fill = context->bytes_low & 0x3F;
Packit f354a3
#ifdef USE_HEAP_INSTEAD_OF_STACK
Packit f354a3
	unsigned char* buffer;
Packit f354a3
#else
Packit f354a3
	unsigned char buffer[4096];
Packit f354a3
#endif
Packit f354a3
	int  n;
Packit f354a3
    CODE:
Packit f354a3
	if (fh) {
Packit f354a3
#ifdef USE_HEAP_INSTEAD_OF_STACK
Packit f354a3
	    New(0, buffer, 4096, unsigned char);
Packit f354a3
	    assert(buffer);
Packit f354a3
#endif
Packit f354a3
            if (fill) {
Packit f354a3
	        /* The MD5Update() function is faster if it can work with
Packit f354a3
	         * complete blocks.  This will fill up any buffered block
Packit f354a3
	         * first.
Packit f354a3
	         */
Packit f354a3
	        STRLEN missing = 64 - fill;
Packit f354a3
	        if ( (n = PerlIO_read(fh, buffer, missing)) > 0)
Packit f354a3
	 	    MD5Update(context, buffer, n);
Packit f354a3
	        else
Packit f354a3
		    XSRETURN(1);  /* self */
Packit f354a3
	    }
Packit f354a3
Packit f354a3
	    /* Process blocks until EOF or error */
Packit f354a3
            while ( (n = PerlIO_read(fh, buffer, sizeof(buffer))) > 0) {
Packit f354a3
	        MD5Update(context, buffer, n);
Packit f354a3
	    }
Packit f354a3
#ifdef USE_HEAP_INSTEAD_OF_STACK
Packit f354a3
	    Safefree(buffer);
Packit f354a3
#endif
Packit f354a3
	    if (PerlIO_error(fh)) {
Packit f354a3
		croak("Reading from filehandle failed");
Packit f354a3
	    }
Packit f354a3
	}
Packit f354a3
	else {
Packit f354a3
	    croak("No filehandle passed");
Packit f354a3
	}
Packit f354a3
	XSRETURN(1);  /* self */
Packit f354a3
Packit f354a3
void
Packit f354a3
digest(context)
Packit f354a3
	MD5_CTX* context
Packit f354a3
    ALIAS:
Packit f354a3
	Digest::MD5::digest    = F_BIN
Packit f354a3
	Digest::MD5::hexdigest = F_HEX
Packit f354a3
	Digest::MD5::b64digest = F_B64
Packit f354a3
    PREINIT:
Packit f354a3
	unsigned char digeststr[16];
Packit f354a3
    PPCODE:
Packit f354a3
        MD5Final(digeststr, context);
Packit f354a3
	MD5Init(context);  /* In case it is reused */
Packit f354a3
        ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
Packit f354a3
        XSRETURN(1);
Packit f354a3
Packit f354a3
void
Packit f354a3
context(ctx, ...)
Packit f354a3
	MD5_CTX* ctx
Packit f354a3
    PREINIT:
Packit f354a3
	char out[16];
Packit f354a3
        U32 w;
Packit f354a3
    PPCODE:
Packit f354a3
	if (items > 2) {
Packit f354a3
	    STRLEN len;
Packit f354a3
	    unsigned long blocks = SvUV(ST(1));
Packit f354a3
	    unsigned char *buf = (unsigned char *)(SvPV(ST(2), len));
Packit f354a3
	    ctx->A = buf[ 0] | (buf[ 1]<<8) | (buf[ 2]<<16) | (buf[ 3]<<24);
Packit f354a3
	    ctx->B = buf[ 4] | (buf[ 5]<<8) | (buf[ 6]<<16) | (buf[ 7]<<24);
Packit f354a3
	    ctx->C = buf[ 8] | (buf[ 9]<<8) | (buf[10]<<16) | (buf[11]<<24);
Packit f354a3
	    ctx->D = buf[12] | (buf[13]<<8) | (buf[14]<<16) | (buf[15]<<24);
Packit f354a3
	    ctx->bytes_low = blocks << 6;
Packit f354a3
	    ctx->bytes_high = blocks >> 26;
Packit f354a3
	    if (items == 4) {
Packit f354a3
		buf = (unsigned char *)(SvPV(ST(3), len));
Packit f354a3
		MD5Update(ctx, buf, len);
Packit f354a3
	    }
Packit f354a3
	    XSRETURN(1); /* ctx */
Packit f354a3
	} else if (items != 1) {
Packit f354a3
	    XSRETURN(0);
Packit f354a3
	}
Packit f354a3
Packit f354a3
        w=ctx->A; out[ 0]=w; out[ 1]=(w>>8); out[ 2]=(w>>16); out[ 3]=(w>>24);
Packit f354a3
        w=ctx->B; out[ 4]=w; out[ 5]=(w>>8); out[ 6]=(w>>16); out[ 7]=(w>>24);
Packit f354a3
        w=ctx->C; out[ 8]=w; out[ 9]=(w>>8); out[10]=(w>>16); out[11]=(w>>24);
Packit f354a3
        w=ctx->D; out[12]=w; out[13]=(w>>8); out[14]=(w>>16); out[15]=(w>>24);
Packit f354a3
Packit f354a3
	EXTEND(SP, 3);
Packit f354a3
	ST(0) = sv_2mortal(newSVuv(ctx->bytes_high << 26 |
Packit f354a3
				   ctx->bytes_low >> 6));
Packit f354a3
	ST(1) = sv_2mortal(newSVpv(out, 16));
Packit f354a3
	ST(2) = sv_2mortal(newSVpv((char *)ctx->buffer,
Packit f354a3
				   ctx->bytes_low & 0x3F));
Packit f354a3
	XSRETURN(3);
Packit f354a3
Packit f354a3
void
Packit f354a3
md5(...)
Packit f354a3
    ALIAS:
Packit f354a3
	Digest::MD5::md5        = F_BIN
Packit f354a3
	Digest::MD5::md5_hex    = F_HEX
Packit f354a3
	Digest::MD5::md5_base64 = F_B64
Packit f354a3
    PREINIT:
Packit f354a3
	MD5_CTX ctx;
Packit f354a3
	int i;
Packit f354a3
	unsigned char *data;
Packit f354a3
        STRLEN len;
Packit f354a3
	unsigned char digeststr[16];
Packit f354a3
    PPCODE:
Packit f354a3
	MD5Init(&ctx;;
Packit f354a3
Packit f354a3
	if ((PL_dowarn & G_WARN_ON) || ckWARN(WARN_SYNTAX)) {
Packit f354a3
            const char *msg = 0;
Packit f354a3
	    if (items == 1) {
Packit f354a3
		if (SvROK(ST(0))) {
Packit f354a3
                    SV* sv = SvRV(ST(0));
Packit f354a3
                    char *name;
Packit f354a3
		    if (SvOBJECT(sv) && (name = HvNAME(SvSTASH(sv)))
Packit f354a3
                                     && strEQ(name, "Digest::MD5"))
Packit f354a3
		        msg = "probably called as method";
Packit f354a3
		    else
Packit f354a3
			msg = "called with reference argument";
Packit f354a3
		}
Packit f354a3
	    }
Packit f354a3
	    else if (items > 1) {
Packit f354a3
		data = (unsigned char *)SvPV(ST(0), len);
Packit f354a3
		if (len == 11 && memEQ("Digest::MD5", data, 11)) {
Packit f354a3
		    msg = "probably called as class method";
Packit f354a3
		}
Packit f354a3
		else if (SvROK(ST(0))) {
Packit f354a3
		    SV* sv = SvRV(ST(0));
Packit f354a3
                    char *name;
Packit f354a3
		    if (SvOBJECT(sv) && (name = HvNAME(SvSTASH(sv)))
Packit f354a3
                                     && strEQ(name, "Digest::MD5"))
Packit f354a3
		        msg = "probably called as method";
Packit f354a3
		}
Packit f354a3
	    }
Packit f354a3
	    if (msg) {
Packit f354a3
	        const char *f = (ix == F_BIN) ? "md5" :
Packit f354a3
		                (ix == F_HEX) ? "md5_hex" : "md5_base64";
Packit f354a3
	        warn("&Digest::MD5::%s function %s", f, msg);
Packit f354a3
	    }
Packit f354a3
	}
Packit f354a3
Packit f354a3
	for (i = 0; i < items; i++) {
Packit f354a3
            U32 had_utf8 = SvUTF8(ST(i));
Packit f354a3
	    data = (unsigned char *)(SvPVbyte(ST(i), len));
Packit f354a3
	    MD5Update(&ctx, data, len);
Packit f354a3
	    if (had_utf8) sv_utf8_upgrade(ST(i));
Packit f354a3
	}
Packit f354a3
	MD5Final(digeststr, &ctx;;
Packit f354a3
        ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
Packit f354a3
        XSRETURN(1);