Add implementation of MD5 hash function.

This commit is contained in:
Stephen Heumann 2017-07-04 12:15:00 -05:00
parent 015ae8559f
commit 0f144df99b
7 changed files with 788 additions and 1 deletions

View File

@ -1,6 +1,7 @@
CFLAGS = -O255 -w255
PROGRAMS = aescbctest aesctrtest aestest aescrypt sha1sum sha1test sha256sum sha256test
PROGRAMS = aescbctest aesctrtest aestest aescrypt sha1sum sha1test \
sha256sum sha256test md5sum md5test
.PHONY: default
default: $(PROGRAMS)
@ -29,6 +30,12 @@ sha256sum: sha256sum.c sha256.cc sha256.asm sha256.macros sha256.h
sha256test: sha256test.c sha256.cc sha256.asm sha256.macros sha256.h
occ $(CFLAGS) sha256test.c sha256.cc -o sha256test
md5sum: md5sum.c md5.cc md5.asm md5.macros md5.h
occ $(CFLAGS) md5sum.c md5.cc -o md5sum
md5test: md5test.c md5.cc md5.asm md5.macros md5.h
occ $(CFLAGS) md5test.c md5.cc -o md5test
.PHONY: clean
clean:
rm -f *.a *.A *.b *.B *.root *.ROOT *.o $(PROGRAMS)

169
md5.asm Normal file
View File

@ -0,0 +1,169 @@
* Copyright (c) 2017 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* Implementation of the MD5 hash function for the 65816
case on
mcopy md5.macros
* Direct page locations
length gequ 0
extra gequ 8
idx gequ 10
a_ gequ 12 ; elements of state
b gequ 16
c gequ 20
d gequ 24
;unused gequ 28
f_plus_a gequ 32
temp gequ 36
h0 gequ 40
h1 gequ 44
h2 gequ 48
h3 gequ 52
;unused gequ 56
m gequ 60
* Precomputed values of g*4 for each loop iteration, for indexing the message
g_times_4 private
dc i4' 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60'
dc i4' 4, 24, 44, 0, 20, 40, 60, 16, 36, 56, 12, 32, 52, 8, 28, 48'
dc i4'20, 32, 44, 56, 4, 16, 28, 40, 52, 0, 12, 24, 36, 48, 60, 8'
dc i4' 0, 28, 56, 20, 48, 12, 40, 4, 32, 60, 24, 52, 16, 44, 8, 36'
end
k private
dc i4'$d76aa478, $e8c7b756, $242070db, $c1bdceee'
dc i4'$f57c0faf, $4787c62a, $a8304613, $fd469501'
dc i4'$698098d8, $8b44f7af, $ffff5bb1, $895cd7be'
dc i4'$6b901122, $fd987193, $a679438e, $49b40821'
dc i4'$f61e2562, $c040b340, $265e5a51, $e9b6c7aa'
dc i4'$d62f105d, $02441453, $d8a1e681, $e7d3fbc8'
dc i4'$21e1cde6, $c33707d6, $f4d50d87, $455a14ed'
dc i4'$a9e3e905, $fcefa3f8, $676f02d9, $8d2a4c8a'
dc i4'$fffa3942, $8771f681, $6d9d6122, $fde5380c'
dc i4'$a4beea44, $4bdecfa9, $f6bb4b60, $bebfbc70'
dc i4'$289b7ec6, $eaa127fa, $d4ef3085, $04881d05'
dc i4'$d9d4d039, $e6db99e5, $1fa27cf8, $c4ac5665'
dc i4'$f4292244, $432aff97, $ab9423a7, $fc93a039'
dc i4'$655b59c3, $8f0ccc92, $ffeff47d, $85845dd1'
dc i4'$6fa87e4f, $fe2ce6e0, $a3014314, $4e0811a1'
dc i4'$f7537e82, $bd3af235, $2ad7d2bb, $eb86d391'
end
* Initialize a MD5 context.
* This must be called before any of the other MD5 functions.
md5_init start
CFunction MD5_INIT
end
MD5_INIT start
lda #$2301
sta h0
lda #$6745
sta h0+2
lda #$AB89
sta h1
lda #$EFCD
sta h1+2
lda #$DCFE
sta h2
lda #$98BA
sta h2+2
lda #$5476
sta h3
lda #$1032
sta h3+2
stz length
stz length+2
stz length+4
stz length+6
stz extra
rtl
end
* Process one 64-byte block through the MD5 hashing function.
* This is a low-level function; users should normally not call this directly.
md5_processblock start
CFunction MD5_PROCESSBLOCK
end
MD5_PROCESSBLOCK start
lda h0
sta a_
lda h0+2
sta a_+2
lda h1
sta b
lda h1+2
sta b+2
lda h2
sta c
lda h2+2
sta c+2
lda h3
sta d
lda h3+2
sta d+2
stz idx
BlockLoopPart 1
BlockLoopPart 2
BlockLoopPart 3
BlockLoopPart 4
endloop clc
lda h0
adc a_
sta h0
lda h0+2
adc a_+2
sta h0+2
clc
lda h1
adc b
sta h1
lda h1+2
adc b+2
sta h1+2
clc
lda h2
adc c
sta h2
lda h2+2
adc c+2
sta h2+2
clc
lda h3
adc d
sta h3
lda h3+2
adc d+2
sta h3+2
rtl
end

138
md5.cc Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2017 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma noroot
#pragma lint -1
#pragma optimize -1
#include "md5.h"
#include <string.h>
#define length_offset 0
#define extra_offset 8
#define hash_offset 40
#define data_offset 60
extern void MD5_PROCESSBLOCK(void);
/*
* Update a MD5 context based on the specified data.
*/
void md5_update(struct md5_context *context,
const unsigned char *data,
unsigned long length)
{
unsigned int extra = context->extra;
unsigned long oldlength = context->length;
if ((context->length += length) < oldlength)
context->length2++;
if (extra > 0) {
if (length >= 64 - extra) {
memcpy(&context->block[extra], data, 64 - extra);
asm {
phd
lda context
tcd
jsl MD5_PROCESSBLOCK
pld
}
length -= 64 - extra;
data += 64 - extra;
} else {
memcpy(&context->block[extra], data, length);
context->extra += length;
return;
}
}
while (length >= 64) {
memcpy(&context->block, data, 64);
asm {
phd
lda context
tcd
jsl MD5_PROCESSBLOCK
pld
}
length -= 64;
data += 64;
}
memcpy(&context->block, data, length);
context->extra = length;
}
/*
* Finish MD5 processing and generate the final hash code.
*/
void md5_finalize(struct md5_context *context)
{
unsigned int extra = context->extra;
context->block[extra++] = 0x80;
memset(&context->block[extra], 0, 64 - extra);
if (extra > 64 - 8) {
asm {
phd
lda context
tcd
jsl MD5_PROCESSBLOCK
pld
}
memset(&context->block, 0, 64 - 8);
}
asm {
phd
lda context
tcd
/* Append total length in bits */
asl length_offset
rol length_offset+2
rol length_offset+4
rol length_offset+6
asl length_offset
rol length_offset+2
rol length_offset+4
rol length_offset+6
asl length_offset
rol length_offset+2
rol length_offset+4
rol length_offset+6
lda length_offset
sta data_offset+56
lda length_offset+2
sta data_offset+58
lda length_offset+4
sta data_offset+60
lda length_offset+6
sta data_offset+62
/* Process final block */
jsl MD5_PROCESSBLOCK
pld
}
}
#append "md5.asm"

51
md5.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2017 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct md5_context {
unsigned long length;
unsigned long length2;
unsigned short extra;
unsigned char reserved1[30];
unsigned char hash[16];
unsigned char reserved2[4];
unsigned char block[64];
};
/*
* The context structure must be in bank 0, preferably page-aligned.
*/
/*
* Initialize a MD5 context.
* This must be called before any of the other MD5 functions.
*/
void md5_init(struct md5_context *context);
/*
* Update a MD5 context based on the specified data.
*/
void md5_update(struct md5_context *context, const unsigned char *data, unsigned long length);
/*
* Finish MD5 processing and generate the final hash code.
*/
void md5_finalize(struct md5_context *context);
/*
* Process one 64-byte block through the MD5 hashing function.
* This is a low-level function; users should normally not call this directly.
*/
void md5_processblock(struct md5_context *context);

273
md5.macros Normal file
View File

@ -0,0 +1,273 @@
* Copyright (c) 2017 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* Right-rotate 32-bit value in &loc (DP or 16-bit address) by &n positions
macro
ROTR4 &loc,&n
aif &n>16,.dorotl
lda &loc+2
lcla &i
&i seta &n
.rotrloop
lsr a ;to set carry
ror &loc
ror &loc+2
&i seta &i-1
aif &i>0,.rotrloop
ago .end
.dorotl
ROTL4 &loc,32-&n
.end
mend
* Left-rotate 32-bit value in &loc (DP or 16-bit address) by &n positions
macro
ROTL4 &loc,&n
aif &n>16,.dorotr2
lda &loc
lcla &i
&i seta &n
.rotlloop2
asl a ;to set carry
rol &loc+2
rol &loc
&i seta &i-1
aif &i>0,.rotlloop2
ago .end2
.dorotr2
ROTR4 &loc,32-&n
.end2
mend
* &to := &from ROTR4 &n
macro
ROTR4MOVE &to,&from,&n
aif &n>16,.dorotl3
lda &from
sta &to
lda &from+2
sta &to+2
lcla &i
&i seta &n
.rotrloop3
lsr a ;to set carry
ror &to
ror &to+2
&i seta &i-1
aif &i>0,.rotrloop3
ago .end3
.dorotl3
ROTL4MOVE &to,&from,32-&n
.end3
mend
* &to := &from ROTL4 &n
macro
ROTL4MOVE &to,&from,&n
aif &n>16,.dorotr4
lda &from+2
sta &to+2
lda &from
sta &to
lcla &i
&i seta &n
.rotlloop4
asl a ;to set carry
rol &to+2
rol &to
&i seta &i-1
aif &i>0,.rotlloop4
ago .end4
.dorotr4
ROTR4MOVE &to,&from,32-&n
.end4
mend
* This makes a function wrapper that is callable from C,
* taking a pointer to the context structure as its argument.
macro
CFunction &fn
phb
plx
ply
tdc
pld
plb
plb
phy
phx
plb
pha
jsl &fn
pld
rtl
mend
* One iteration of the loop for processing blocks.
* The a,b,c,d variables are given as parameters so we can avoid cycling them.
* shift is a per-round shift amount.
macro
BlockLoopIter &a,&b,&c,&d,&shift
* f_0 to f_15
aif &part<>1,.skip1
lda &c
eor &d
and &b
eor &d
clc
adc &a
sta f_plus_a
lda &c+2
eor &d+2
and &b+2
eor &d+2
adc &a+2
sta f_plus_a+2
.skip1
* f_16 to f_31
aif &part<>2,.skip2
lda &b
eor &c
and &d
eor &c
clc
adc &a
sta f_plus_a
lda &b+2
eor &c+2
and &d+2
eor &c+2
adc &a+2
sta f_plus_a+2
.skip2
* f_32 to f_47
aif &part<>3,.skip3
lda &b
eor &c
eor &d
clc
adc &a
sta f_plus_a
lda &b+2
eor &c+2
eor &d+2
adc &a+2
sta f_plus_a+2
.skip3
* f_48 to f_63
aif &part<>4,.skip4
lda &d
eor #$FFFF
ora &b
eor &c
clc
adc &a
sta f_plus_a
lda &d+2
eor #$FFFF
ora &b+2
eor &c+2
adc &a+2
sta f_plus_a+2
.skip4
ldy idx
ldx g_times_4,y
lda m,x
clc
adc f_plus_a
sta temp
inx
inx
lda m,x
adc f_plus_a+2
sta temp+2
lda k,y
clc
adc temp
sta temp
iny
iny
lda k,y
adc temp+2
sta temp+2
ROTL4 temp,&shift
clc
lda &b
adc temp
sta &a
lda &b+2
adc temp+2
sta &a+2
inc idx
inc idx
inc idx
inc idx
mend
* One part of the loop for processing blocks (20 iterations)
macro
BlockLoopPart &part
loop&part anop
aif &part<>1,.skip1a
BlockLoopIter a_,b,c,d,7
BlockLoopIter d,a_,b,c,12
BlockLoopIter c,d,a_,b,17
BlockLoopIter b,c,d,a_,22
.skip1a
aif &part<>2,.skip2a
BlockLoopIter a_,b,c,d,5
BlockLoopIter d,a_,b,c,9
BlockLoopIter c,d,a_,b,14
BlockLoopIter b,c,d,a_,20
.skip2a
aif &part<>3,.skip3a
BlockLoopIter a_,b,c,d,4
BlockLoopIter d,a_,b,c,11
BlockLoopIter c,d,a_,b,16
BlockLoopIter b,c,d,a_,23
.skip3a
aif &part<>4,.skip4a
BlockLoopIter a_,b,c,d,6
BlockLoopIter d,a_,b,c,10
BlockLoopIter c,d,a_,b,15
BlockLoopIter b,c,d,a_,21
.skip4a
lda idx
cmp #16*4*&part
bge endloop&part
jmp loop&part
endloop&part anop
mend

55
md5sum.c Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2017 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "md5.h"
unsigned char buf[0x8000];
int main(int argc, char **argv) {
struct md5_context ctx;
FILE *file;
size_t count;
int i;
srand(time(NULL));
if (argc != 2)
return EXIT_FAILURE;
file = fopen(argv[1], "rb");
if (file == NULL)
return EXIT_FAILURE;
md5_init(&ctx);
do {
count = (rand() & 0x7FFF) + 1;
count = fread(buf, 1, count, file);
md5_update(&ctx, buf, count);
} while (count != 0);
fclose(file);
md5_finalize(&ctx);
for (i = 0; i < 16; i++) {
printf("%02x", ctx.hash[i]);
}
printf("\n");
return 0;
}

94
md5test.c Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2017 Stephen Heumann
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "md5.h"
#include <stdio.h>
#include <MiscTool.h>
#include <Memory.h>
#include <orca.h>
#include <string.h>
int main(int argc, char **argv) {
unsigned int i;
unsigned long tick_count;
long double bytes_per_sec;
struct md5_context *context, **context_hndl;
struct md5_context context_init = {0,0,0, {0}, {0}, {0},
{0x61,0x62,0x63,0x80,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
}};
context_hndl = (struct md5_context **)NewHandle(sizeof(struct md5_context),
userid(), attrFixed|attrPage|attrBank|attrNoCross, 0x000000);
if (toolerror())
return 0;
context = *context_hndl;
*context = context_init;
md5_init(context);
md5_processblock(context);
printf("h[..] = %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
context->hash[0], context->hash[1], context->hash[2], context->hash[3],
context->hash[4], context->hash[5], context->hash[6], context->hash[7],
context->hash[8], context->hash[9], context->hash[10], context->hash[11],
context->hash[12], context->hash[13], context->hash[14], context->hash[15]);
tick_count = GetTick();
for (i = 0; i < 1000; i++) {
md5_processblock(context);
}
tick_count = GetTick() - tick_count;
bytes_per_sec = (long double)1000 * 64 * 60 / tick_count;
printf("Time for 1000 iters = %lu ticks (%lf bytes/sec)\n", tick_count, bytes_per_sec);
tick_count = GetTick();
md5_init(context);
md5_update(context, (void*)0x030000, 64000);
md5_finalize(context);
tick_count = GetTick() - tick_count;
bytes_per_sec = (long double)1000 * 64 * 60 / tick_count;
printf("Append time = %lu ticks (%lf bytes/sec)\n", tick_count, bytes_per_sec);
if (argc > 1) {
md5_init(context);
md5_update(context, argv[1], strlen(argv[1]));
md5_finalize(context);
printf("h[..] = %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
context->hash[0], context->hash[1], context->hash[2], context->hash[3],
context->hash[4], context->hash[5], context->hash[6], context->hash[7],
context->hash[8], context->hash[9], context->hash[10], context->hash[11],
context->hash[12], context->hash[13], context->hash[14], context->hash[15]);
}
}