MD5 and Zip Libraries

Discuss programming topics for the various GPL'd game engine sources.
Post Reply
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

MD5 and Zip Libraries

Post by Baker »

Does anyone know of a good MD5 function and/or zip library (>for use with files <) that would be compatible with the GPL 2 or 3?

I figure this issue has come up enough times that rather than using Google to find out, someone here probably knows the obvious best answer. I know zlib does compression stuff but I have never thought of the idea of using it with zip files (I don't know if it is any good with that ...)
Algorithm
As of February 2010 zlib only supports one algorithm called DEFLATE which is a variation of LZ77 (Lempel–Ziv 1977)
This algorithm provides good compression on a wide variety of data with minimal use of system resources. This is also the algorithm used in the ZIP archive format.
It is unlikely that the zlib format will ever be extended to use any other algorithms, though the header makes allowance for this possibility.
(I know ezQuake utilizes a zip library, but I think that can only read zip files ... not 100%, haven't looked lately.)
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
andrewj
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Re: MD5 and Zip Libraries

Post by andrewj »

By MD5 you mean the message digest algorithm (not the model format), right?

One place is in Quake3: code/qcommon/md5.c

I've written a C++ class for it:
http://edge.svn.sourceforge.net/viewvc/ ... xt%2Fplain
http://edge.svn.sourceforge.net/viewvc/ ... xt%2Fplain

For ZIP archives, LibPHYSFS is probably the best way to go, though Quake3 does have reading code (for pk3 files) in code/qcommon/unzip.cc but it's pretty hard to follow.

I've written some *very basic* C++ code to read and write ZIP files:
http://oblige.svn.sourceforge.net/viewv ... xt%2Fplain
http://oblige.svn.sourceforge.net/viewv ... xt%2Fplain
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: MD5 and Zip Libraries

Post by Baker »

andrewj wrote:By MD5 you mean the message digest algorithm (not the model format), right?
Hehe, yeah. And I checked out your C++ class ... thank you.

One place is in Quake3: code/qcommon/md5.c
For ZIP archives, LibPHYSFS is probably the best way to go, though Quake3 does have reading code (for pk3 files) in code/qcommon/unzip.cc but it's pretty hard to follow.

I've written some *very basic* C++ code to read and write ZIP files:
http://oblige.svn.sourceforge.net/viewv ... xt%2Fplain
http://oblige.svn.sourceforge.net/viewv ... xt%2Fplain
Cool ... I'll check those out too. I'm not looking to do anything except the basics with .zip, but I had an interesting idea come to mind that requires writing out a .zip.

Thanks for both of those.

OBLIGE level maker

Ah cool! Back 4 years ago I snagged some random maze creator vb6 program off the internet and made it output brushes and made it have a button to run it through txqbsp. OMG ... the mazes were damn near impossible.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: MD5 and Zip Libraries

Post by revelator »

physfs is cool :) it also handles quake1 pak files doom formats etc.
Maybe good as a general archive handler for quake ?.
Productivity is a state of mind.
Spirit
Posts: 1068
Joined: Sat Nov 20, 2004 9:00 pm
Contact:

Re: MD5 and Zip Libraries

Post by Spirit »

Improve Quaddicted, send me a pull request: https://github.com/Quaddicted/quaddicted-data
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: MD5 and Zip Libraries

Post by mh »

7-zip was the first one I thought of too, but I'm not certain what would be involved in integrating it into another program the way Baker wants.

I use the RSA MD5 code which is public domain. http://www.ietf.org/rfc/rfc1321.txt
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: MD5 and Zip Libraries

Post by Baker »

funzip.c --- public domain

Code: Select all

/* funzip.c -- Not copyrighted 1992 by Mark Adler */

#define VERSION "2.1 of 23 October 1992"


/* You can do whatever you like with this source file, though I would
   prefer that if you modify it and redistribute it that you include
   comments to that effect with your name and the date.  Thank you.

   History:
   vers     date          who           what
   ----   ---------  --------------  ------------------------------------
    1.0   13 Aug 92  M. Adler        really simple unzip filter.
    1.1   13 Aug 92  M. Adler        cleaned up somewhat, give help if
                                     stdin not redirected, warn if more
                                     zip file entries after the first.
    1.2   15 Aug 92  M. Adler        added check of lengths for stored
                                     entries, added more help.
    1.3   16 Aug 92  M. Adler        removed redundant #define's, added
                                     decryption.
    1.4   27 Aug 92  G. Roelofs      added exit(0).
    1.5    1 Sep 92  K. U. Rommel    changed read/write modes for OS/2.
    1.6    6 Sep 92  G. Roelofs      modified to use dummy crypt.c and
                                     crypt.h instead of -DCRYPT.
    1.7   23 Sep 92  G. Roelofs      changed to use DOS_OS2; included
                                     crypt.c under MS-DOS.
    1.8    9 Oct 92  M. Adler        improved inflation error msgs.
    1.9   17 Oct 92  G. Roelofs      changed ULONG/UWORD/byte to ulg/ush/uch;
                                     renamed inflate_entry() to inflate();
                                     adapted to use new, in-place zdecode.
    2.0   22 Oct 92  M. Adler        allow file name argument, prompt for
                                     passwords and don't echo, still allow
                                     command-line password entry, but as an
                                     option.
    2.1   23 Oct 92  J. Gailly       fixed crypt/store bug,
                     G. Roelofs      removed crypt.c under MS-DOS, fixed
                                     decryption check to compare single byte.
 */


/*

   All funzip does is take a zip file from stdin and decompress the
   first entry to stdout.  The entry has to be either deflated or
   stored.  If the entry is encrypted, then the decryption password
   must be supplied on the command line as the first argument.

   funzip needs to be linked with inflate.o and crypt.o compiled from
   the unzip source.  If decryption is desired, the full version of
   crypt.c (and crypt.h) from zcrypt20.zip or later must be used.

 */

#include "unzip.h"
#include "crypt.h"

/* enforce binary i/o if recognized */
#if defined(__STDC__) || defined(DOS_OS2)
#  define BINIO
#endif

#ifdef BINIO
#  define FOPR "rb"
#  define FOPW "wb"
#else
#  define FOPR "r"
#  define FOPW "w"
#endif

/* PKZIP header definitions */
#define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
#define LOCFLG 6                /* offset of bit flag */
#define  CRPFLG 1               /*  bit for encrypted entry */
#define  EXTFLG 8               /*  bit for extended local header */
#define LOCHOW 8                /* offset of compression method */
#define LOCTIM 10               /* file mod time (for decryption) */
#define LOCCRC 14               /* offset of crc */
#define LOCSIZ 18               /* offset of compressed size */
#define LOCLEN 22               /* offset of uncompressed length */
#define LOCFIL 26               /* offset of file name field length */
#define LOCEXT 28               /* offset of extra field length */
#define LOCHDR 30               /* size of local header, including sig */
#define EXTHDR 16               /* size of extended local header, inc sig */

/* Macros for getting two-byte and four-byte header values */
#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))

/* Function prototypes */
ulg updcrc OF((uch *, int));
int inflate OF((void));
void err OF((int, char *));
void main OF((int, char **));

/* Globals */
FILE *in, *out;                 /* input and output files */
union work area;                /* inflate sliding window */
uch *outbuf;                    /* malloc'ed output buffer */
uch *outptr;                    /* points to next byte in output buffer */
int outcnt;                     /* bytes in output buffer */
ulg outsiz;                     /* total bytes written to out */
int decrypt;                    /* flag to turn on decryption */
char *key;                      /* not used--needed to link crypt.c */

/* Masks for inflate.c */
ush mask_bits[] = {
    0x0000,
    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};


/* Table of CRC-32's of all single-byte values (made by makecrc.c) */
ulg crc_32_tab[] = {
  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
  0x2d02ef8dL
};


ulg updcrc(s, n)
uch *s;                 /* pointer to bytes to pump through */
int n;                  /* number of bytes in s[] */
/* Run a set of bytes through the crc shift register.  If s is a NULL
   pointer, then initialize the crc shift register contents instead.
   Return the current crc in either case. */
{
  register ulg c;       /* temporary variable */

  static ulg crc = 0xffffffffL; /* shift register contents */

  if (s == NULL)
    c = 0xffffffffL;
  else
  {
    c = crc;
    while (n--)
      c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
  }
  crc = c;
  return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
}


void err(n, m)
int n;
char *m;
/* Exit on error with a message and a code */
{
  fprintf(stderr, "funzip error: %s\n", m);
  exit(n);
}


int ReadByte(b)
ush *b;
/* Used by inflate.c to get a byte (archaism from unzip) */
{
  register int c = getc(in);

  if (c == EOF)
    return 0;
#ifdef CRYPT
  if (decrypt)
    zdecode(c);
#endif
  *b = (ush)c;
  return 8;
}


int FlushOutput()
/* Empty output buffer */
{
  if (outcnt)
  {
    updcrc(outbuf, outcnt);
    if (fwrite((char *)outbuf, 1,outcnt,out) != outcnt)
      err(9, "out of space on stdout");
    outsiz += outcnt;
    outptr = outbuf;
    outcnt = 0;
  }
  return 0;
}


void main(argc, argv)
int argc;
char **argv;
/* Given a zip file on stdin, decompress the first entry to stdout. */
{
  uch h[LOCHDR];               /* first local header */
#ifdef CRYPT
  char *s = " [-password]";
  char *p;                      /* password */
#else /* !CRYPT */
  char *s = "";
#endif /* ?CRYPT */

  /* skip executable name */
  argc--;
  argv++;

#ifdef CRYPT
  /* get the command line password, if any */
  p = NULL;
  if (argc && **argv == '-')
  {
    argc--;
    p = 1 + *argv++;
  }
#endif /* ?CRYPT */

  /* if no file argument and stdin not redirected, give the user help */
  if (argc == 0 && isatty(0))
  {
    fprintf(stderr, "FUnZip (Filter UnZip), version %s\n", VERSION);
    fprintf(stderr, "usage: ... | funzip%s | ...\n", s);
    fprintf(stderr, "       ... | funzip%s  > outfile\n", s);
    fprintf(stderr, "       funzip%s infile.zip > outfile\n", s);
    fprintf(stderr,
      "       extracts to stdout the first zip entry of stdin.\n");
    exit(3);
  }

  /* prepare to be a binary filter */
  if ((outbuf = (uch *)malloc(OUTBUFSIZ)) == NULL)
    err(1, "out of memory");
  if (argc)
  {
    if ((in = fopen(*argv, FOPR)) == NULL)
      err(2, "cannot find input file");
  }
  else
  {
#ifdef DOS_OS2
    setmode(0, O_BINARY); /* some buggy C libraries require BOTH :-( the  */
#endif                  /*  setmode() call AND the fdopen() in binary mode */
    if ((in = fdopen(0, FOPR)) == NULL)
      err(2, "cannot find stdin");
  }
#ifdef DOS_OS2
  setmode(1, O_BINARY);
#endif
  if ((out = fdopen(1, FOPW)) == NULL)
    err(2, "cannot write to stdout");

  /* read local header, check validity, and skip name and extra fields */
  if (fread((char *)h, 1, LOCHDR, in) != LOCHDR || LG(h) != LOCSIG)
    err(3, "input not a zip file or empty");
  if (SH(h + LOCHOW) != STORED && SH(h + LOCHOW) != DEFLATED)
    err(3, "first entry not deflated or stored--can't funzip");
  fseek(in, (long)(SH(h + LOCFIL)) + (long)(SH(h + LOCEXT)), 1);

  /* if entry encrypted, decrypt and validate encryption header */
  if ((decrypt = h[LOCFLG] & CRPFLG) != 0)
#ifdef CRYPT
    {
      ush i, e;

      if (p == NULL)
        if ((p = (char *)malloc(PWLEN+1)) == NULL)
          err(1, "out of memory");
        else if ((p = getp("Enter password: ", p, PWLEN+1)) == NULL)
          err(1, "no tty to prompt for password");
      init_keys(p);
      for (i = 0; i < RAND_HEAD_LEN; i++)
        ReadByte(&e);
/*    if (e != (h[LOCFLG] & EXTFLG ? SH(h + LOCTIM) : SH(h + LOCCRC + 2)))  */
      if (e != (ush)(h[LOCFLG] & EXTFLG ? h[LOCTIM + 1] : h[LOCCRC + 3]))
        err(3, "incorrect password for first entry");
    }
#else /* !CRYPT */
    err(3, "cannot decrypt entry (need to recompile with full crypt.c)");
#endif /* ?CRYPT */

  /* prepare output buffer and crc */
  outptr = outbuf;
  outcnt = 0;
  outsiz = 0L;
  updcrc(NULL, 0);

  /* decompress */
  if (h[LOCHOW])
  {                             /* deflated entry */
    int r;
 
    if ((r = inflate()) != 0)
      if (r == 3)
        err(1, "out of memory");
      else
        err(4, "invalid compressed data--format violated");
  }
  else
  {                             /* stored entry */
    register ulg n;

    n = LG(h + LOCLEN);
    if (n != LG(h + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
      fprintf(stderr, "len %ld, siz %ld\n", n, LG(h + LOCSIZ));
      err(4, "invalid compressed data--length mismatch");
    }
    while (n--) {
      ush c = getc(in);
#ifdef CRYPT
      if (decrypt)
        zdecode(c);
#endif
      OUTB(c);
    }
  }
  FlushOutput();
  fflush(out);

  /* if extended header, get it */
  if ((h[LOCFLG] & EXTFLG) &&
      fread((char *)h + LOCCRC - 4, 1, EXTHDR, in) != EXTHDR)
    err(3, "zip file ended prematurely");

  /* validate decompression */
  if (LG(h + LOCCRC) != updcrc(outbuf, 0))
    err(4, "invalid compressed data--crc error");
  if (LG(h + LOCLEN) != outsiz)
    err(4, "invalid compressed data--length error");

  /* check if there are more entries */
  if (fread((char *)h, 1, 4, in) == 4 && LG(h) == LOCSIG)
    fprintf(stderr,
      "funzip warning: zip file has more than one entry--rest ignored\n");

  exit(0);
}
MD5.c

Code: Select all

/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
 */

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.

License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.

License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.

RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.

These notices must be retained in any copies of any part of this
documentation and/or software.
 */

/*


*/

#include "versions.h"

#pragma warning (disable: 4131)

#include "global.h"
#include "md5.h"

/* Constants for MD5Transform routine.
 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

static void MD5Transform PROTO_LIST ( (UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
( (unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
( (UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ( (POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ( (POINTER, int, unsigned int));

static unsigned char PADDING[64] =
{
	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* F, G, H and I are basic MD5 functions.
 */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits.
 */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
 */
#define FF(a, b, c, d, x, s, ac) { \
 (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
 (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
 (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
 (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
}

/* MD5 initialization. Begins an MD5 operation, writing a new context.
 */
void MD5Init (context)
MD5_CTX *context;                                        /* context */
{
	context->count[0] = context->count[1] = 0;
	/* Load magic initialization constants.
	*/
	context->state[0] = 0x67452301;
	context->state[1] = 0xefcdab89;
	context->state[2] = 0x98badcfe;
	context->state[3] = 0x10325476;
}

/* MD5 block update operation. Continues an MD5 message-digest
  operation, processing another message block, and updating the
  context.
 */
void MD5Update (context, input, inputLen)
MD5_CTX *context;                                        /* context */
unsigned char *input;                                /* input block */
unsigned int inputLen;                     /* length of input block */
{
	unsigned int i, index, partLen;

	/* Compute number of bytes mod 64 */
	index = (unsigned int) ( (context->count[0] >> 3) & 0x3F);

	/* Update number of bits */
	if ( (context->count[0] += ( (UINT4) inputLen << 3))
			< ( (UINT4) inputLen << 3))
		context->count[1]++;

	context->count[1] += ( (UINT4) inputLen >> 29);

	partLen = 64 - index;

	/* Transform as many times as possible.
	*/
	if (inputLen >= partLen)
	{
		MD5_memcpy
		( (POINTER) &context->buffer[index], (POINTER) input, partLen);
		MD5Transform (context->state, context->buffer);

		for (i = partLen; i + 63 < inputLen; i += 64)
			MD5Transform (context->state, &input[i]);

		index = 0;
	}
	else
		i = 0;

	/* Buffer remaining input */
	MD5_memcpy
	( (POINTER) &context->buffer[index], (POINTER) &input[i],
	  inputLen - i);
}

/* MD5 finalization. Ends an MD5 message-digest operation, writing the
  the message digest and zeroizing the context.
 */
void MD5Final (digest, context)
unsigned char digest[16];                         /* message digest */
MD5_CTX *context;                                       /* context */
{
	unsigned char bits[8];
	unsigned int index, padLen;

	/* Save number of bits */
	Encode (bits, context->count, 8);

	/* Pad out to 56 mod 64.
	*/
	index = (unsigned int) ( (context->count[0] >> 3) & 0x3f);
	padLen = (index < 56) ? (56 - index) : (120 - index);
	MD5Update (context, PADDING, padLen);

	/* Append length (before padding) */
	MD5Update (context, bits, 8);

	/* Store state in digest */
	Encode (digest, context->state, 16);

	/* Zeroize sensitive information.
	*/
	MD5_memset ( (POINTER) context, 0, sizeof (*context));
}

/* MD5 basic transformation. Transforms state based on block.
 */
static void MD5Transform (state, block)
UINT4 state[4];
unsigned char block[64];
{
	UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

	Decode (x, block, 64);

	/* Round 1 */
	FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
	FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
	FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
	FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
	FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
	FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
	FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
	FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
	FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
	FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
	FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
	FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
	FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
	FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
	FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
	FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

	/* Round 2 */
	GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
	GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
	GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
	GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
	GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
	GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
	GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
	GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
	GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
	GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
	GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
	GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
	GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
	GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
	GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
	GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

	/* Round 3 */
	HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
	HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
	HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
	HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
	HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
	HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
	HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
	HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
	HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
	HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
	HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
	HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
	HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
	HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
	HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
	HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */

	/* Round 4 */
	II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
	II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
	II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
	II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
	II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
	II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
	II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
	II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
	II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
	II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
	II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
	II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
	II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
	II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
	II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
	II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */

	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;

	/* Zeroize sensitive information.
	*/
	MD5_memset ( (POINTER) x, 0, sizeof (x));
}

/* Encodes input (UINT4) into output (unsigned char). Assumes len is
  a multiple of 4.
 */
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
	unsigned int i, j;

	for (i = 0, j = 0; j < len; i++, j += 4)
	{
		output[j] = (unsigned char) (input[i] & 0xff);
		output[j+1] = (unsigned char) ( (input[i] >> 8) & 0xff);
		output[j+2] = (unsigned char) ( (input[i] >> 16) & 0xff);
		output[j+3] = (unsigned char) ( (input[i] >> 24) & 0xff);
	}
}

/* Decodes input (unsigned char) into output (UINT4). Assumes len is
  a multiple of 4.
 */
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
	unsigned int i, j;

	for (i = 0, j = 0; j < len; i++, j += 4)
		output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
					(((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
}

/* Note: Replace "for loop" with standard memcpy if possible.
 */

static void MD5_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
	unsigned int i;

	for (i = 0; i < len; i++)
		output[i] = input[i];
}

/* Note: Replace "for loop" with standard memset if possible.
 */
static void MD5_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
	unsigned int i;

	for (i = 0; i < len; i++)
		( (char *) output)[i] = (char) value;
}


/*
=================
MD5_Driver

Standard driver implementation for encoding data of an arbitrary length.  Both data and checksum
must be valid pointers!!!
=================
*/
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final


void MD5_Checksum (unsigned char *data, int dataLen, unsigned char *checksum)
{
	MD_CTX context;
	int i;
	unsigned char digest[16];

	MDInit (&context);
	MDUpdate (&context, data, dataLen);
	MDFinal (digest, &context);

	// copy digest to checksum
	for (i = 0; i < 16; i++)
	{
		checksum[i] = digest[i];
	}
}


char MD5_Compare (unsigned char *digest1, unsigned char *digest2)
{
	int i;

	for (i = 0; i < 16; i++)
	{
		if (digest1[i] != digest2[i])
			return 0;
	}

	return 1;
}


void MD5_Copy (unsigned char *srcdigest, unsigned char *dstdigest)
{
	int i;

	for (i = 0; i < 16; i++)
	{
		dstdigest[i] = srcdigest[i];
	}
}

The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: MD5 and Zip Libraries

Post by Spike »

the only time I've used md5 hashes was for smtp/pop3 protocol stuff...
if you're protecting passwords, you should use something else if you're not bound by compatibility.
if its just for cheat protection then I guess it makes no real difference.
sha1 is generally greatly favoured nowadays.
Stroggos
Posts: 50
Joined: Tue Apr 14, 2009 11:40 am
Location: Australia

Re: MD5 and Zip Libraries

Post by Stroggos »

miniz is also Public Domain:
http://code.google.com/p/miniz/

On top of that if you're already using zlib all you need to do is place the source file in your project and you're set.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: MD5 and Zip Libraries

Post by Baker »

Spike wrote:if its just for cheat protection then I guess it makes no real difference.
That wasn't something I was thinking or worrying about.

I'm thinking about the traditional uses of checksums, like valid validation (did file download correctly, did file change?) or texture compares and such.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: MD5 and Zip Libraries

Post by Spike »

aye, makes no real difference then. md5 is a little faster than sha1, so still works nicely for hashes and stuff, though its not as fast as eg adler32 (commonly part of zlib).
heck, texture compares could probably be just the first four bytes of the image, though I know that zquake+ uses crcs for that.

from a quakeworld perspective, all engines already have code for md4, as well as some 16bit crc. Spoilt for choice really. The crc provides network proxy protection (supposedly), while md4 provides map verification to stop people from chopping out all the walls in the map.

Soo... As you were!
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: MD5 and Zip Libraries

Post by Baker »

Spike wrote:md4 provides map verification to stop people from chopping out all the walls in the map.
Well, anti-wallhack means I care about this in what way exactly?

Sure particles aren't filtered, but that's rather tame stuff. I guess in my mind I consider model checking and map hacking as entirely irrelevant in this day and age. Maybe still cheaters can "see someone behind them", but if you can be silent waiting around the next corner unseen and nothing a cheater can do about it, I see that as a settled issue.

I thought even Quakeworld was using anti-wallhack now. Maybe I am wrong? If so, what is the reason QW will not use anti-wallhack?
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Post Reply