From 93ce5a404df32169901e05a869f8b226ad74d941 Mon Sep 17 00:00:00 2001
From: Steve Kemp
Date: Thu, 28 Mar 2024 18:25:46 +0200
Subject: [PATCH 1/3] Generate encrypted versions of the ZX Spectrum game
The recent issue with broken encryption, reported in #37, might have
been more easily visible if I'd generated encrypted versions of the
ZX Spectrum image.
Generating an encrypted ZX Spectrum binary is largely the same as
the process for the CP/M binary - with one complication:
* Generate the build, with the DEFINE set.
* Post-process the generated build, to XOR the contents.
The complication is that the .TAP file generated for Spectrums contains
checksums, so we needed to update the `encrypt.c` helper to add support
for that (optionally).
I've updated the `release` target of the Makefile to consider ordering
too, such that we generate "naked" and "encrypted" releases of both
our versions.
All together this should close #38.
---
.gitignore | 4 +-
Makefile | 52 ++++++++++++++++-----
README.md | 14 ++++--
encrypt.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 174 insertions(+), 27 deletions(-)
diff --git a/.gitignore b/.gitignore
index 8655e68..e6de444 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,4 @@
-game.com
-lihouse.com
-lihouse2.com
lighthouse
encrypt
*.tap
+*.com
diff --git a/Makefile b/Makefile
index 73f30a4..b75ea37 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,7 @@ VERSION := $(or ${GITHUB_REF},${GITHUB_REF},"unreleased-git")
all: lighthouse game-cpm game-spectrum
+
# Build the C version
lighthouse: handlers.c inventory.c items.c main.c world.c util.c
gcc -o lighthouse -Os -Wall -Wextra -Werror handlers.c inventory.c items.c main.c world.c util.c
@@ -14,6 +15,12 @@ lighthouse: handlers.c inventory.c items.c main.c world.c util.c
clean:
rm -f lighthouse *.com *.tap encrypt || true
+
+# Build the encryption helper
+encrypt: encrypt.c
+ gcc -o encrypt -Wall -Werror encrypt.c
+
+
# Format our C-code
format:
astyle --style=allman -A1 --indent=spaces=4 --break-blocks --pad-oper --pad-header --unpad-paren --max-code-length=200 *.c *.h
@@ -23,28 +30,51 @@ format:
version:
echo "DB \"$$(echo ${VERSION} | awk -F/ '{print $$NF}' )\"" > version.z80
+
+
# build the game for CP/M
game-cpm: game.z80 bios.z80 version Makefile
pasmo --equ ENTRYPOINT=100h --equ ENCRYPT_STRINGS=0 --equ SPECTRUM=0 game.z80 lihouse.com
+# build the game for CP/M with encrypted strings/code
+game-cpm-encrypted: game.z80 bios.z80 version Makefile encrypt
+ pasmo --equ ENTRYPOINT=100h --equ ENCRYPT_STRINGS=1 --equ SPECTRUM=0 game.z80 lihouse.com
+ ./encrypt lihouse.com lihousex.com
+ rm lihouse.com
+
+
+
# build the game for the ZX Spectrum
game-spectrum: game.z80 bios.z80 version Makefile
pasmo --tapbas --equ ENTRYPOINT=32768 --equ ENCRYPT_STRINGS=0 --equ SPECTRUM=1 game.z80 lihouse.tap
-# Build the encryption helper
-encrypt: encrypt.c
- gcc -o encrypt -Wall -Werror encrypt.c
+# build the game for the ZX Spectrum with encrypted strings
+game-spectrum-encrypted: game.z80 bios.z80 version Makefile encrypt
+ pasmo --tapbas --equ ENTRYPOINT=32768 --equ ENCRYPT_STRINGS=1 --equ SPECTRUM=1 game.z80 lihouse.tap
+ ./encrypt -crc lihouse.tap lihousex.tap
+ rm lihouse.tap
+
# Build the game for release - with strings encrypted
-release: game.z80 encrypt version
- pasmo --equ ENTRYPOINT=100h --equ ENCRYPT_STRINGS=1 --equ SPECTRUM=0 game.z80 lihouse.com
- ./encrypt
- mv lihouse2.com lihouse.com
+release: version
+ make game-cpm-encrypted
+ make game-cpm
+ make game-spectrum-encrypted
+ make game-spectrum
-# Run for CP/M
-run-cpm: game
+# Run the CP/M version via runcpm
+run-cpm: game-cpm
~/cpm/cpm lihouse
-run-spectrum:
- xspect -quick-load -load-immed -tap *.tap
+# Run the CP/M version via runcpm, with the encrypted version of the code
+run-cpm-encrypted: game-cpm-encrypted
+ ~/cpm/cpm lihouseX
+
+# Run the spectrum version
+run-spectrum: game-spectrum
+ xspect -quick-load -load-immed -tap lihouse.tap
+
+# Run the spectrum version, with strings encrypted
+run-spectrum-encrypted: game-spectrum-encrypted
+ xspect -quick-load -load-immed -tap lihousex.tap
diff --git a/README.md b/README.md
index 01a717a..948ee91 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ Quick links within this README file:
* [Bugs?](#bugs)
+
## Play Online
Thanks to the excellent [jsspeccy](https://github.com/gasman/jsspeccy3) ZX Spectrum emulator you can play this game with your browser here:
@@ -88,9 +89,11 @@ defining `SPECTRUM`, and `ENTRYPOINT` as appropriate.
* Along the way I realized that having fixed inventory slots made the coding more of a challenge, so I made the location of each object a property of the object itself.
* The Z80 version has more easter-eggs (Try typing "`xyzzy`" a few times).
* There are __two__ victory conditions.
-* The CP/M version of the game can be built with the text-strings, and game code, protected by simple XOR encryption:
+* The game can be built with the text-strings, and game code, protected by simple XOR encryption:
* This stops users from looking through the binary for hints.
- * Run `make release` to build the _protected_ CP/M version.
+ * Run `make release` to build both "normal" and "protected" versions of the release.
+ * The encrypted versions of the games have an X suffix in their filenames.
+
## Compiling & Running It
@@ -106,9 +109,11 @@ Running `make` will generate the default targets:
If you wish to build only individual things then :
* `make game-cpm` to build a normal CP/M version.
+* `make game-cpm-encrypted` to build an encrypted CP/M version.
* `make game-spectrum` to build the ZX Spectrum version.
+* `make game-spectrum-encrypted` to build the encrypted ZX Spectrum version.
* `make lighthouse` will build the C-game for Linux
-* `make release` will build the _protected_ CP/M version.
+* `make release` will build both versions of the CP/M and ZX Spectrum release.
@@ -117,7 +122,10 @@ If you wish to build only individual things then :
If you look on our [release page](https://github.com/skx/lighthouse-of-doom/releases/) you can find the latest stable build.
* For CP/M download `lihouse.com` to your system, and then run `LIHOUSE` to launch it.
+ * `lihouseX.com` is the encrypted version.
* For the ZX Spectrum download `lihouse.tap` to your system, and then launch in your favourite emulator.
+ * `lihouseX.tap` is the encrypted version.
+
## Bugs?
diff --git a/encrypt.c b/encrypt.c
index ea7c0d5..2e977bc 100644
--- a/encrypt.c
+++ b/encrypt.c
@@ -1,5 +1,8 @@
/*
- * Load `lihouse.com` and scramble the strings, saving to `lihouse2.com`.
+ * Generate an encrypted version of the specified input file.
+ *
+ * Optionally update the CRC check of the file - this is necessary
+ * for the .TAP version we generate for the ZX Spectrum.
*/
#include
@@ -7,41 +10,121 @@
#include
#include
+typedef unsigned char byte;
+
+
+// calculate the checksum for the given region
+byte crc(byte *start, int length)
+{
+ byte tcrc = 0;
+
+ for (int i = 0; i < length; i++)
+ tcrc = tcrc ^ start[i];
+
+ return tcrc;
+}
+
int main(int argc, char *argv[])
{
- FILE *f = fopen("lihouse.com", "r");
+ // check argument count
+ if (argc != 3 && argc != 4)
+ {
+ printf("Usage: encrypt [-crc] input output\n");
+ return 1;
+ }
+
+ // flags / arguments
+ int do_crc = 0;
+ char *input = NULL;
+ char *output = NULL;
+
+ // look for flags
+ if (argc == 4)
+ {
+ // Should we run a CRC update?
+ for (int i = 1; i < argc ; i++)
+ {
+ if (strcmp(argv[i], "-crc") == 0)
+ {
+ do_crc = 1;
+ }
+ }
+ }
+
+ // look for input/output names.
+ for (int i = 1; i < argc ; i++)
+ {
+ // Ignore flags
+ if (strcmp(argv[i], "-crc") == 0)
+ {
+ continue;
+ }
+
+ // input file goes first
+ if (input == NULL)
+ {
+ input = argv[i];
+ continue;
+ }
+
+ // output file goes second.
+ if (output == NULL)
+ {
+ output = argv[i];
+ continue;
+ }
+ }
+
+ printf("Input file: %s\n", input);
+ printf("Output file: %s\n", output);
+
+ if (do_crc)
+ {
+ printf("CRC will be updated\n");
+ }
+ else
+ {
+ printf("No CRC update\n");
+ }
+
+ // Open the file for reading
+ FILE *f = fopen(input, "r");
if (f == NULL)
{
- printf("Failed to open file\n");
- return 0;
+ printf("Failed to open input file: %s\n", input);
+ return 1;
}
// get file size
fseek(f, 0L, SEEK_END);
size_t sz = ftell(f);
+ printf("File size is %ld bytes\n", sz);
+
// get back to start
fseek(f, 0L, SEEK_SET);
// allocate memory
- char *buf = malloc(sz);
+ unsigned char *buf = malloc(sz);
if (buf == NULL)
{
printf("failed to allocate memory\n");
- return 0;
+ return 1;
}
// read the file
- int n = fread(buf, sizeof(char), sz, f);
+ int n = fread(buf, sizeof(unsigned char), sz, f);
if (ferror(f) != 0)
{
printf("error reading\n");
return 1;
}
- if ( n != sz ) {
+
+ if (n != sz)
+ {
printf("short read\n");
return 1;
}
@@ -68,12 +151,40 @@ int main(int argc, char *argv[])
k++;
}
+ if (do_crc)
+ {
+ // Now we have to fixup the CRC
+ unsigned char *pos = buf;
+
+ for (int i = 1; i < sz; i++)
+ {
+ size_t blocksize = pos[0] | (pos[1] << 8);
+
+ if ((pos + blocksize + 1) < (buf + sz))
+ {
+ if (blocksize > 1)
+ {
+ char ccrc = crc(&pos[2], blocksize - 1);
+
+ if (pos[blocksize + 1] != ccrc)
+ {
+ printf("Updated CRC\n");
+ pos[blocksize + 1] = ccrc;
+ }
+ }
+ }
+
+
+ pos += blocksize + 2;
+ }
+ }
+
// Write
- FILE *nw = fopen("lihouse2.com", "w");
+ FILE *nw = fopen(output, "w");
if (nw == NULL)
{
- printf("Failed to open file for writing\n");
+ printf("Failed to open file for writing: %s\n", output);
}
fwrite(buf, sz, 1, nw);
From 9742fb139e0afab6facacc0e5ddcf5b889950d7d Mon Sep 17 00:00:00 2001
From: Steve Kemp
Date: Thu, 28 Mar 2024 18:29:38 +0200
Subject: [PATCH 2/3] Corrected case used in the filename.
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 948ee91..d931132 100644
--- a/README.md
+++ b/README.md
@@ -122,9 +122,9 @@ If you wish to build only individual things then :
If you look on our [release page](https://github.com/skx/lighthouse-of-doom/releases/) you can find the latest stable build.
* For CP/M download `lihouse.com` to your system, and then run `LIHOUSE` to launch it.
- * `lihouseX.com` is the encrypted version.
+ * `lihousex.com` is the encrypted version.
* For the ZX Spectrum download `lihouse.tap` to your system, and then launch in your favourite emulator.
- * `lihouseX.tap` is the encrypted version.
+ * `lihousex.tap` is the encrypted version.
From c1f0f8a72f30305ee58d02f204a4acc15f90e36f Mon Sep 17 00:00:00 2001
From: Steve Kemp
Date: Thu, 28 Mar 2024 18:31:31 +0200
Subject: [PATCH 3/3] Minor cleanup
---
README.md | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index d931132..1587dba 100644
--- a/README.md
+++ b/README.md
@@ -100,18 +100,12 @@ defining `SPECTRUM`, and `ENTRYPOINT` as appropriate.
Ensure you have the `pasmo` assembler installed, and then use the supplied Makefile to compile the game.
-Running `make` will generate the default targets:
-
-* `make lighthouse` -> Build the game for linux.
-* `make lihouse.com` -> Build the game for CP/M, without the XOR encryption.
-* `make lihouse.tap` -> Build the game for the 48k ZX Spectrum.
-
-If you wish to build only individual things then :
+Running `make` will generate the default targets, if you wish to build only individual things then :
* `make game-cpm` to build a normal CP/M version.
-* `make game-cpm-encrypted` to build an encrypted CP/M version.
+ * `make game-cpm-encrypted` to build an encrypted CP/M version.
* `make game-spectrum` to build the ZX Spectrum version.
-* `make game-spectrum-encrypted` to build the encrypted ZX Spectrum version.
+ * `make game-spectrum-encrypted` to build the encrypted ZX Spectrum version.
* `make lighthouse` will build the C-game for Linux
* `make release` will build both versions of the CP/M and ZX Spectrum release.