views:

172

answers:

8

Hello,

I am trying to use md5 code to calculate checksums of file. Now the given function prints out the (previously calculated) checksum on screen, but I want to store it in a variable, to be able to compare it later on.

I guess the main problem is that I want to store the content of an array in one variable. How can I manage that? Probably this is a very stupid question, but maybe somone can help.

Below is the function to print out the value. I want to modify it to store the result in one variable.

static void MDPrint (MD5_CTX* mdContext)
{
 int i;
 for (i = 0; i < 16; i++)
 {
   printf ("%02x", mdContext->digest[i]);
 } // end of for 
} // end of function

For reasons of completeness the used struct:

 /* typedef a 32 bit type */
 typedef unsigned long int UINT4;

 /* Data structure for MD5 (Message Digest) computation */
 typedef struct {
  UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */
  UINT4 buf[4];                                    /* scratch buffer */
  unsigned char in[64];                              /* input buffer */
  unsigned char digest[16];     /* actual digest after MD5Final call */
 } MD5_CTX;

and the used function to calculate the checksum:

static int MDFile (char* filename)
{
 FILE *inFile = fopen (filename, "rb");
 MD5_CTX mdContext;
 int bytes;
 unsigned char data[1024];

 if (inFile == NULL) {
    printf ("%s can't be opened.\n", filename);
    return -1;
 } // end of if
 MD5Init (&mdContext);
 while ((bytes = fread (data, 1, 1024, inFile)) != 0)
 MD5Update (&mdContext, data, bytes);
 MD5Final (&mdContext);
 MDPrint (&mdContext);
 printf (" %s\n", filename);
 fclose (inFile);
 return 0;
}
+1  A: 

You can define a variable:

char **md5sums;

You will then need to modify MDPrint to instead return a malloced null-terminated string with the 32 hex digits. You can basically reuse your existing loop, but with sprintf instead.

Then have main add each md5sum (a char*) to md5sums. You will need to use realloc to allocate memory for md5sums because you don't know the number of elements up front.

It should be:

static char* MDString (mdContext) 
MD5_CTX *mdContext; 
{ 
  int i; 
  char *digest = malloc(sizeof(char) * 33);
  if(digest == NULL)
  { 
    return NULL;
  }
  for (i = 0; i < 16; i++)
  { 
    sprintf(digest + (i * 2), "%02x", mdContext->digest[i]); 
  } 
  return digest;
}

Also, you should modify your code by editing your question. And why are you using K&R syntax?

EDIT: I fixed some incorrect counts.

Matthew Flaschen
Thanks for all your comments so far. I tried the way you proposed before, but I did not manage to use sprintf with the correct parameters in the existing loop.My attempts looked like:Previously initiated: char test[]="d41d8cd98f00b204e9800998ecf8427e";In the loop: sprintf(test[i],"%02x",mdContext->digest[i]); which results in "passing argument 1 of ‘sprintf’ makes pointer from integer without a cast"
OldMacDonald
A: 

Store it as a string and then use strcmp() to compare.

scribu
strcmp is only for null-terminated strings. Use memcmp here.
interjay
A: 

Just leave in an array! You don't have you store it in variable; because it is ALREADY in a variable.. Just create global variable, store MD5 hash in it and compare to it later.

What you need is MD5IsEqual function, which takes 2 arrays like this.

int MD5IsEqual(unsigned char *x, unsigned char* y)
{
   int i;
   for(i=0; i<16;i++)
      if(x[i] != y[i]) 
          return 0;
   return 1;
}
Yousf
A: 

Why not make the function

MD5File(char * filename, unsigned char *digest){

/* as before */ memcpy(digest, mdContext->digest, 16); return;

}

so that outside the function you have access to the digest (after printing it) ?

The digest is just an array of 16 unsigned char...

Henno Brandsma
+4  A: 

Declare an array and memcpy the result.

Example:

unsigned char old_md5_dig[16]; // <-- binary format
...

MD5_CTX mdContext;
MD5Init(&mdContext);
MD5Update(&mdContext, data, bytes);
MD5Final(&mdContext);
memcpy(old_md5_dig, mdContext.digest, 16); // <--

Edit: to compare the previous with the new md5 hash you can use memcmp,

if (memcmp(old_md5_dig, mdContext.digest, 16)) {
   // different hashes
}
Nick D
This is simple, correct and exactly what the OP needs. I would only add that you would later use `memcmp()` to compare such arrays.
caf
+1 for memcmp. Hooray!
Duracell
+1  A: 

Just pass a char buffer and its size to this function:

static void MDGen (mdContext, buf, size)
MD5_CTX *mdContext;
char *buf;
size_t size;
{
    int i;
    int minSize = 33; // 16 pairs of hex digits plus terminator

    if ((buf != NULL) && (size >= minSize))
    {
        memset(buf, 0, size);

        for (i = 0; i < 16; i++)
        {
            snprintf(buf + (i*2), size - (i*2), "%02x", mdContext->digest[i]);
        }
    }
}
Amardeep
I will try this, here I think I see what my problem with the s(n)printf function was.
OldMacDonald
+1  A: 

Since you want to duplicate, store, compare, free and probably more the MD5 digest, just create a md5_t type and write appropriate functions to manipulate it, ie :

typedef char md5_t[16];

md5_t *md5_new( MD5_CTX *pMD5Context )
{
     md5_t *pMD5 = malloc( sizeof( md5_t ) );
     memcpy( pMD5, pMD5Context->digest, 16 );
     return pMD5 ;
}

int md5_cmp( md5_t *pMD5A, md5_t *pMD5B )
{
     return memcmp( pMD5A, pMD5B, 16 );
}

void md5_print( md5_t *pMD5 )
{
     ...
}


void md5_free( md5_t *pMD5 )
{
     free( pMD5 );
}

And so on ... Next, create a type for your MD5 array and simple functions to manipulate it :

 typedef struct md5array_t { 
     unsigned int  uSize ;
     md5_t       **ppMD5 ;
 }

 md5array_t *md5array_new()
 {
     md5array_t *pArray = malloc( sizeof( md5array_t );
     pArray->uSize = 0 ;
     pArray->ppMD5 = NULL ;
 }

 md5array_t *md5array_add( md5array_t *pArray, md5_t *pMD5 )
 {
     pArray->uSize ++ ;
     pArray = realloc( pArray, pArray->uSize + sizeof( md5_t * ) );
     pArray->ppMD5[ pArray->uSize-1 ] = pMD5 ;
 }

 md5_t *md5array_get( md5array_t *pArray, unsigned int uIndex )
 {
     return pArray->ppMD5[ uIndex ];
 }

 void md5array_free( md5array_t *pArray }
 {
      /* I let you find what to write here.
      Be sure to read AND understand the previous
      funtions. */
 }

To resume : create a type and the functions you need to manipulate it as soon as you want to do more than one operation with a datum. You don't need to create a real, generic type with full-blown functions representing as many operations you can imagine on that type : just code what you need. For example, in the md5array_t, you can add a md5_t * but you cannot delete it (unless you write the function void md5array_del( md5array_t *pArray *, int iIndex ).

P.S. : my C code is here to "illustrate" my point of view, not to be useable by just copying/pasting it as is ...

Platypus
`md5_t` is an array type, and you cannot have a function returning an array, so the definition of `md5_new()` is an error.
caf
@caf You're right, this was a typo error, now corrected. Thanks.
Platypus
A: 

You know where the sum is stored by the way you print it: through ->digest[i]. Which is defined like

unsigned char digest[16];

So you basically just need to copy these 16 unsigned char in another array of unsigned char (at least 16 unsigned char long). The function memcpy can do it. If you need comparing two sums, you can use memcmp (the comparing size will be 16*sizeof(unsigned char) which is 16, being sizeof(unsigned char) 1.

ShinTakezou