Uso de funciones de hash mediante la librería OpenSSL

Un sencillo pero útil ejemplo de uso de la librería OpenSSL para realizar resumentes (hashes) en algunos algoritmos conocidos: MD4, MD5, SHA1, etc.



/******************************************************************************
*
*  autor: Daniel Lerch
*
*  Referencias:
*  Network security with OpenSSL (O'Reilly)
*  [Adaptacion de un ejemplo del libro para multiples algoritmos hash]
*
*  Compilacion:
*  $ gcc digest.c -o digest -lssl
*
******************************************************************************/
                                                                                
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
                                                                                
                                                                                
#define READSIZE 1024
                                                                                
unsigned char *simple_digest (char *alg,
                              char *buffer,
                              unsigned int len,
                              int *olen)
{
   EVP_MD *m;
   EVP_MD_CTX ctx;
   unsigned char *ret;
                                                                                
   OpenSSL_add_all_digests ();
   if (!(m = (EVP_MD*) EVP_get_digestbyname (alg)))
      return NULL;
   if (!(ret = (unsigned char *) malloc (EVP_MAX_MD_SIZE)))
      return NULL;
   EVP_DigestInit (&ctx, m);
   EVP_DigestUpdate (&ctx, buffer, len);
   EVP_DigestFinal (&ctx, ret, olen);
   return ret;
}
                                                                                
void print_hex (unsigned char *bs, unsigned int n)
{
   int i;
                                                                                
   for (i = 0; i < n; i++)
      printf ("%02x", bs[i]);
}

unsigned char *read_file (FILE * f, int *len)
{
   unsigned char *buffer = NULL, *last = NULL;
   unsigned char inbuffer[READSIZE];
   int tot, n;
                                                                                
   tot = 0;
   for (;;)
   {
      n = fread (inbuffer, sizeof (unsigned char), READSIZE, f);
      if (n > 0)
      {
         last = buffer;
         buffer = (unsigned char *) malloc (tot + n);
         memcpy (buffer, last, tot);
         memcpy (&buffer[tot], inbuffer, n);
         if (last)
            free (last);
         tot += n;
         if (feof (f) > 0)
         {
            *len = tot;
            return buffer;
         }
      }
      else
      {
         if (buffer)
            free (buffer);
         break;
      }
   }
   return NULL;
}

unsigned char *process_file (char *algorithm, FILE * f, unsigned int *olen)
{
   int filelen;
   unsigned char *ret, *contents = read_file (f, &filelen);
   if (!contents)
      return NULL;
   ret = simple_digest (algorithm, contents, filelen, olen);
   free (contents);
   return ret;
}
                                                                                
int process_stdin (char *algorithm)
{
   unsigned int olen;
   unsigned char *digest = process_file (algorithm, stdin, &olen);
   if (!digest)
      return 0;
   print_hex (digest, olen);
   printf ("\n");
   free(digest);
   return 1;
}
                                                                                
void usage (char *progname) {
                                                                                
   printf ("Usage: %s [ md2 | md4 | md5 | sha | sha1 ] [ Files ] \n\n",
            progname);
   exit(0);
}

int main (int argc, char *argv[])
{
   int i;
                                                                                
   /* Sin parametros */
   if (argc < 2) usage(argv[0]);
                                                                                
   /* Verificamos los algoritmos */
   if ( (strcmp(argv[1], "md2")  != 0) &&
        (strcmp(argv[1], "md4")  != 0) &&
        (strcmp(argv[1], "md5")  != 0) &&
        (strcmp(argv[1], "sha")  != 0) &&
        (strcmp(argv[1], "sha1") != 0) ) usage(argv[0]);
                                                                                
                                                                                
   /* Un solo parametro, entrada estandar */
   if (argc == 2) { if (!process_stdin (argv[1])) perror ("stdin"); }
                                                                                
   /* Lee y procesa todos los parametros recibidos */
   else {
                                                                                
      for (i = 2; i < argc; i++) {
                                                                                
         FILE *file = fopen (argv[i], "rb");
         unsigned int olen;
         unsigned char *digest;
                                                                                
         if (!file) { perror (argv[i]); return -1; }
                                                                                
         digest = process_file (argv[1], file, &olen);
                                                                                
         if (!digest) {
                                                                                
            fclose (file);
            return -1;
         }
                                                                                
         fclose (file);
         print_hex (digest, olen);
         printf ("  %s\n", argv[i]);
         free(digest);
      }
   }
   return 1;
}




daniellerch.com