Algoritmo SHA-1

El algoritmo SHA-1(una función resumen más) se utiliza como firma digital, NO es un algoritmo criptográfico, sino, como complemento de uno, como detección de código auténtico, etc.
Dado un parámetro como entrada 2 veces consecutivas, devuelve el mismo resultado.

Esta implementado en una clase, para la plataforma Win32.

/*
*           "$id: sha1.h,v 1.6 01/01/2007 $"
*
*           Abstract:
*                      Definitions/Declarations for class Csha.
*                      Implementación del Algoritmo SHA-1.
*                      Función Resumen para detectar autenticidad de
*                      código dentro de un algoritmo criptográfico.
*
*           Write By:
*                      Daniel Tomás Borelli
*                      daltomi@gmail.com
*
*           Revision History:
*                      "$log:sha1.h,v 1.5 01/01/2007 $"
*                      Initial Revision.
*                      Se eliminó la inclusión del arch. 'stdafx.h'.
*
*           Copyright (C) 2007 Daniel Tomás Borelli
*/

#ifndef __SHA_H__
#define __SHA_H__

#include "stdlib.h"
#include "stdio.h"
#include "string.h"

#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

#define F( x,  y, z) (((x) & (y)) | ((~x) & (z)))
#define G( x,  y, z) ((x) ^ (y) ^ (z))
#define H( x,  y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))

typedef unsigned char*                      POINTER;

typedef unsigned __int8                     UI8;
typedef unsigned __int16        UI16;
typedef unsigned __int32        UI32;

static const UI32 register_state[]         = {0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0};
static const UI32 register_key[]           = {0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};

static UCHAR register_block[64]          = {80, 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};
typedef struct {
             unsigned char buffer_block[64];
             UI32 count[2];
             UI32 abcde[5];
}SHA_CTX;

/*
*           'Csha' - Definición de la clase.
*/
class Csha{
public:
            void     sha1(void*,unsigned int, unsigned char*);
private:
            void     update(SHA_CTX*,unsigned char*, unsigned int);
            void     init(SHA_CTX*);
            void     finish(SHA_CTX*);
            void     ejecute(SHA_CTX*, unsigned char*);
            void     encode(unsigned char*, UI32*, unsigned int);
            UI32     iterator(unsigned,unsigned,unsigned,unsigned int);
};

/*
*           'update' - Actualiza el bloque de texto.
*           Alinea [buffer] a 512 bits, ejecuta el algoritmo SHA-1
*           y lo asigna [context->buffer_block].
*/
void Csha::update(SHA_CTX* context, unsigned char* buffer, unsigned int lenbuffer)
{
            unsigned int i,index,partLen;
            index = (unsigned int)((context->count[0] >> 3)&0x3F);
            if ((context->count[0] += ((UI32)lenbuffer << 3))< ((UI32)lenbuffer << 3))
            {
                        context->count[1]++;
            }
            context->count[1] += ((UI32)lenbuffer >> 29);
            partLen = 64 - index;
            if (lenbuffer >= partLen)
            {
                        memcpy((POINTER)&context->buffer_block[index], (POINTER)buffer, partLen);
                        ejecute(context,context->buffer_block);
                        for (i = partLen; i + 63 < lenbuffer; i += 64)
                        {
                                   ejecute(context,&buffer[i] );
                        }
                        index = 0;
            }else
            {
                        i = 0;
            }
            memcpy ((POINTER)&context->buffer_block[index], (POINTER)&buffer[i], lenbuffer-i);//buffer de 0 a 7 con input
}

/*
*           'finish' - Finaliza [context->buffer_block].
*/
void Csha::finish(SHA_CTX* context)
{
            unsigned char bits[8];
            unsigned int index, padLen;

            encode (bits, context->count, 8);
            index = (unsigned int)((context->count[0] >> 3) & 0x3f);
            padLen = (index < 56) ? (56 - index) : (120 - index);
            update(context,register_block, padLen);
            update(context, bits, 8);
}

/*
*           'encode' - Asigna [len] bytes en 4 bytes.
*           Se utiliza la notación BIG ENDIAN para
*           el algoritmo SHA-1.
*/
void Csha::encode(unsigned char *output, UI32 *input, unsigned int len)
{          
            unsigned int i, j;
            for (i = 1, j = 0; j < len; i--, j += 4) {
                        output[j+3]       = (unsigned char)(((input[i])) & 0xff);
                        output[j+2] = (unsigned char)(((input[i]) >>  8) & 0xff);                       
                        output[j+1] = (unsigned char)(((input[i]) >> 16) & 0xff);          
                        output[j]           = (unsigned char)(((input[i]) >> 24) & 0xff);     
            }                                                                                                                                                                                          
}          
                                                                                                                                                                               
/*
*           'iterator' - Itera las llamadas a funciones
*           según parámetro [t].
*/
UI32 Csha::iterator(unsigned x,unsigned y,unsigned z,unsigned int t)
{
            if((t>=0) && (t<=19))
            {
                        return((UI32)F(x,y,z));
            }else if( (t>= 20) && (t<=39) || (t>=60) && (t <=79))
            {          
                        return((UI32)G(x,y,z));
            }else if( (t>=40) && (t<=59))
            {
                        return((UI32)H(x,y,z));
            }
            return 0L;
}

/*
*           'init' - Inicia el contexto.
*/
void Csha::init(SHA_CTX* context)
{
            for(int i = 0;i<=4;i++)
            {
                        context->abcde[i] = register_state[i];
            }
            context->count[0] = context->count[1] = (UI32)0x0;
}

/*
*           'ejecute' - Ejecuta el bloque de texto alineado.
*           En ésta función se resaltan 3 bloques: A,B,C.
*           A y B son preparativos; C es el proceso principal.
*/
void Csha::ejecute(SHA_CTX* context, unsigned char* input)
{
            unsigned k = 0,j = 0,i = 0,t = 0;
            UI32 a,b,c,d,e;
            UI32 temp = 0;
            UI32 block16[16];
            UI32 block80[80];

            //se asignan los contenidos anteriores.
            a = context->abcde[0];
            b = context->abcde[1];
            c = context->abcde[2];
            d = context->abcde[3];
            e = context->abcde[4];

            //          BLOQUE A:
            //para el algoritmo SHA-1 se debe utilizar la notación BIG ENDIAN.
            //procesa  un bloque de 64 y lo convierte en un bloque de 16.
            for (k = 0, j = 0; j  < 63; k++, j += 4)
            {
                        block16[k] = (((UI32)input[j])<<24) | (((UI32)input[j+1]) << 16) | (((UI32)input[j+2]) << 8) | ((UI32)input[j+3]);
            }

            //BLOQUE B:
            //procesa un bloque de 16 y lo convierte en un bloque de 80.
            //los primeros 16 se copian tal cual.
            //desde 17 a 80 los copia con desplazamiento de bits a la izquierda con retroalimentación.
            for(i= 0; i<= 79;i++)
            {
                        if( (i>=0) && (i<=15))
                        {
                                   block80[i] = block16[i];
                        }else if( (i>=16) && (i<=79))
                        {
                                   block80[i] = ROTATE_LEFT(((block80[i-3]) ^ (block80[i-8]) ^ (block80[i-14]) ^ (block80[i-16])),(1));
                        }
            }
            //por seguridad se limpia el contenido.
            memset((POINTER)block16,0,sizeof(block16));

            //BLOQUE C:
            //proceso principal del algoritmo SHA-1.
            for(t; t<=79;t++)
            {
                        i = t / 20;
                        temp = ROTATE_LEFT((a),(5)) + iterator(b,c,d,t) + e + block80[t] + register_key[i];
                        e = d;
                        d = c;
                        c = ROTATE_LEFT((b),(30));
                        b = a;
                        a = temp;
            }
            //se asignan sumados los registros obtenidos del bloque C.
            context->abcde[0] += a;
            context->abcde[1] += b;
            context->abcde[2] += c;
            context->abcde[3] += d;
            context->abcde[4] += e;

            //por seguridad se limpia el contenido.
            memset(&block80,0,80);
}

/*
*           'sha1' - Ejecuta el algoritmo SHA-1.
*/
void Csha::sha1(void *buffer,unsigned int length,unsigned char* out)
{
            SHA_CTX ctx;
            init(&ctx);
            update(&ctx,(unsigned char*)buffer,length);
            finish(&ctx);
            memcpy((POINTER)out,&ctx.abcde[0],sizeof(ctx.abcde));
            memset ((POINTER)&ctx, 0, sizeof (ctx));
}
#endif // _SHA1_H_
/*
*           End for "$id: sha1.h,v 1.6 01/01/2007 $"

*/