type error in C

Hi

For my my next project I would need a good hash function (SHA-1 or MD5). On the internet I have found AVR-Crypto-Lib project which includes all the implementations (in C or ASM) I need. First I located the source files for MD5 function (md5.h, md5.c, md5_sbox.h). I compiled the source (avr-gcc -mmcu=atmega328p -c md5.c) and I copied the object files + two header files in the /Library/MD5 directory.

Then I wrote a small program:

#include <md5.h>
#include <md5_sbox.h>

char strA[] = "Hello world!";
char destination[16];

void setup(){
md5(destination, strA, 72);
}

but I got the following error:

error: cannot convert 'char*' to 'uint8_t ()[16]' for argument '1' to 'void md5(uint8_t ()[16], const void*, uint32_t).

Function md5 should be the calling function. Its first argument takes pointer to hash destination, second argument is string to calculate hash from and the last argument is the length of the previous argument in bits.

Md5 function is defined as: void md5(md5_hash_t* dest, const void* msg, uint32_t length_b)
md5_hast_t if defined as: typedef uint8_t md5_hash_t[MD5_HASH_BYTES]

When I try to use C files instead of precompiled object files I get the same error. Can somebody please help me?

Thanks a lot.

Crt.

Try changing

char destination[16];

to

uint8_t destination[16];

Hi

Thanks for your help, but I get similar error.

error: cannot convert 'uint8_t*' to 'uint8_t ()[16]' for argument '1' to 'void md5(uint8_t ()[16], const void*, uint32_t)

I called md5(&destination, strA, 72); and it seems to get further. It gives me an error "undefined reference to md5..." I think it is because the md5_asm.o file is not being copied to the temp directory, but I cannot figure out how to get it to copy.

#include <md5.h>
#include <md5_sbox.h>

char strA[] = "Hello world!";
md5_hash_t destination;

void setup(){ 
 md5(&destination, strA, 72);
}

maybe?

I was able to get it to work if I put the contents of the md5.c, md5.h, and md5_sbox.h, files directly into the sketch. Here it is:

#include <stdint.h>
#include <avr/pgmspace.h>

extern "C" {
  uint32_t md5_T[] PROGMEM = {
        0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 
        0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 
        0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 
        0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 
        0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 
        0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 
        0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 
        0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 
        0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 
        0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 
        0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 
        0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 
        0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
  
  #define MD5_HASH_BITS  128
  #define MD5_HASH_BYTES (MD5_HASH_BITS/8)
  #define MD5_BLOCK_BITS 512
  #define MD5_BLOCK_BYTES (MD5_BLOCK_BITS/8)
  
  typedef struct md5_ctx_st {
        uint32_t a[4];
        uint32_t counter;
  } md5_ctx_t;
  
  #ifndef MD5_HASH_
    #define MD5_HASH_
    typedef uint8_t md5_hash_t[MD5_HASH_BYTES];
  #endif
  
  void md5_init(md5_ctx_t *s){
        s->counter = 0;
        s->a[0] = 0x67452301;
        s->a[1] = 0xefcdab89;
        s->a[2] = 0x98badcfe;
        s->a[3] = 0x10325476;
  }
  
  static 
  uint32_t md5_F(uint32_t x, uint32_t y, uint32_t z){
        return ((x&y)|((~x)&z));
  }
  
  static
  uint32_t md5_G(uint32_t x, uint32_t y, uint32_t z){
        return ((x&z)|((~z)&y));
  }
  
  static
  uint32_t md5_H(uint32_t x, uint32_t y, uint32_t z){
        return (x^y^z);
  }
  
  static
  uint32_t md5_I(uint32_t x, uint32_t y, uint32_t z){
        return (y ^ (x | (~z)));
  }
  
  typedef uint32_t md5_func_t(uint32_t, uint32_t, uint32_t);
  
  #define ROTL32(x,n) (((x)<<(n)) | ((x)>>(32-(n))))  
  
  static
  void md5_core(uint32_t* a, void* block, uint8_t as, uint8_t s, uint8_t i, uint8_t fi){
        uint32_t t;
        md5_func_t* funcs[]={md5_F, md5_G, md5_H, md5_I};
        as &= 0x3;
        /* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
        t = a[as] + funcs[fi](a[(as+1)&3], a[(as+2)&3], a[(as+3)&3]) 
            + *((uint32_t*)block) + pgm_read_dword(md5_T+i) ;
        a[as]=a[(as+1)&3] + ROTL32(t, s);
  }
  
  void md5_nextBlock(md5_ctx_t *state, const void* block){
        uint32_t      a[4];
        uint8_t            m,n,i=0;
        /* this requires other mixed sboxes */
        a[0]=state->a[0];
        a[1]=state->a[1];
        a[2]=state->a[2];
        a[3]=state->a[3];
        
        /* round 1 */
        uint8_t s1t[]={7,12,17,22}; // 1,-1   1,4   2,-1   3,-2
        for(m=0;m<4;++m){
              for(n=0;n<4;++n){
                    md5_core(a, &(((uint32_t*)block)[m*4+n]), 4-n, s1t[n],i++,0);
              }
        }
        /* round 2 */
        uint8_t s2t[]={5,9,14,20}; // 1,-3   1,1   2,-2   2,4
        for(m=0;m<4;++m){
              for(n=0;n<4;++n){
                    md5_core(a, &(((uint32_t*)block)[(1+m*4+n*5)&0xf]), 4-n, s2t[n],i++,1);
              }
        }
        /* round 3 */
        uint8_t s3t[]={4,11,16,23}; // 0,4   1,3   2,0   3,-1
        for(m=0;m<4;++m){
              for(n=0;n<4;++n){
                    md5_core(a, &(((uint32_t*)block)[(5-m*4+n*3)&0xf]), 4-n, s3t[n],i++,2);
              }
        }
        /* round 4 */
        uint8_t s4t[]={6,10,15,21}; // 1,-2   1,2   2,-1   3,-3
        for(m=0;m<4;++m){
              for(n=0;n<4;++n){
                    md5_core(a, &(((uint32_t*)block)[(0-m*4+n*7)&0xf]), 4-n, s4t[n],i++,3);
              }
        }
        state->a[0] += a[0];
        state->a[1] += a[1];
        state->a[2] += a[2];
        state->a[3] += a[3];
        state->counter++;
  }
  
  void md5_lastBlock(md5_ctx_t *state, const void* block, uint16_t length_b){
        uint16_t l;
        uint8_t b[64];
        while (length_b >= 512){
              md5_nextBlock(state, block);
              length_b -= 512;
              block = ((uint8_t*)block) + 512/8;
        }
        memset(b, 0, 64);
        memcpy(b, block, length_b/8);
        /* insert padding one */
        l=length_b/8;
        if(length_b%8){
              uint8_t t;
              t = ((uint8_t*)block)[l];
              t |= (0x80>>(length_b%8));
              b[l]=t;
        }else{
              b[l]=0x80;
        }
        /* insert length value */
        if(l+sizeof(uint64_t) >= 512/8){
              md5_nextBlock(state, b);
              state->counter--;
              memset(b, 0, 64-8);
        }
        *((uint64_t*)&b[64-sizeof(uint64_t)]) = (state->counter * 512) + length_b;
        md5_nextBlock(state, b);
  }
  
  void md5_ctx2hash(md5_hash_t* dest, const md5_ctx_t* state){
        memcpy(dest, state->a, MD5_HASH_BYTES);
  }
  
  void md5(md5_hash_t* dest, const void* msg, uint32_t length_b){
        md5_ctx_t ctx;
        md5_init(&ctx);
        while(length_b>=MD5_BLOCK_BITS){
              md5_nextBlock(&ctx, msg);
              msg = (uint8_t*)msg + MD5_BLOCK_BYTES;
              length_b -= MD5_BLOCK_BITS;
        }
        md5_lastBlock(&ctx, msg, length_b);
        md5_ctx2hash(dest, &ctx);
  }
}

char strA[] = "Hello World!";
md5_hash_t destination; // OR: uint8_t destination[16];

void setup() {
  Serial.begin(9600);
}

void loop() {
  // Pass the address of the destination arry, the string, and the length of the string *in bits*.
  md5(&destination, strA, strlen(strA) * 8);  

  // Testing: Output the byte array to the serial montior.
  int i;
  for (i = 0; i < 16; i = i + 1) {
    Serial.print(destination[i], HEX);
    Serial.print(" ");
  }
  Serial.println("");

  delay(1000);  
}

I would rather be able to put the md5 stuff in a Library, but when I do that it compains that md5_t has multiple definitions. It almost seems that the #ifndef isn't working. I am not a C/C++ guy, so I don't really know what to do.

I might have a solution, if you still need it. I Haven't worked with the AVR Crypto Lib yet, not sure if I want to either (only becuase I would like to implement this stuff on my own! ;D), but I have altered the MD5 source code so it works w/ the Arduino. Basically I altered the typedefs and function declarations and definitions so that it compiles in Arduino. I have the altered source code and a working example, I will post the link in my next post.

Also, I had to put global.h, MD5.h, and MD5.c into C:\Program Files\Arduino\hardware\arduino\cores\arduino, I'm using Windows and that's the only way it would see those files, even in the same directory as the .pde wouldn't work. Of course YRMV.

I'll also post the code here for convenience.

global.h

/* GLOBAL.H - RSAREF types and constants */

/* PROTOTYPES should be set to one if and only if the compiler
 * supports function argument prototyping.
 * The following makes PROTOTYPES default to 0 if it has not already
 * been defined with C compiler flags.
 */
#ifndef PROTOTYPES
#define PROTOTYPES 0
#endif

/*Modified by MMoore http://mikestechspot.blogspot.com
Changed typedefs to be fully compatible w/ Arduino 08/09/2010 */

/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;

/* UINT2 defines a two byte word */
typedef unsigned int UINT2;

/* UINT4 defines a four byte word */
typedef unsigned long UINT4;

/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
 * If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
 * returns an empty list.
 */
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif

MD5.h

/* MD5.H - header file for MD5C.C
 * 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.
 */

/* MD5 context. */
typedef struct {
  UINT4 state[4];                                   /* state (ABCD) */
  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
  unsigned char buffer[64];                         /* input buffer */
} MD5_CTX;

void MD5Init (MD5_CTX *);
void MD5Update (MD5_CTX *, unsigned char *, unsigned int);
void MD5Final (unsigned char [16], MD5_CTX *);

/*Below added by MMoore http://mikestechspot.blogspot.com*/
void MD5 (unsigned char [], unsigned int);

MD5.pde (My example code)

/*MD5.PDE*/
/*THIS PROGRAM WILL HASH A STRING OR OTHER INPUT, USING THE MD5 HASHING FUNCTION*/
/*Created by MDMoore http://mikestechspot.blogspot.com*/

#include <MD5.c>

int incomingByte = 0;
int x = 0;
unsigned char strMessage[1024];

void setup(){
  Serial.begin(9600);  
}

void loop(){

  incomingByte = 0;
  Serial.println("");
  x = 0;
  
  
  Serial.print("Enter string to hash(1KB Max): ");
  
  while((incomingByte != 13) || x >= 1023){
    
    if(Serial.available() > 0){
      
      incomingByte = Serial.read();
      
        strMessage[x] = incomingByte;
        
        Serial.print(strMessage[x]);
        
        ++x;
    }
    
  }
  
  MD5(strMessage, (x-1)); //When calling the MD5 function, pass in the length as (length  - 1), so the NULL '\0' character is not hashed as well
  
  Serial.print("\nMessage Received: ");
  
   x = 0;

  while(strMessage[x] != '\0'){
    Serial.print(strMessage[x]);
    ++x;
  }
  Serial.println("");
  
  
  
  Serial.print("Hash Calculated As: ");
  
  x = 0;

  while(x<=15){
    PrintHex8((unsigned char *)&MD5Digest[x], 1); //The Hash is stored in a static variable in MD5.c called MD5Digest, of type unsigned char[16]
    ++x;
  }
  
  Serial.println("");
  
}

/*Taken from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1279500031 */
void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
      char tmp[16];
        for (int i=0; i<length; i++) {
          sprintf(tmp, "%.2X",data[i]);
          Serial.print(tmp);
        }
}

MD5.c (Part 1 of 2)

/* 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 "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(UINT4 [4], unsigned char [64]);
static void Encode(unsigned char *, UINT4 *, unsigned int);
static void Decode(UINT4 *, unsigned char *, unsigned int);
static void MD5_memcpy(POINTER, POINTER, unsigned int);
static void MD5_memset(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
};

static unsigned char MD5Digest[16];

/* 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 (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 (MD5_CTX *context, unsigned char *input,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 (unsigned char digest[16], MD5_CTX *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 (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));
}

MD5.c (Part 2 of 2)

/* Encodes input (UINT4) into output (unsigned char). Assumes len is
 * a multiple of 4.
 */
static void Encode (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 (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 (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 (POINTER output, int value, unsigned int len)
{
  unsigned int i;

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

/* Modified by MMoore http://mikestechspot.blogspot.com
Called from Arduino it takes the char array and the length of the
char array (without the '\0' NULL at the end) and stores the result
inside the static variable MD5Digest[16], an unsigned char[] declared
at the top of this file. */
void MD5(unsigned char strInputString[], unsigned int len){
      
      MD5_CTX ctx;
      MD5Init(&ctx);

      MD5Update(&ctx, strInputString, len);
      MD5Final(MD5Digest, &ctx);


}

Sorry, I should have posted this a while ago. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1272577380/3 MD5 library.

@Moore: I used your code and am getting the following:

Message Received: 4EA92B4292701F318222 (8 2 2 2 )
Hash Calculated As: 4C155E724314EE9CED5EEBF5BB9C0A81
Expected: BEFF520F8280591AC0BBCB83B468FAA5

Any ideas why it's not the same... I have included my code below:

/*MD5.PDE*/
/*THIS PROGRAM WILL HASH A STRING OR OTHER INPUT, USING THE MD5 HASHING FUNCTION*/
/*Created by MDMoore http://mikestechspot.blogspot.com*/

#include <MD5.c>
#include <WString.h>
#include <string.h>
String pair = "4EA92B4292701F31";  
String passcode = "8222";  
String expected = "BEFF520F8280591AC0BBCB83B468FAA5";

int x = 0;
unsigned char strMessage[1024];

void setup(){
  Serial.begin(115200); 
 
  x = 0;
  
  
     for (int i=0; i<pair.length(); i++){
      strMessage[x] = pair.charAt(i);
      ++x;
     }
  
     for (int i=0; i<passcode.length(); i++){
      strMessage[x] = passcode.charAt(i);
      ++x;
      strMessage[x] = 0x00;
      ++x;
     }
     
     strMessage[x] = 0x01; 
        
    Serial.print(strMessage[x]);
        
  MD5(strMessage, (x-1)); //When calling the MD5 function, pass in the length as (length  - 1), so the NULL '\0' character is not hashed as well
  
  Serial.print("\nMessage Received: ");
  
   x = 0;

  while(strMessage[x] != '\1'){
    Serial.print(strMessage[x]);
    ++x;
  }
  Serial.println("");
  
  
  
  Serial.print("Hash Calculated As: ");
  
  x = 0;

  while(x<=15){
    PrintHex8((unsigned char *)&MD5Digest[x], 1); //The Hash is stored in a static variable in MD5.c called MD5Digest, of type unsigned char[16]
    ++x;
  }
  
  Serial.println("");
  
   Serial.print("Expected: ");
    Serial.println(expected);
  
}

void loop(){

 
  
}

/*Taken from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1279500031 */
void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
      char tmp[16];
        for (int i=0; i<length; i++) {
          sprintf(tmp, "%.2X",data[i]);
          Serial.print(tmp);
        }
}

Nevermind... I got it working! Was off by one count.

THANKS!