Compare commits

...

10 Commits

Author SHA1 Message Date
Stephen Heumann 58a9c564ae Implement "KDF in Counter Mode" from NIST SP 800-108.
This is currently instantiated with HMAC-SHA256 as the pseudo-random function, but is implemented using a template so that other PRFs could also be used.
2024-04-15 19:48:42 -05:00
Stephen Heumann d3d3dbbad9 Add and use result macros for all HMACs. 2024-04-15 18:39:36 -05:00
Stephen Heumann 0ae8f97c3c Add header declarations and tests for all incremental HMACs. 2024-04-15 18:29:01 -05:00
Stephen Heumann 60e4998d16 Implement AES-CMAC. 2024-04-14 22:17:07 -05:00
Stephen Heumann 191a27af86 Update HMAC-MD5 code to support processing a message in multiple parts.
This is implemented in the common HMAC code and can apply to the other hash algorithms as well, but the header and tests are currently only implemented for HMAC-MD5.
2023-12-10 15:09:57 -06:00
Stephen Heumann 5a986a996f Implement RC4.
This is another old algorithm with known vulnerabilities, but it is still used in some places.
2023-12-01 21:39:40 -06:00
Stephen Heumann aece58138f Update .gitignore file. 2023-11-30 18:35:36 -06:00
Stephen Heumann e32645eaae Correct a comment. 2023-11-30 18:35:23 -06:00
Stephen Heumann 8469c7744c Implement MD4.
This is an old and insecure hash algorithm, but some things of interest still use it.
2023-11-30 18:35:11 -06:00
Stephen Heumann c1e1caa766 Implement HMAC-MD5, HMAC-SHA1, and HMAC-SHA256. 2023-11-29 20:03:37 -06:00
27 changed files with 1918 additions and 28 deletions

11
.gitignore vendored
View File

@ -5,15 +5,8 @@
*.root
*.ROOT
*.o
sha1sum
sha1test
sha256sum
sha256test
md5sum
md5test
aestest
*sum
*test
aescrypt
aescbctest
aesctrtest
lib65816crypto
lib65816hash

View File

@ -1,4 +1,4 @@
Copyright (c) 2017 Stephen Heumann
Copyright (c) 2017,2023,2024 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

View File

@ -3,8 +3,8 @@ CFLAGS = -O255 -w255
LIBRARIES = lib65816crypto lib65816hash
PROGRAMS = aescbctest aesctrtest aestest aescrypt sha1sum sha1test \
sha256sum sha256test md5sum md5test
PROGRAMS = aescbctest aesctrtest aestest aescrypt rc4test cmactest sha1sum \
sha1test sha256sum sha256test md5sum md5test md4sum md4test hmactest
.PHONY: default
default: $(LIBRARIES) $(PROGRAMS)
@ -13,31 +13,41 @@ pagealign.root: pagealign.asm
$(CC) -c $<
mv pagealign.ROOT pagealign.root
# AES encryption/decryption algorithm
# Encryption/decryption algorithms
aescmac.a: aescmac.c aes.h
$(CC) $(CFLAGS) -c $<
aesmodes.a: aesmodes.c aes.h
$(CC) $(CFLAGS) -c $<
aes.a: aes.asm aes.macros
$(CC) $(CFLAGS) -c $<
mv aes.A aes.a
rc4.a: rc4.cc rc4.h rc4.asm
$(CC) $(CFLAGS) -c $<
rc4.B: rc4.a
# Hash algorithms
sha1.a: sha1.cc sha1.h sha1.asm sha1.macros
sha1.a: sha1.cc sha1.h sha1.asm sha1.macros hmacimpl.h
$(CC) $(CFLAGS) -c $<
sha1.B: sha1.a
sha256.a: sha256.cc sha1.h sha256.asm sha1.macros
sha256.a: sha256.cc sha256.h sha256.asm sha256.macros hmacimpl.h kdfimpl.h
$(CC) $(CFLAGS) -c $<
sha256.B: sha256.a
md5.a: md5.cc md5.h md5.asm md5.macros
md5.a: md5.cc md5.h md5.asm md5.macros hmacimpl.h
$(CC) $(CFLAGS) -c $<
md5.B: md5.a
md4.a: md4.cc md4.h md4.asm md4.macros hmacimpl.h
$(CC) $(CFLAGS) -c $<
md4.B: md4.a
# Libraries
lib65816crypto: aesmodes.a aes.a
lib65816crypto: aescmac.a aesmodes.a aes.a rc4.a rc4.B
rm -f $@
iix makelib -P $@ $(patsubst %,+%,$^)
lib65816hash: sha1.a sha1.B sha256.a sha256.B md5.a md5.B
lib65816hash: sha1.a sha1.B sha256.a sha256.B md5.a md5.B md4.a md4.B
rm -f $@
iix makelib -P $@ $(patsubst %,+%,$^)
@ -51,6 +61,12 @@ aestest.a: aestest.c aes.h
aescrypt.a: aescrypt.c aes.h
$(CC) $(CFLAGS) -c $<
rc4test.a: rc4test.c rc4.h
$(CC) $(CFLAGS) -c $<
cmactest.a: cmactest.c aes.h
$(CC) $(CFLAGS) -c $<
sha1sum.a: sha1sum.c sha1.h cksumcommon.h
$(CC) $(CFLAGS) -c $<
sha1test.a: sha1test.c sha1.h
@ -66,6 +82,14 @@ md5sum.a: md5sum.c md5.h cksumcommon.h
md5test.a: md5test.c md5.h
$(CC) $(CFLAGS) -c $<
md4sum.a: md4sum.c md4.h cksumcommon.h
$(CC) $(CFLAGS) -c $<
md4test.a: md4test.c md4.h
$(CC) $(CFLAGS) -c $<
hmactest.a: hmactest.c sha256.h sha1.h md5.h md4.h
$(CC) $(CFLAGS) -c $<
aescbctest: aescbctest.a pagealign.root lib65816crypto
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816crypto -o $@
aesctrtest: aesctrtest.a pagealign.root lib65816crypto
@ -75,6 +99,12 @@ aestest: aestest.a pagealign.root lib65816crypto
aescrypt: aescrypt.a pagealign.root lib65816crypto
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816crypto -o $@
rc4test: rc4test.a lib65816crypto
$(CC) $(CFLAGS) $< -L. -llib65816crypto -o $@
cmactest: cmactest.a lib65816crypto
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816crypto -o $@
sha1sum: sha1sum.a lib65816hash
$(CC) $(CFLAGS) $< -L. -llib65816hash -o $@
sha1test: sha1test.a lib65816hash
@ -90,6 +120,13 @@ md5sum: md5sum.a pagealign.root lib65816hash
md5test: md5test.a pagealign.root lib65816hash
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816hash -o $@
md4sum: md4sum.a pagealign.root lib65816hash
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816hash -o $@
md4test: md4test.a pagealign.root lib65816hash
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816hash -o $@
hmactest: hmactest.a lib65816hash
$(CC) $(CFLAGS) pagealign.root $< -L. -llib65816hash -o $@
.PHONY: clean
clean:

View File

@ -1,7 +1,7 @@
65816 Cryptographic & Hash Libraries
====================================
This package contains libraries implementing cryptographic algorithms for the 65816, suitable for use on the Apple IIgs and potentially also other 65816-based systems. Currently, it includes implementations of AES encryption and decryption (in `lib65816crypto`), and of the MD5, SHA-1, and SHA-256 hash functions (in `lib65816hash`). The core algorithms for each of these are written in carefully optimized assembly code, and they can generally process at least several thousand bytes per second on a 2.8 MHz Apple IIgs.
This package contains libraries implementing cryptographic algorithms for the 65816, suitable for use on the Apple IIgs and potentially also other 65816-based systems. Currently, it includes implementations of AES and RC4 encryption and decryption (in `lib65816crypto`), and of the MD4, MD5, SHA-1, and SHA-256 hash functions (in `lib65816hash`). The core algorithms for each of these are written in carefully optimized assembly code, and they can generally process at least several thousand bytes per second on a 2.8 MHz Apple IIgs.
Using the Libraries
-------------------
@ -11,11 +11,11 @@ If you are calling these algorithms from assembly language, simply follow the us
If you use these libraries in your program, you will need to link them into it. You can either place the libraries in the `Libraries` directory of your ORCA installation, or place them somewhere else and specify them on the command line when linking your program. When using certain algorithms (currently AES and MD5), you may also need to include `pagealign.root` as the first file on the linker command line. This file contains no code, but simply specifies that the default load segment should be page-aligned. This is needed because those algorithms include data tables that are page-aligned to maximize performance.
Note that some of the algorithms implemented in this package (including MD5 and SHA-1) have known security weaknesses. If you are using them in a situation where security is important, you should refer to up-to-date cryptanalytic results and advice to determine whether they are appropriate for your application.
Note that some of the algorithms implemented in this package (including RC4, MD4, MD5, and SHA-1) have known security weaknesses. If you are using any of these algorithms in a situation where security is important, you should refer to up-to-date cryptanalytic results and advice to determine whether they are appropriate for your application.
Building the Libraries
----------------------
If you want to build these libraries yourself, you will need ORCA/M and ORCA/C. To ensure everything builds correctly, I recommend using [ORCA/C 2.2.0 B1 or later][1]. The included `Makefile` is set up to build the libraries and test programs on a modern system using [Golden Gate][2], but they could also be build under the ORCA shell or GNO with a suitable build script.
If you want to build these libraries yourself, you will need ORCA/M and ORCA/C. To ensure everything builds correctly, I recommend using [ORCA/C 2.2.0 or later][1]. The included `Makefile` is set up to build the libraries and test programs on a modern system using [Golden Gate][2], but they could also be build under the ORCA shell or GNO with a suitable build script.
[1]: https://github.com/byteworksinc/ORCA-C/releases
[2]: http://golden-gate.ksherlock.com

23
aes.h
View File

@ -21,6 +21,12 @@ struct aes_context {
unsigned char reserved2[16*13];
};
struct aes_cmac_context {
struct aes_context ctx;
unsigned char k1[16];
unsigned char k2[16];
};
/*
* The context structure must be in bank 0, preferably page-aligned.
* Note that a 256-byte (one page) context structure is sufficient for
@ -90,3 +96,20 @@ void aes_ctr_process(struct aes_context *context,
unsigned char *out,
unsigned long nblocks,
const unsigned char *counter);
/*
* Initialize a context for AES-CMAC computation with a specified key.
* This must be called before any calling aes_cmac_compute.
*/
void aes_cmac_init(struct aes_cmac_context *context,
const unsigned char key[16]);
/*
* Compute the AES-CMAC of a message as a single operation.
* The result will be in context->ctx.data.
* The context can be reused for multiple aes_cmac_compute operations.
*/
void aes_cmac_compute(struct aes_cmac_context *context,
const unsigned char *message,
unsigned long message_length);

176
aescmac.c Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2024 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 <string.h>
#include <stddef.h>
#include "aes.h"
extern void AES_ENCRYPT(void);
static asm void aes_cmac_subkey_compute_step(struct aes_cmac_context *ctx) {
tdc
tay
phb
plx
pla
pld
sta 1,s
phx
plb
sep #0x20
asl 15
rol 14
rol 13
rol 12
rol 11
rol 10
rol 9
rol 8
rol 7
rol 6
rol 5
rol 4
rol 3
rol 2
rol 1
rol 0
bcc done
lda 15
eor #0x87
sta 15
done: rep #0x20
tya
tcd
rtl
}
/*
* Initialize a context for AES-CMAC computation with a specified key.
* This must be called before any calling aes_cmac_compute.
*/
void aes_cmac_init(struct aes_cmac_context *context,
const unsigned char key[16])
{
memcpy(context->ctx.key, key, 16);
aes128_expandkey(&context->ctx);
memset(context->ctx.data, 0, 16);
aes_encrypt(&context->ctx);
aes_cmac_subkey_compute_step(context);
memcpy(context->k1, context->ctx.data, 16);
aes_cmac_subkey_compute_step(context);
memcpy(context->k2, context->ctx.data, 16);
}
/*
* Compute the AES-CMAC of a message as a single operation.
* The result will be in context->ctx.data.
* The context can be reused for multiple aes_cmac_compute operations.
*/
void aes_cmac_compute(struct aes_cmac_context *context,
const unsigned char *message,
unsigned long message_length)
{
unsigned i;
memset(&context->ctx.data, 0, 16);
while (message_length > 16) {
asm {
lda [message]
eor [context]
sta [context]
ldy #2
lda [message],y
eor [context],y
sta [context],y
iny
iny
lda [message],y
eor [context],y
sta [context],y
iny
iny
lda [message],y
eor [context],y
sta [context],y
iny
iny
lda [message],y
eor [context],y
sta [context],y
iny
iny
lda [message],y
eor [context],y
sta [context],y
iny
iny
lda [message],y
eor [context],y
sta [context],y
iny
iny
lda [message],y
eor [context],y
sta [context],y
phd
lda context
tcd
jsl AES_ENCRYPT
pld
}
message_length -= 16;
message += 16;
}
if (message_length == 16) {
for (i = 0; i < 16; i++) {
context->ctx.data[i] ^= message[i] ^ context->k1[i];
}
} else {
for (i = 0; i < 16; i++) {
if (i < message_length) {
context->ctx.data[i] ^= message[i] ^ context->k2[i];
} else if (i == message_length) {
context->ctx.data[i] ^= 0x80 ^ context->k2[i];
} else {
context->ctx.data[i] ^= context->k2[i];
}
}
}
asm {
phd
lda context
tcd
jsl AES_ENCRYPT
pld
}
}

92
cmactest.c Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2024 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 <stdio.h>
#include <string.h>
#include "aes.h"
/* AES-CMAC test vectors from RFC 4493 */
unsigned char K[16] = {
0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,
0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c
};
unsigned char K1[16] = {
0xfb,0xee,0xd6,0x18,0x35,0x71,0x33,0x66,
0x7c,0x85,0xe0,0x8f,0x72,0x36,0xa8,0xde
};
unsigned char K2[16] = {
0xf7,0xdd,0xac,0x30,0x6a,0xe2,0x66,0xcc,
0xf9,0x0b,0xc1,0x1e,0xe4,0x6d,0x51,0x3b
};
unsigned char ex2[16] = {
0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,
0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a
};
unsigned char ex3[40] = {
0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,
0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,
0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11
};
unsigned char ex4[64] = {
0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,
0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,
0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,
0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef,
0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,
0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10
};
void print_hexbytes(char *prefix, unsigned char *data, unsigned int n) {
int i;
printf("%s", prefix);
for (i = 0; i < n; i++) {
printf("%02x ", data[i]);
}
printf("\n");
}
int main(void) {
struct aes_cmac_context *ctx;
aes_cmac_init(ctx, K);
if (memcmp(ctx->k1, K1, 16) != 0)
print_hexbytes("wrong K1: got ", ctx->k1, 16);
if (memcmp(ctx->k2, K2, 16) != 0)
print_hexbytes("wrong K2: got ", ctx->k2, 16);
aes_cmac_compute(ctx, "", 0);
print_hexbytes("Example 1 AES-CMAC: ", ctx->ctx.data, 16);
aes_cmac_compute(ctx, ex2, sizeof(ex2));
print_hexbytes("Example 2 AES-CMAC: ", ctx->ctx.data, 16);
aes_cmac_compute(ctx, ex3, sizeof(ex3));
print_hexbytes("Example 3 AES-CMAC: ", ctx->ctx.data, 16);
aes_cmac_compute(ctx, ex4, sizeof(ex4));
print_hexbytes("Example 4 AES-CMAC: ", ctx->ctx.data, 16);
}

114
hmacimpl.h Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2023 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.
*/
/*
* This file is a template for computing HMACs using the hash functions
* from lib65816hash. It is #included from the files implementing the
* hash functions, with HASH_ALG defined to the name of the hash function.
*/
#define join(a,b) a##b
#define concat(a,b) join(a,b)
#define join3(a,b,c) a##b##c
#define concat3(a,b,c) join3(a,b,c)
#define hash_init concat(HASH_ALG,_init)
#define hash_update concat(HASH_ALG,_update)
#define hash_finalize concat(HASH_ALG,_finalize)
#define hmac_init concat3(hmac_,HASH_ALG,_init)
#define hmac_update concat3(hmac_,HASH_ALG,_update)
#define hmac_finalize concat3(hmac_,HASH_ALG,_finalize)
#define hmac_compute concat3(hmac_,HASH_ALG,_compute)
#define hmac_context concat3(hmac_,HASH_ALG,_context)
#define BLOCK_SIZE sizeof(context->u[0].ctx.block)
#define HASH_SIZE sizeof(context->u[0].ctx.hash)
void hmac_init(struct hmac_context *context,
const unsigned char *key,
unsigned long key_length)
{
unsigned i;
// Compute adjusted key (hashed from original key if necessary)
memset(context->u[0].k, 0, BLOCK_SIZE);
if (key_length <= BLOCK_SIZE) {
memcpy(context->u[0].k, key, key_length);
} else {
hash_init(&context->u[1].ctx);
hash_update(&context->u[1].ctx, key, key_length);
hash_finalize(&context->u[1].ctx);
memcpy(context->u[0].k, context->u[1].ctx.hash, HASH_SIZE);
}
// Set context->u[0].k to K XOR opad, context->u[1].k to K XOR ipad
for (i = 0; i < BLOCK_SIZE; i++) {
context->u[1].k[i] = context->u[0].k[i] ^ 0x36;
context->u[0].k[i] ^= 0x5C;
}
// Save inner hash context following initial block as context->u[2].ctx
hash_init(&context->u[2].ctx);
hash_update(&context->u[2].ctx, context->u[1].k, BLOCK_SIZE);
// Save outer hash context following initial block as context->u[1].ctx
hash_init(&context->u[1].ctx);
hash_update(&context->u[1].ctx, context->u[0].k, BLOCK_SIZE);
// initialize context for use with hmac_update
context->u[0].ctx = context->u[2].ctx;
}
void hmac_update(struct hmac_context *context,
const unsigned char *message_part,
unsigned long part_length)
{
hash_update(&context->u[0].ctx, message_part, part_length);
}
void hmac_finalize(struct hmac_context *context)
{
// finalize inner hash
hash_finalize(&context->u[0].ctx);
memcpy(context->inner_hash, context->u[0].ctx.hash, HASH_SIZE);
// Compute outer hash
context->u[0].ctx = context->u[1].ctx;
hash_update(&context->u[0].ctx, context->inner_hash, HASH_SIZE);
hash_finalize(&context->u[0].ctx);
}
void hmac_compute(struct hmac_context *context,
const unsigned char *message,
unsigned long message_length)
{
// Compute inner hash
context->u[0].ctx = context->u[2].ctx;
hash_update(&context->u[0].ctx, message, message_length);
hash_finalize(&context->u[0].ctx);
memcpy(context->inner_hash, context->u[0].ctx.hash, HASH_SIZE);
// Compute outer hash
context->u[0].ctx = context->u[1].ctx;
hash_update(&context->u[0].ctx, context->inner_hash, HASH_SIZE);
hash_finalize(&context->u[0].ctx);
}

126
hmactest.c Normal file
View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2023 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 <stdio.h>
#include <orca.h>
#include <memory.h>
#include "sha256.h"
#include "sha1.h"
#include "md5.h"
#include "md4.h"
int main(void) {
Handle context_hndl;
struct hmac_sha256_context *hmac_sha256_context;
struct hmac_sha1_context *hmac_sha1_context;
struct hmac_md5_context *hmac_md5_context;
struct hmac_md4_context *hmac_md4_context;
char key[] = "key";
char msg[] = "The quick brown fox jumps over the lazy dog";
context_hndl = NewHandle(sizeof(struct hmac_sha256_context),
userid(), attrFixed|attrPage|attrBank|attrNoCross, 0x000000);
if (toolerror())
return 0;
hmac_sha256_context = (struct hmac_sha256_context *)*context_hndl;
hmac_sha256_init(hmac_sha256_context, key, sizeof(key)-1);
hmac_sha256_compute(hmac_sha256_context, msg, sizeof(msg)-1);
printf("HMAC-SHA256: ");
for (int i = 0; i < sizeof(hmac_sha256_result(hmac_sha256_context)); i++) {
printf("%02x", hmac_sha256_result(hmac_sha256_context)[i]);
}
printf("\n");
hmac_sha1_context = (struct hmac_sha1_context *)*context_hndl;
hmac_sha1_init(hmac_sha1_context, key, sizeof(key)-1);
hmac_sha1_compute(hmac_sha1_context, msg, sizeof(msg)-1);
printf("HMAC-SHA1: ");
for (int i = 0; i < sizeof(hmac_sha1_result(hmac_sha1_context)); i++) {
printf("%02x", hmac_sha1_result(hmac_sha1_context)[i]);
}
printf("\n");
hmac_md5_context = (struct hmac_md5_context *)*context_hndl;
hmac_md5_init(hmac_md5_context, key, sizeof(key)-1);
hmac_md5_compute(hmac_md5_context, msg, sizeof(msg)-1);
printf("HMAC-MD5: ");
for (int i = 0; i < sizeof(hmac_md5_result(hmac_md5_context)); i++) {
printf("%02x", hmac_md5_result(hmac_md5_context)[i]);
}
printf("\n");
hmac_md4_context = (struct hmac_md4_context *)*context_hndl;
hmac_md4_init(hmac_md4_context, key, sizeof(key)-1);
hmac_md4_compute(hmac_md4_context, msg, sizeof(msg)-1);
printf("HMAC-MD4: ");
for (int i = 0; i < sizeof(hmac_md4_result(hmac_md4_context)); i++) {
printf("%02x", hmac_md4_result(hmac_md4_context)[i]);
}
printf("\n");
hmac_sha256_init(hmac_sha256_context, key, sizeof(key)-1);
hmac_sha256_update(hmac_sha256_context, "T", 1);
hmac_sha256_update(hmac_sha256_context, msg+1, sizeof(msg)-2);
hmac_sha256_finalize(hmac_sha256_context);
printf("HMAC-SHA256 (incremental calculation): ");
for (int i = 0; i < sizeof(hmac_sha256_result(hmac_sha256_context)); i++) {
printf("%02x", hmac_sha256_result(hmac_sha256_context)[i]);
}
printf("\n");
hmac_sha1_init(hmac_sha1_context, key, sizeof(key)-1);
hmac_sha1_update(hmac_sha1_context, "T", 1);
hmac_sha1_update(hmac_sha1_context, msg+1, sizeof(msg)-2);
hmac_sha1_finalize(hmac_sha1_context);
printf("HMAC-SHA1 (incremental calculation): ");
for (int i = 0; i < sizeof(hmac_sha1_result(hmac_sha1_context)); i++) {
printf("%02x", hmac_sha1_result(hmac_sha1_context)[i]);
}
printf("\n");
hmac_md5_init(hmac_md5_context, key, sizeof(key)-1);
hmac_md5_update(hmac_md5_context, "T", 1);
hmac_md5_update(hmac_md5_context, msg+1, sizeof(msg)-2);
hmac_md5_finalize(hmac_md5_context);
printf("HMAC-MD5 (incremental calculation): ");
for (int i = 0; i < sizeof(hmac_md5_result(hmac_md5_context)); i++) {
printf("%02x", hmac_md5_result(hmac_md5_context)[i]);
}
printf("\n");
hmac_md4_init(hmac_md4_context, key, sizeof(key)-1);
hmac_md4_update(hmac_md4_context, "T", 1);
hmac_md4_update(hmac_md4_context, msg+1, sizeof(msg)-2);
hmac_md4_finalize(hmac_md4_context);
printf("HMAC-MD4 (incremental calculation): ");
for (int i = 0; i < sizeof(hmac_md4_result(hmac_md4_context)); i++) {
printf("%02x", hmac_md4_result(hmac_md4_context)[i]);
}
printf("\n");
}

89
kdfimpl.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 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.
*/
/*
* This file is a template for computing a key-derivation function
* ("KDF in Counter Mode" as specified in NIST SP 800-108), which may
* use various HMAC functions (among others) as a "pseudo-random function."
*
* This file is #included from the files implementing the hash functions,
* with KDF_PRF defined to the name of the pseudo-random function being used,
* and KDF_PRF_h defined to the width of its output in bits.
*/
#include <string.h>
#define join(a,b) a##b
#define concat(a,b) join(a,b)
#define KDF_PRF_init concat(KDF_PRF,_init)
#define KDF_PRF_update concat(KDF_PRF,_update)
#define KDF_PRF_finalize concat(KDF_PRF,_finalize)
#define KDF_PRF_result concat(KDF_PRF,_result)
#define KDF_PRF_context concat(KDF_PRF,_context)
#define KDF_PRF_kdf_ctr concat(KDF_PRF,_kdf_ctr)
/*
* This implements "KDF in Counter Mode" as specified in NIST SP 800-108.
* See that specification for details of its parameters.
*
* This implementation can be instantiated for various pseudo-random functions
* (e.g. HMACs). It assumes r = 32, and assumes big-endian byte order is used
* for integers. L must be a multiple of 8. The result buffer must be L bits
* (i.e. L/8 bytes) long. The PRF context structure must be provided for use
* within this function; its state at the beginning and end is not meaningful.
*/
void KDF_PRF_kdf_ctr(struct KDF_PRF_context *ctx,
const unsigned char *k_in, unsigned key_len,
unsigned long L, unsigned char *result,
const char *label, unsigned long label_len,
const char *context, unsigned long context_len)
{
unsigned long n, i;
static const char zero = 0;
unsigned long lastSize;
n = L / KDF_PRF_h;
lastSize = L % KDF_PRF_h;
if (lastSize != 0) {
n++;
} else {
lastSize = KDF_PRF_h;
}
for (i = 1; i && i <= n; i++) {
KDF_PRF_init(ctx, k_in, key_len);
KDF_PRF_update(ctx, (unsigned char *)&i + 3, 1);
KDF_PRF_update(ctx, (unsigned char *)&i + 2, 1);
KDF_PRF_update(ctx, (unsigned char *)&i + 1, 1);
KDF_PRF_update(ctx, (unsigned char *)&i + 0, 1);
KDF_PRF_update(ctx, label, label_len);
KDF_PRF_update(ctx, &zero, 1);
KDF_PRF_update(ctx, context, context_len);
KDF_PRF_update(ctx, (unsigned char *)&L + 3, 1);
KDF_PRF_update(ctx, (unsigned char *)&L + 2, 1);
KDF_PRF_update(ctx, (unsigned char *)&L + 1, 1);
KDF_PRF_update(ctx, (unsigned char *)&L + 0, 1);
KDF_PRF_finalize(ctx);
if (i != n) {
memcpy(result, KDF_PRF_result(ctx), KDF_PRF_h/8);
result += KDF_PRF_h/8;
} else {
memcpy(result, KDF_PRF_result(ctx), lastSize/8);
}
}
}

153
md4.asm Normal file
View File

@ -0,0 +1,153 @@
* Copyright (c) 2017,2023 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 md4 hash function for the 65816
case on
mcopy md4.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
zero1 gequ 28
temp gequ 30
zero2 gequ 34
;unused 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
; align 256
g_times_4 private
dc i2' 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60'
dc i2' 0, 16, 32, 48, 4, 20, 36, 52, 8, 24, 40, 56, 12, 28, 44, 60'
dc i2' 0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60'
end
* Initialize a md4 context.
* This must be called before any of the other md4 functions.
md4_init start
CFunction MD4_INIT
end
MD4_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
stz zero1
stz zero2
rtl
end
* Process one 64-byte block through the md4 hashing function.
* This is a low-level function; users should normally not call this directly.
md4_processblock start
CFunction MD4_PROCESSBLOCK
end
MD4_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
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

141
md4.cc Normal file
View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2017,2023 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 "md4.h"
#include <string.h>
#define length_offset 0
#define extra_offset 8
#define hash_offset 40
#define data_offset 60
extern void MD4_PROCESSBLOCK(void);
/*
* Update a md4 context based on the specified data.
*/
void md4_update(struct md4_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 MD4_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 MD4_PROCESSBLOCK
pld
}
length -= 64;
data += 64;
}
memcpy(&context->block, data, length);
context->extra = length;
}
/*
* Finish md4 processing and generate the final hash code.
*/
void md4_finalize(struct md4_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 MD4_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 MD4_PROCESSBLOCK
pld
}
}
#define HASH_ALG md4
#include "hmacimpl.h"
#append "md4.asm"

95
md4.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2017,2023 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 md4_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];
};
struct hmac_md4_context {
union {
struct md4_context ctx;
unsigned char k[64];
} u[3];
unsigned char inner_hash[16];
};
/*
* The context structure must be in bank 0, preferably page-aligned.
*/
/*
* Initialize a md4 context.
* This must be called before any of the other md4 functions.
*/
void md4_init(struct md4_context *context);
/*
* Update a md4 context based on the specified data.
*/
void md4_update(struct md4_context *context, const unsigned char *data, unsigned long length);
/*
* Finish md4 processing and generate the final hash code.
*/
void md4_finalize(struct md4_context *context);
/*
* Process one 64-byte block through the md4 hashing function.
* This is a low-level function; users should normally not call this directly.
*/
void md4_processblock(struct md4_context *context);
/*
* Initialize a context for HMAC-MD4 computation with a specified key.
* This must be called before any other HMAC calls. After initialization,
* the context can be used with either hmac_md4_update/hmac_md4_finalize
* or hmac_md4_compute, but they should not be mixed.
*/
void hmac_md4_init(struct hmac_md4_context *context,
const unsigned char *key,
unsigned long key_length);
/*
* Update an HMAC-MD4 context based on the specified data.
*/
void hmac_md4_update(struct hmac_md4_context *context,
const unsigned char *message_part,
unsigned long part_length);
/*
* Finish HMAC-MD4 processing and generate the final HMAC.
*/
void hmac_md4_finalize(struct hmac_md4_context *context);
/*
* Compute the HMAC-MD4 of a message as a single operation.
* The context can be reused for multiple hmac_md4_compute operations.
*/
void hmac_md4_compute(struct hmac_md4_context *context,
const unsigned char *message,
unsigned long message_length);
/*
* Get the result of an HMAC-MD4 computation following hmac_md4_finalize
* or hmac_md4_compute.
*/
#define hmac_md4_result(context) ((context)->u[0].ctx.hash)

361
md4.macros Normal file
View File

@ -0,0 +1,361 @@
* Copyright (c) 2017,2023 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
* Expects the contents of &loc+2 to be loaded in A already
macro
ROTR4CONT &loc,&n
aif &n>16,.dorotl
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
* Expects the contents of &loc to be loaded in A already
macro
ROTL4CONT &loc,&n
aif &n>16,.dorotr2
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
* Left-rotate with various optimizations applied
macro
ROTL4AUTO &loc,&n,&haveLocPlus2
aif &n>4,.skip1
ROTL4 &loc,&n
mexit
.skip1
aif &n>7,.skip2
ldx &loc+1
lda &loc+3
ora &loc-1
sta &loc
stx &loc+2
txa
ROTR4CONT &loc,8-&n
mexit
.skip2
aif &n>11,.skip3
ldx &loc+1
lda &loc+3
ora &loc-1
sta &loc
stx &loc+2
ROTL4CONT &loc,&n-8
mexit
.skip3
aif &n>15,.skip4
aif C:&haveLocPlus2>0,.noload1
ldy &loc+2
ago .didload1
.noload1
tay
.didload1
lda &loc
sta &loc+2
sty &loc
ROTR4CONT &loc,16-&n
mexit
.skip4
aif &n>16,.skip5
aif C:&haveLocPlus2>0,.noload2
lda &loc+2
.noload2
ldy &loc
sta &loc
sty &loc+2
mexit
.skip5
aif &n>20,.skip6
aif C:&haveLocPlus2>0,.noload2
lda &loc+2
.noload2
ldy &loc
sta &loc
sty &loc+2
ROTL4CONT &loc,&n-16
mexit
.skip6
ldx &loc+1
lda &loc+3
ora &loc-1
sta &loc+2
stx &loc
ROTR4CONT &loc,24-&n
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 temp
lda &c+2
eor &d+2
and &b+2
eor &d+2
adc &a+2
sta temp+2
.skip1
* f_16 to f_31
aif &part<>2,.skip2
lda &c
tax
ora &d
and &b
sta temp
txa
and &d
ora temp
clc
adc &a
tay
lda &c+2
tax
ora &d+2
and &b+2
sta temp+2
txa
and &d+2
ora temp+2
adc &a+2
tax
clc
tya
adc #$7999
sta temp
txa
adc #$5A82
sta temp+2
.skip2
* f_32 to f_47
aif &part<>3,.skip3
lda &b
eor &c
eor &d
clc
adc &a
tay
lda &b+2
eor &c+2
eor &d+2
adc &a+2
tax
clc
tya
adc #$EBA1
sta temp
txa
adc #$6ED9
sta temp+2
.skip3
ldy idx
ldx g_times_4,y
lda m,x
clc
adc temp
sta temp
inx
inx
lda m,x
adc temp+2
sta temp+2
iny
iny
sty idx
ROTL4AUTO temp,&shift,1
lda temp
sta &a
lda temp+2
sta &a+2
mend
* One part of the loop for processing blocks (16 iterations)
macro
BlockLoopPart &part
loop&part anop
aif &part<>1,.skip1a
BlockLoopIter a_,b,c,d,3
BlockLoopIter d,a_,b,c,7
BlockLoopIter c,d,a_,b,11
BlockLoopIter b,c,d,a_,19
.skip1a
aif &part<>2,.skip2a
BlockLoopIter a_,b,c,d,3
BlockLoopIter d,a_,b,c,5
BlockLoopIter c,d,a_,b,9
BlockLoopIter b,c,d,a_,13
.skip2a
aif &part<>3,.skip3a
BlockLoopIter a_,b,c,d,3
BlockLoopIter d,a_,b,c,9
BlockLoopIter c,d,a_,b,11
BlockLoopIter b,c,d,a_,15
.skip3a
lda idx
cmp #16*2*&part
bge endloop&part
jmp loop&part
endloop&part anop
mend

20
md4sum.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2017,2023 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 "md4.h"
#define HASH_FUNCTION md4
#include "cksumcommon.h"

94
md4test.c Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2017,2023 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 "md4.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 md4_context *context, **context_hndl;
struct md4_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 md4_context **)NewHandle(sizeof(struct md4_context),
userid(), attrFixed|attrPage|attrBank|attrNoCross, 0x000000);
if (toolerror())
return 0;
context = *context_hndl;
*context = context_init;
md4_init(context);
md4_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++) {
md4_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();
md4_init(context);
md4_update(context, (void*)0x030000, 64000);
md4_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) {
md4_init(context);
md4_update(context, argv[1], strlen(argv[1]));
md4_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]);
}
}

5
md5.cc
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Stephen Heumann
* Copyright (c) 2017,2023 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
@ -135,4 +135,7 @@ void md5_finalize(struct md5_context *context)
}
}
#define HASH_ALG md5
#include "hmacimpl.h"
#append "md5.asm"

46
md5.h
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Stephen Heumann
* Copyright (c) 2017,2023 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
@ -24,6 +24,14 @@ struct md5_context {
unsigned char block[64];
};
struct hmac_md5_context {
union {
struct md5_context ctx;
unsigned char k[64];
} u[3];
unsigned char inner_hash[16];
};
/*
* The context structure must be in bank 0, preferably page-aligned.
*/
@ -49,3 +57,39 @@ void md5_finalize(struct md5_context *context);
* This is a low-level function; users should normally not call this directly.
*/
void md5_processblock(struct md5_context *context);
/*
* Initialize a context for HMAC-MD5 computation with a specified key.
* This must be called before any other HMAC calls. After initialization,
* the context can be used with either hmac_md5_update/hmac_md5_finalize
* or hmac_md5_compute, but they should not be mixed.
*/
void hmac_md5_init(struct hmac_md5_context *context,
const unsigned char *key,
unsigned long key_length);
/*
* Update an HMAC-MD5 context based on the specified data.
*/
void hmac_md5_update(struct hmac_md5_context *context,
const unsigned char *message_part,
unsigned long part_length);
/*
* Finish HMAC-MD5 processing and generate the final HMAC.
*/
void hmac_md5_finalize(struct hmac_md5_context *context);
/*
* Compute the HMAC-MD5 of a message as a single operation.
* The context can be reused for multiple hmac_md5_compute operations.
*/
void hmac_md5_compute(struct hmac_md5_context *context,
const unsigned char *message,
unsigned long message_length);
/*
* Get the result of an HMAC-MD5 computation following hmac_md5_finalize
* or hmac_md5_compute.
*/
#define hmac_md5_result(context) ((context)->u[0].ctx.hash)

View File

@ -334,7 +334,7 @@
mend
* One part of the loop for processing blocks (20 iterations)
* One part of the loop for processing blocks (16 iterations)
macro
BlockLoopPart &part

55
rc4.asm Normal file
View File

@ -0,0 +1,55 @@
* Copyright (c) 2023 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.
* Direct page locations
i gequ 0
j gequ 1
S gequ 2
* Do one step of the RC4 pseudo-random generation algorithm.
* Call with DP = RC4 context structure, and short M/X.
RC4_PRGA start
;i := (i + 1) mod 256
inc i
;j := (j + S[i]) mod 256
ldx i
clc
lda S,x
tay
adc j
sta j
;swap values of S[i] and S[j]
tax
lda S,x
ldx i
sta S,x
ldx j
tya
sta S,x
;temp := (S[i] + S[j]) mod 256
ldx i
clc
adc S,x
;return S[temp]
tax
lda S,x
rtl
end

81
rc4.cc Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2023 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 "rc4.h"
/*
* Initialize an RC4 context context with a specified key.
* This must be called before calling rc4_process.
*/
void rc4_init(struct rc4_context *context,
const unsigned char *key,
unsigned keylength)
{
unsigned int i;
unsigned char j;
unsigned char temp;
for (i = 0; i < 256; i++) {
context->S[i] = i;
}
j = 0;
for (i = 0; i < 256; i++) {
j = j + context->S[i] + key[i % keylength];
temp = context->S[j];
context->S[j] = context->S[i];
context->S[i] = temp;
}
context->i = 0;
context->j = 0;
}
/*
* Process data using RC4. This either encrypts or decrypts data,
* depending on whether in contains plaintext or ciphertext.
*
* To get the raw RC4 output stream, specify the input as all zeros.
* The same buffer may be used for in and out.
*/
void rc4_process(struct rc4_context *context,
const unsigned char *in,
unsigned char *out,
unsigned long length)
{
extern unsigned char RC4_PRGA(void);
while (length--) {
asm {
phd
lda context
tcd
sep #0x30
jsl RC4_PRGA
pld
eor [in]
sta [out]
rep #0x30
}
in++;
out++;
}
}
#append "rc4.asm"

40
rc4.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 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 rc4_context {
unsigned char i,j;
unsigned char S[256];
};
/*
* Initialize an RC4 context context with a specified key.
* This must be called before calling rc4_process.
*/
void rc4_init(struct rc4_context *context,
const unsigned char *key,
unsigned keylength);
/*
* Process data using RC4. This either encrypts or decrypts data,
* depending on whether in contains plaintext or ciphertext.
*
* To get the raw RC4 output stream, specify the input as all zeros.
* The same buffer may be used for in and out.
*/
void rc4_process(struct rc4_context *context,
const unsigned char *in,
unsigned char *out,
unsigned long length);

39
rc4test.c Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2023 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 <stdio.h>
#include <string.h>
#include "rc4.h"
int main(int argc, char *argv[]) {
struct rc4_context context;
size_t length;
size_t i;
if (argc < 3)
return 0;
rc4_init(&context, argv[1], strlen(argv[1]));
length = strlen(argv[2]);
rc4_process(&context, argv[2], argv[2], length);
for(i = 0; i < length; i++) {
printf("%02x", argv[2][i]);
}
printf("\n");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Stephen Heumann
* Copyright (c) 2017,2023 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
@ -180,4 +180,7 @@ void sha1_finalize(struct sha1_context *context)
}
}
#define HASH_ALG sha1
#include "hmacimpl.h"
#append "sha1.asm"

46
sha1.h
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Stephen Heumann
* Copyright (c) 2017,2023 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
@ -24,6 +24,14 @@ struct sha1_context {
unsigned char reserved2[16];
};
struct hmac_sha1_context {
union {
struct sha1_context ctx;
unsigned char k[64];
} u[3];
unsigned char inner_hash[20];
};
/*
* The context structure must be in bank 0, preferably page-aligned.
*/
@ -49,3 +57,39 @@ void sha1_finalize(struct sha1_context *context);
* This is a low-level function; users should normally not call this directly.
*/
void sha1_processblock(struct sha1_context *context);
/*
* Initialize a context for HMAC-SHA1 computation with a specified key.
* This must be called before any other HMAC calls. After initialization,
* the context can be used with either hmac_sha1_update/hmac_sha1_finalize
* or hmac_sha1_compute, but they should not be mixed.
*/
void hmac_sha1_init(struct hmac_sha1_context *context,
const unsigned char *key,
unsigned long key_length);
/*
* Update an HMAC-SHA1 context based on the specified data.
*/
void hmac_sha1_update(struct hmac_sha1_context *context,
const unsigned char *message_part,
unsigned long part_length);
/*
* Finish HMAC-SHA1 processing and generate the final HMAC.
*/
void hmac_sha1_finalize(struct hmac_sha1_context *context);
/*
* Compute the HMAC-SHA1 of a message as a single operation.
* The context can be reused for multiple hmac_sha1_compute operations.
*/
void hmac_sha1_compute(struct hmac_sha1_context *context,
const unsigned char *message,
unsigned long message_length);
/*
* Get the result of an HMAC-SHA1 computation following hmac_sha1_finalize
* or hmac_sha1_compute.
*/
#define hmac_sha1_result(context) ((context)->u[0].ctx.hash)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Stephen Heumann
* Copyright (c) 2017,2023 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
@ -204,4 +204,11 @@ void sha256_finalize(struct sha256_context *context)
}
}
#define HASH_ALG sha256
#include "hmacimpl.h"
#define KDF_PRF hmac_sha256
#define KDF_PRF_h 256
#include "kdfimpl.h"
#append "sha256.asm"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Stephen Heumann
* Copyright (c) 2017,2023 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
@ -24,6 +24,14 @@ struct sha256_context {
unsigned char reserved2[60];
};
struct hmac_sha256_context {
union {
struct sha256_context ctx;
unsigned char k[64];
} u[3];
unsigned char inner_hash[32];
};
/*
* The context structure must be in bank 0, preferably page-aligned.
*/
@ -57,3 +65,55 @@ void sha256_finalize(struct sha256_context *context);
* This is a low-level function; users should normally not call this directly.
*/
void sha256_processblock(struct sha256_context *context);
/*
* Initialize a context for HMAC-SHA256 computation with a specified key.
* This must be called before any other HMAC calls. After initialization,
* the context can be used with either hmac_sha256_update/hmac_sha256_finalize
* or hmac_sha256_compute, but they should not be mixed.
*/
void hmac_sha256_init(struct hmac_sha256_context *context,
const unsigned char *key,
unsigned long key_length);
/*
* Update an HMAC-SHA256 context based on the specified data.
*/
void hmac_sha256_update(struct hmac_sha256_context *context,
const unsigned char *message_part,
unsigned long part_length);
/*
* Finish HMAC-SHA256 processing and generate the final HMAC.
*/
void hmac_sha256_finalize(struct hmac_sha256_context *context);
/*
* Compute the HMAC-SHA256 of a message as a single operation.
* The context can be reused for multiple hmac_sha256_compute operations.
*/
void hmac_sha256_compute(struct hmac_sha256_context *context,
const unsigned char *message,
unsigned long message_length);
/*
* Get the result of an HMAC-SHA256 computation following hmac_sha256_finalize
* or hmac_sha256_compute.
*/
#define hmac_sha256_result(context) ((context)->u[0].ctx.hash)
/*
* This implements "KDF in Counter Mode" as specified in NIST SP 800-108, with
* HMAC-SHA256 as the pseudo-random function. See that specification for
* details of its parameters.
*
* This implementation assumes r = 32 and assumes big-endian byte order is used
* for integers. L must be a multiple of 8. The result buffer must be L bits
* (i.e. L/8 bytes) long. The HMAC-SHA256 context must be provided for use
* within this function; its state at the beginning and end is not meaningful.
*/
void hmac_sha256_kdf_ctr(struct hmac_sha256_context *ctx,
const unsigned char *k_in, unsigned key_len,
unsigned long L, unsigned char *result,
const char *label, unsigned long label_len,
const char *context, unsigned long context_len);