Let's recap a little
So far we've:
- Reversed a string
- Shifted bits left and right (mostly right)
- Brute forced a known simple cipher
- Faked it, but then looking for a 4 digit known pin
What we need next in our toolbox is to be able to search through a large number of values to look for something. This will build on the previous skills and also reinforce working with tables and 24 bit math on an 8Bit Processor.
I think Joshua can help us with this.
"It's sending random numbers to the silos"
Joshua starts to brute force try all of the possible combinations. If the programmer had limited the number of failed tries allowed...
"At this rate the computer will have the codes in 5.3 minutes."
This is an interesting scene to implement in our Cipher series because we can build upon the Terminator pin cracker which just did some random stuff before running down 10000 decimals to find a pre coded pin.
For the Wargames demo we'll:
- Generate random launch code hashes on each startup
- Search through these codes in a table to find the matches
- Stop the launch code for that hash and use as the launch code sequence
- Launch the missiles, therefore making a mess of earth
The idea of the series is to keep building toolsets so we can do "real" cracking later. Whatever "real" cracking is. I've now watched this movie twice this week in preparation for this article and what we're doing here might not be too far off from what Joshua (the computer) would have had to do to get the launch codes.
Generating random numbers on the Commodore is pretty simple, we'll continue to use the method from Compute! magazine. There IS a strange caveat: it only generates a new random byte every so many CPU cycles, so we actually need to delay a bit to keep from getting a couple in a row. Robin explores this in depth here
genlaunchcodes .block ldx #31 loop lda $d41b sta launchhash,x dex bne loop rts .bend
Without it, we get some repeats:
Adding some NOPs here helps, even if it feels wasteful. We only need to do it once during the setup, so don't get too bent out of shape over a handful of wasted cycles.
genlaunchcodes .block ldx #31 loop nop nop nop nop nop lda $d41b sta launchhash,x dex bne loop rts .bend launchhash .byte 0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0
Great, so now we use these random bytes as the encoded codes to guess and store them in a table called launchhash. We'll work on them in groups of three, so there's going to be some 24 bit math to do. Don't worry, it's not that difficult.
24 bits gives us 2563 (16777216) total possible numbers to search through. The Commodore runs at roughly 0.43 MIPS (Millions of instructions per second) at the 1Mhz clock cycle, so this can actually take a while.
Btw, this is not remotely close to being random enough for anything serious in 2021 (or 2001 for that matter), but it's random enough for games and demos to be useful and it's easy to implement.
Needs to take 5 minutes
"At this rate the computer will have the codes in 5.3 minutes."
Going back to the movie scene, it would be nice to be able to get this code in a similar amount of time. Maybe a little faster so we don't have to sit and watch it for 5.3 minutes right?
NAH! Let's assume the 24 bits which seems more realistic for a 1983 set of codes for a missile launch. Plus we need to work 24 bit math into this series, so this is a good place to do it. 32 bits and up is the same thing we do here, just more times to loop.
24 bit "codes" to crack
We need to search through 16,777,216 combinations 10 times (one for each of the launch code digits).
getlaunch .block loop clc lda launchcode,x adc #1 sta launchcode,x bcc aheadc lda launchcode+1,x adc #0 sta launchcode+1,x bcc aheadc lda launchcode+2,x adc #0 sta launchcode+2,x aheadc lda launchcode+2,x cmp launchhash+2,x bne ahead lda launchcode+1,x cmp launchhash+1,x bne ahead lda launchcode,x cmp launchhash,x beq done ahead jmp loop done rts .bend
We want to call this routine as fast as we can while allowing the screen updates to happen slower.
A simple way to time screen updates is to wait for a raster line in a wait loop. Some variation of:
Update the screen launch codes
This update runs slowly to match the movie speed that Joshua is guessing the numbers at (apparently, it's fake of course). If we just wait for a raster line to update the screen rotations, we effectively halt all of the other routines while it's waiting. On an NTSC machine, 60 calculations per second to count to 16,777,216 10 times will take longer than we need it to. And we can certainly count much faster than +1 per frame. In fact, we NEED to, it would take more then 770 hours to count to the maximum at this rate!
IRQ the screen update
Let's move the screen update to an IRQ and leave the "cracker" routine running in the main loop. This way we only get interrupted on the IRQ calls to update the screen. This dramatically speeds up the background calculations. Don't worry if you're not sure about this routine at the moment, we'll go over it in detail later in the series.
irqsetup sei ldy #$7f sty $dc0d sty $dc0d lda $dc0d lda $dd0d lda #$01 sta $d01a lda #<irq ldx #>irq sta $0314 stx $0315 lda #100 sta $d012 cli ;---- below is what gets called when we get to raster line 100 now irq .block dec $d019 beq skip jsr guesscodes skip jmp $ea81 rts .bend
Fake but not fake
Since we're doing a real match on a random set of bytes we generate every time we run this, the chances of us getting the same launch code as the one in the movie are, well, pretty slim.
Because we're matching on a random number, ours will stop on each digit when it stops.
This turned out really well. I added a few (pretty sloppy) routines to randomize the digits at startup and the order in which the found hashes match and we get a real time movie effect.
It actually takes between 3.5 and 4 hours to get all 10 of them. MUCH better than the 770 hours (that's 32 days) it was going to take before moving the screen into the IRQ routine. Not bad for a 1983 Computer you could buy at Toys-R-Us for $299. Or $149 two years later. A bargain!
Here it is sped up to complete in less than a minute via the magic of video editing. This took 3.7 hours this time. It will take a different amount each time since we're generating the hashes to find randomly.
Are there improvements that can be made? For certain. Does it work and look pretty cool? It does.
- use a table to randomize the starting positions of each of the 10 launch code characters like my version shows
- create a python version of this routine and compare the speed