Dies ist ein kleines Beispiel-Programm für eine einfache Hashfunktion, die sich prinzipiell an den SHA-Algorithmus anlehnt. Es wurde nicht auf die absolute Sicherheit, die eine Hashfunktion bieten sollte geachtet, sondern auf möglichst einfache, verständliche Implementierung.
/* Datei: Hash.c
* Programmierer: Jochen Baur, Florian Bühr, Christoph Gärtner
* Datum: Irgendwann im Dezember 97
* gedacht für ANSI-C-Compiler */
#include<stdio.h>
#include<string.h>
/* Initialisierung der Struktur von fünf 32-bit-Variablen */
typedef struct abcde {unsigned long a,b,c,d,e;} hilfevar;
/* Definition der vier SHA-Konstanten */
#define K1 0x5a827999L
#define K2 0x6ed9eba1L
#define K3 0x8f1bbcdcL
#define K4 0xca62c1d6L
/* Eine Operation von SHA, die pro Runde 20mal ausgeführt werden
soll */
void operation (hilfevar *in,unsigned char fktnr,unsigned long w )
{ unsigned long temp;
/* Auswahl einer der vier nichtlinearen Funktionen abhängig von
der Runde*/
switch(fktnr)
{
case 0: {
temp = in->e+((in->b & in->c)|(~in->b & in->d))+((in->a<<5)|(in->a<<27))+w+K1;
break;}
case 1: {
temp = in->e+(in->b^in->c^in->d)+((in->a<<5)|(in->a<<27))+w+K2;
break;}
case 2: {
temp = in->e+((in->b & in->c)|(in->b & in->d)|(in->c & in->d))+((in->a<<5)|(in->a<<27))+w+K3;
break;}
case 3: {
temp = in->e+(in->b^in->c^in->d)+((in->a<<5)|(in->a<<27))+w+K4;
break;}
}
/* Kopieren der durch die Funktionen veränderten Variablen
in->e = in->d;
in->d = in->c;
in->c = ((in->b<<30)|(in->b<<2));
in->b = in->a;
in->a = temp;
}
/* Eine Runde von SHA, die viermal ausgeführt werden soll */
void runde (hilfevar *G,unsigned long *wert)
{ unsigned char opcounter;
hilfevar h; /* Initialisierung der Hilfsvariablen */
h.a = G->a; /* mit den Werten der Verkettungsvariablen */
h.b = G->b;
h.c = G->c;
h.d = G->d;
h.e = G->e;
/* Schleife, die 20mal eine SHA-Operation aufruft */
for(opcounter = 0;opcounter<20;opcounter++)
{ operation(& h,opcounter%4,wert[opcounter]); }
G->a+ = h.a; /* Die in der Runde veränderten Hilfsvariablen */
G->b+ = h.b; /* werden zu den Verkettungsvariablen addiert */
G->c+ = h.c;
G->d+ = h.d;
G->e+ = h.e;
}
/* Hauptprogramm, das File zum hashen einliest und Runden viermal
aufruft */
void main (int arg,unsigned char *filename[])
{
FILE *in;
hilfevar H,erg;
unsigned char ch[4];
unsigned char i,j,k,n,p;
long test;
unsigned long W[20];
/* Initialisierung der Verkettungsvariablen mit den Anfangswerten */
erg.a = H.a = 0x67452301L;
erg.b = H.b = 0xefcdab89L;
erg.c = H.c = 0x98badcfeL;
erg.d = H.d = 0x10325476L;
erg.e = H.e = 0xc3d2e1f0L;
printf("\n\nHashfunktion Copyright by Baur, Buehr, Gaertner,
Herbert A.D.1997\n\n");
/* Fehlerbehandlung, falls angegebene Datei nicht vorhanden */
if ((in = fopen(filename[1], "r")) == NULL)
{
fprintf(stderr, "Konnte Datei nicht oeffnen.\n");
}
/* Setze Datei-Zeiger auf Dateiende und lese Dateilänge ein */
fseek(in,0,SEEK_END);
test = ftell(in);
/* Setze Datei-Zeiger auf Anfang */
fseek(in,0x0,SEEK_SET);
/* Schleife zum Einlesen der 32-bit-Teilblöcke (Message
Digests) */
for(j = 0;j<(long)(test/64);j++)
{ /* Schreibe in jedes Byte, das Datei länger ist als Vielfaches
von 512 bit eine '0' ...
wichtigster Unterschied zum Secure Hash Standard/Algorithm */
for (i = 0;i<16;i++)
{
W[i] = 0;
for (n = 0; n < 4; n++)
{
ch[n] = fgetc(in);
/* Lese Byte und schreibe in W-Feld */
if(feof(in)) W[i] = 0; else
W[i] = (W[i] << 8) | ch[n];
/* wenn Ende der Datei, schreibe '0', andernfalls
rotiere um nächstes Byte anzuhängen */
}
/* Kopiere die letzten vier Teilblöcke in die ersten vier
W[16] = W[1]; W[17] = W[2];
W[18] = W[3]; W[19] = W[4];
}
/* Aufruf der SHA-Runden und Schreiben der Ausgabe der Runde in
endgültigen Verkettungsvariablen */
runde(& H,W);
erg.a = H.a+ = erg.a;
erg.b = H.b+ = erg.b;
erg.c = H.c+ = erg.c;
erg.d = H.d+ = erg.d;
erg.e = H.e+ = erg.e;
runde(& H,W);
erg.a = H.a+ = erg.a;
erg.b = H.b+ = erg.b;
erg.c = H.c+ = erg.c;
erg.d = H.d+ = erg.d;
erg.e = H.e+ = erg.e;
runde(& H,W);
erg.a = H.a+ = erg.a;
erg.b = H.b+ = erg.b;
erg.c = H.c+ = erg.c;
erg.d = H.d+ = erg.d;
erg.e = H.e+ = erg.e;
runde(& H,W);
erg.a = H.a+ = erg.a;
erg.b = H.b+ = erg.b;
erg.c = H.c+ = erg.c;
erg.d = H.d+ = erg.d;
erg.e = H.e+ = erg.e;
if(feof(in)) break; /* Schleifenabbruch, falls Dateiende */
}
/* Ausgabe auf 'stdout' des Hashwerts von 160 bit durch Aneinderreihen
der Verkettungsvariablen */
printf("Hashwert auf
stdout:\t%lx%lx%lx%lx%lx\n",erg.a,erg.b,erg.c,erg.d,erg.e);
fclose(in); /* Schließe Datei, die gehasht wurde */
}
Programmaufruf und Ausgabe:
C:\>hash <dateiname> (unter DOS-Prompt)
Hashfunktion copyright by Baur, Buehr, Gaertner, Herbert A.D. 1997
Hashwert auf stdout: 40-stellige hexadezimale Zahl
Beispiel mit einer Datei test01.txt, die
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" enthält:
C:\>hash test01.txt
Hashfunktion ...
Hashwert auf stdout: 67452301efcdab8998badcfb10325476c3d2e1f0
Beispiel mit einer Datei test02.txt, die
"ABBDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789101112" enthält (die fettgedruckten Zeichen sind zu test01.txt verändert):
C:\>hash test02.txt
Hashfunktion ...
Hashwert auf stdout: b680d8edca71ccb01d7eef0cb62eff2c8a729110