Міністерство освіти і науки України
Національний університет „Львівська політехніка”
Кафедра електронних
обчислювальних машин
Звіт
про виконання лабораторної роботи № 4
з курсу „ Захист інформації в комп’ютерних системах ”
Хеш функції.Алгоритм хешування MD5.
Львів – 2005
Мета роботи: ознайомитися із хеш функціями та їх застосуванням, закріпити навики створення хеш функції на прикладі алгоритму хешування MD5.
Завдання: За допомогою алгоритму хешування MD5 отримати хеш вхідної стрічки.
Текст програми:
main.c
#define VERSION "2.0 (2003-04-15)"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
#include "md5.h"
#define FALSE 0
#define TRUE 1
#define EOS '\0'
int main(argc, argv)
int argc; char *argv[];
{
int i, j, opt, cdata = FALSE, docheck = FALSE, showfile = TRUE, f = 0;
unsigned int bp;
char *cp, *clabel, *ifname, *hexfmt = "%02X";
FILE *in = stdin, *out = stdout;
unsigned char buffer[16384], signature[16], csig[16];
struct MD5Context md5c;
for (i = 1; i < argc; i++) {
cp = argv[i];
if (*cp == '-') {
if (strlen(cp) == 1) { i++; break; }
opt = *(++cp);
if (islower(opt)) { opt = toupper(opt); }
switch (opt) {
case 'C': /* -Csignature -- Check signature, set return code */
docheck = TRUE;
if (strlen(cp + 1) != 32) { docheck = FALSE; }
memset(csig, 0, 16);
clabel = cp + 1;
for (j = 0; j < 16; j++) {
if (isxdigit((int) clabel[0]) && isxdigit((int) clabel[1]) &&
sscanf((cp + 1 + (j * 2)), hexfmt, &bp) == 1) {
csig[j] = (unsigned char) bp;
} else { docheck = FALSE; break; }
clabel += 2;
}
if (!docheck) {
fprintf(stderr, "Error in signature specification. Must be 32 hex digits.\n");
return 2;
}
break;
case 'D': /* -Dtext -- Compute signature of given text */
MD5Init(&md5c); MD5Update(&md5c, (unsigned char *) (cp + 1), strlen(cp + 1));
cdata = TRUE; f++; break; /* Mark no infile argument needed */
case 'L': /* -L -- Use lower case letters as hex digits */
hexfmt = "%02x"; break;
case 'N': /* -N -- Don't show file name after sum */
showfile = FALSE; break;
case 'O': /* -Ofname -- Write output to fname (- = stdout) */
cp++;
if (strcmp(cp, "-") != 0) {
if (out != stdout) {
fprintf(stderr, "Redundant output file specification.\n");
return 2;
}
if ((out = fopen(cp, "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s\n", cp); return 2;
}
}
break;
case '?': /* -U, -? -H -- Print how to call information. */
case 'H':
case 'U':
printf("\nMD5 -- Calculate MD5 signature of file. Call");
printf("\n with md5 [ options ] [file ...]\n");
printf("\n Options:");
printf("\n -csig Check against sig, set exit status 0 = OK");
printf("\n -dtext Compute signature of text argument");
printf("\n -l Use lower case letters for hexadecimal digits");
printf("\n -n Do not show file name after sum");
printf("\n -ofname Write output to fname (- = stdout)");
printf("\n -u Print this message");
printf("\n -v Print version information\n");
printf("\nby John Walker -- http://www.fourmilab.ch/");
printf("\nVersion %s\n", VERSION);
printf("\nThis program is in the public domain.\n\n");
return 0;
case 'V': /* -V -- Print version number */
printf("%s\n", VERSION);
return 0;
}
} else { break; }
}
if (cdata && (i < argc)) {
fprintf(stderr, "Cannot specify both -d option and input file.\n");
return 2;
}
if ((i >= argc) && (f == 0)) { f++; }
for (; (f > 0) || (i < argc); i++) {
if ((!cdata) && (f > 0)) {
ifname = "-";
} else { ifname = argv[i]; }
f = 0;
if (!cdata) {
/* If the data weren't supplied on the command line with
the "-d" option, read it now from the input file. */
if (strcmp(ifname, "-") != 0) {
if ((in = fopen(ifname, "rb")) == NULL) {
fprintf(stderr, "Cannot open input file %s\n", ifname); return 2;
}
} else { in = stdin; }
#ifdef _WIN32
_setmode(_fileno(in), _O_BINARY);
#endif
MD5Init(&md5c);
while ((j = (int) fread(buffer, 1, sizeof buffer, in)) > 0) {
MD5Update(&md5c, buffer, (unsigned) j);
}
}
MD5Final(signature, &md5c);
if (docheck) {
docheck = 0;
for (j = 0; j < sizeof signature; j++) {
if (signature[j] != csig[j]) {
docheck = 1; break;
}
}
if (i < (argc - 1)) {
fprintf(stderr, "Only one file may be tested with the -c option.\n"); return 2;
}
} else {
for (j = 0; j < sizeof signature; j++) {
fprintf(out, hexfmt, signature[j]);
}
if ((!cdata) && showfile) { fprintf(out, " %s", (in == stdin) ? "-" : ifname); }
fprintf(out, "\n");
}
}
return docheck;
}
md5.h
#ifndef MD5_H
#define MD5_H
#ifdef __alpha
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif
struct MD5Context {
uint32 buf[4];
uint32 bits[2];
unsigned char in[64];
};
extern void MD5Init();
extern void MD5Update();
extern void MD5Final();
extern void MD5Transform();
typedef struct MD5Context MD5_CTX;
#endif /* !MD5_H */
md5.c
#include <memory.h>
#include "md5.h"
#ifdef sgi
#define HIGHFIRST
#endif
#ifdef sun
#define HIGHFIRST
#endif
#ifndef HIGHFIRST
#define byteReverse(buf, len) /* Nothing */
#else
void byteReverse(buf, longs)
unsigned char *buf; unsigned longs;
{
uint32 t;
do {
t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]);
*(uint32 *) buf = t; buf += 4;
} while (--longs);
}
#endif
void MD5Init(ctx)
struct MD5Context *ctx; {
ctx->buf[0]=0x67452301; ctx->buf[1]=0xefcdab89; ctx->buf[2]=0x98badcfe; ctx->buf[3]=0x10325476;
ctx->bits[0] = 0; ctx->bits[1] = 0;
}
void MD5Update(ctx, buf, len)
struct MD5Context *ctx; unsigned char *buf; unsigned len;
{
uint32 t;
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) { memcpy(p, buf, len); return; }
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += t; len -= t;
}
while (len >= 64) { /* Process data in 64-byte chunks */
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
buf += 64; len -= 64;
}
memcpy(ctx->in, buf, len); /* Handle any remaining bytes of data. */
}
void MD5Final(digest, ctx)
unsigned char digest[16]; struct MD5Context *ctx;
{
unsigned count; unsigned char *p;
count = (ctx->bits[0] >> 3) & 0x3F; /* Compute number of bytes mod 64 */
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
count = 64 - 1 - count; /* Bytes of padding needed to make 64 bytes */
/* Pad out to 56 mod 64 */
if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else { /* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine. */
void MD5Transform(buf, in)
uint32 buf[4]; uint32 in[16];
{
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
Результати виконання програми:
1. Вхідний текст: "Laboratorna robota nomer 4 z kursu Zahyst informatsiyi v kompyuternyh systemah -- Algorytm heshuvann'a MD5"Його 128-бітовий хеш: A3FEBB9522C850A048E17C3D3D0B8A73
2. Вхідний текст: "abc"Його 128-бітовий хеш: 900150983CD24FB0D6963F7D28E17F72
3. Вхідний текст: "message digest"Його 128-бітовий хеш: F96B697D7CB7938D525A2F31AAF161D0
Висновок: виконуючи цю лабораторну роботу, я навчився створювати хеш для будь-якої вхідної послідовності за допомогою алгоритму хешування MD5.