Hacking an old ZIP file with crypto programs of the South African underground

It's not often that we get to study code that only a few people have seen before; a code that was an important part of the destruction of the apartheid system in South Africa; a code used for secure communications with one-time ciphers smuggled into South Africa on floppy disks by a flight attendant. But I experienced this one morning shortly after decrypting a thirty-year-old PKZIP file whose password had long been forgotten.

Recently I became interested in secure communications that were used African National Congress within Operation Voulacarried out in the late 1980s. Operation Vula involved the infiltration of ANC leaders (and transfer of equipment) into South Africa to prepare a secret network that carried out various elements of ANC political activity within the country.

The success of the operation required secure communications based on 8-bit computers, DTMF signals, acoustic transducers and various other equipment for exchanging messages with one-time encryption, using programs written in PowerBASIC.

I won't go into details about how all this works, since the main developer of the encryption system

Tim Jenkin

posted the source code in

open source

. Tim's article on the encryption system can be found

Here

. I highly recommend reading it if you are interested in details.

The code was not made open source earlier for one simple reason: while flying from the UK to South Africa in 1991, he packaged all the source code in a zip file and set a password. In subsequent years, he simply forgot the password! Therefore, when I wrote him a letter asking if it was possible to open source it, he replied:

I still have the source code for Voola, but unfortunately it is mostly inaccessible because when I returned from the UK to South Africa in 1991, I zip-zipped all the files with a password. I was able to decrypt and unpack one of the files, but, alas, it was a very early version of the software. I can't retrieve the rest because I forgot the password. When I returned to South Africa, there was no need for code. I thought I would never forget the password, but when I tried to decrypt it several years later, I couldn't remember it.

If you can figure out how to decode zipped files, I'll be happy to publish them. I have already tried to crack the code several times, but have not yet achieved success.

I readily agreed and he sent me two files:

ALLBAS.ZIP

And

CODMAY93.ZIP

. They were created in an old version of PKZIP and are password protected. Fortunately, there is

known plaintext attack

to the ZipCrypto scheme, which was used in the ZIP format of that era. And the open source implementation of this attack is called

bkcrack

.

That is, it was enough to “simply” predict 12 bytes of plaintext at a known location inside the ZIP file. Here's a snippet of what was inside the ZIP file:

$ bkcrack -L ALLBAS.ZIP | head -n 20

bkcrack 1.7.0 - 2024-05-26
Archive: ALLBAS.ZIP
Index Encryption Compression CRC32    Uncompressed  Packed size Name
----- ---------- ----------- -------- ------------ ------------ ----------------
    0 ZipCrypto  Shrink      b0f86b1d          163          117 A1PSW.BAS
    1 ZipCrypto  Shrink      8fa662d4          163          118 A2PSW.BAS
    2 ZipCrypto  Shrink      0c5a7295          163          119 A3PSW.BAS
    3 ZipCrypto  Shrink      49907f86          179          125 A4PSW.BAS
    4 ZipCrypto  Shrink      3d20eb7a          163          120 A5PSW.BAS
    5 ZipCrypto  Shrink      f8b558f0          136          128 BIOS.INC
    6 ZipCrypto  Implode     799074ed          377          278 CHKERR.INC
    7 ZipCrypto  Implode     c44ea0a5        17906         5401 CODSUBS.INC
    8 ZipCrypto  Implode     7bd7e23d        27287         8297 COMAID.BAS
    9 ZipCrypto  Implode     03dc63da         2109         1001 COMKEY.BAS
   10 ZipCrypto  Store       3500d320         2372         2384 CONFIG.TIM
   11 ZipCrypto  Shrink      35a85089          147          111 CONPSW.BAS
   12 ZipCrypto  Implode     55be75ce         2094          825 DOS.INC
   13 ZipCrypto  Shrink      3387d043          134          127 DOSVER.INC
   14 ZipCrypto  Implode     28a32efa         1304          535 DOSX.INC
   15 ZipCrypto  Implode     6578a66c         3196          966 EDDY.BAS

Tim had several unencrypted files

.BAS

but their versions were different from what was in the file, and attempted attacks

bkcrack

using them (after running from the original PKZIP to

DOSBox

) were unsuccessful; I decided that before carrying out further attacks I needed to think a little.

IN ALLBAS.ZIP contained a lot of uncompressed files because they were already binary and therefore not worth compressing. These files are marked as Store:

$ bkcrack -L ALLBAS.ZIP | grep Store
   10 ZipCrypto  Store       3500d320         2372         2384 CONFIG.TIM
   23 ZipCrypto  Store       14a285ac            2           14 KEYCOD.EXE
   25 ZipCrypto  Store       d6343ce1         4767         4779 KEYONE.ZIP
   26 ZipCrypto  Store       650778b7         6523         6535 KEYTHREE.ZIP
   30 ZipCrypto  Store       12a711cd        58172        58184 OLDCOD.ZIP
   41 ZipCrypto  Store       00000000            0           12 TAPCOD.EXE
   44 ZipCrypto  Store       55000714        12716        12728 TECOD5.ZIP
   45 ZipCrypto  Store       f4f4366c         9230         9242 TECOD6.ZIP

Files stored as

Store

are promising for plaintext prediction because they are not compressed and do not need to compress the source file to obtain the plaintext. Examining ZIP files, since ZIP files begin with a PK header, seemed like a suitable way to find predictable plaintext at a known position. Here are the standard PK header fields at the very beginning of the ZIP file:

I decided that a realistic attack would be to predict the name of the first file in the archive. If the file name consists of at least eight characters (which is quite likely, since at least four characters are used for

.BAS

,

.INC

and so on), then at least 12 characters of plaintext will be available if you add up the size of the file name (offset 0x1A, 0x1B) and the length of the additional field (which in all ZIPs sent by Tim turned out to be equal to 0x00, 0x00).

In the worst case, we will be able to brute force potential filenames, given that they are all combinations of capital letters and numbers with a maximum length of eight characters plus the extension. But it turned out that this was not required.

Fortunately, Tim discovered another version OLDCOD.ZIP (one of the ZIP files inside ALLBAS.ZIP), and he told me that the first file in it is called COMKEY.BAS. I wrote a small Perl program to generate the required plaintext in the hope that OLDCOD.ZIP inside ALLBAS.ZIP starts with COMKEY.BAS

$ cat maken.pl
use strict;
use warnings;

my $outfile = "hexname-$$.txt";

while (<>) {
    chomp;
    my $bas = $_;
    print("$bas / $outfile\n");
    my $n = sprintf("%c\x00\x00\x00$bas",length($bas));
    open G, ">$outfile";
    print G $n;
    close G;
    system("bkcrack -C ALLBAS.ZIP -c OLDCOD.ZIP -p $outfile -o 26 -j 8");
}

In 23 minutes

bkcrack

gave the key to the file

ALLBAS.ZIP

and I managed to decipher it. The same key went to

CODMAY93.ZIP

.

$ time echo "COMKEY.BAS" | perl maken.pl

COMKEY.BAS / hexname-41227.txt

bkcrack 1.7.0 - 2024-05-26

[07:49:38] Z reduction using 6 bytes of known plaintext

100.0 % (6 / 6)

[07:49:38] Attack on 925073 Z values at index 33

Keys: 98e0f009 48a0b11a c70f8499

80.6 % (745571 / 925073) 

Found a solution. Stopping.

You may resume the attack with the option: --continue-attack 745571

[18:13:49] Keys

98e0f009 48a0b11a c70f8499


real 23m4.371s

user 162m3.520s

sys 0m37.752s

After finding the key

bkcrack

performs decryption:

$ bkcrack -C ALLBAS.ZIP -k 98e0f009 48a0b11a c70f8499 -D ALLBAS-DECRYPTED.ZIP

bkcrack 1.7.0 - 2024-05-26

[07:52:22] Writing decrypted archive ALLBAS-DECRYPTED.ZIP

100.0 % (81 / 81)

$ bkcrack -C CODMAY93.ZIP -k 98e0f009 48a0b11a c70f8499 -D CODMAY93-DECRYPTED.ZIP

bkcrack 1.7.0 - 2024-05-26

[07:58:31] Writing decrypted archive CODMAY93-DECRYPTED.ZIP

100.0 % (40 / 40)

And so we finally received the long-lost source code used to organize ANC secure communications!

If I didn't succeed, I would attack one of the other ZIP files using the same method (and then just start trying out the file names). I would guess that TECOD5.ZIPwas probably a ZIP of just one file TECOD.BAS (or maybe TECOD5.BAS), judging by the compressed size TECOD.BAS V ALLBAS.ZIP. It turned out that if I started with this, I wouldn't have to wait 23 minutes:

$ time echo "TECOD5.BAS" | perl maken.pl

TECOD5.BAS / hexname-41544.txt

bkcrack 1.7.0 - 2024-05-26

[18:14:51] Z reduction using 6 bytes of known plaintext

100.0 % (6 / 6)

[18:14:51] Attack on 880113 Z values at index 33

Keys: 98e0f009 48a0b11a c70f8499

2.4 % (20737 / 880113)

Found a solution. Stopping.

You may resume the attack with the option: --continue-attack 20737

[18:15:29] Keys

98e0f009 48a0b11a c70f8499



real	0m38.152s

user	4m35.318s

sys 0m0.897s

Given the correct plaintext, the known plaintext attack on ZipCrypto is fast. If you ever have to do something like this, it's worth spending time thinking about plaintext. In particular, files marked as

Store

in a ZIP file since they are uncompressed and their contents may be easier to predict (instead of having to find the original file and compress it to match what's in the ZIP).

Running the code

I compiled two programs and ran them in DOSBox. First (

RANDOM.BAS

) was used to create disks with random numbers, which were used as a one-time cipher, and the second (

TECOD.BAS

) was used to encrypt and decrypt messages sent by e-mail. The compiled code and generated executables can be found in

GitHub

.

To compile, it was enough to run the PowerBASIC compiler as follows:

C:\>EXE\PBC TECOD.BAS PowerBASIC Compiler Version 3.00b Copyright (c) 1989-1993 by Robert S. Zale Spectra Publishing, Sunnyvale, CA, USA C:\TECOD.BAS 2575 statements, 2329 lines Compile time: 00:12.0 Compilation speed: 12600 stmts/minute 45984 bytes code, 4880 bytes data, 2048 bytes stack Segments(1): 46k C:\>EXE\PBC RANDOM.BAS PowerBASIC Compiler Version 3.00b Copyright (c) 1989-1993 by Robert S. Zale Spectra Publishing, Sunnyvale, CA, USA C:\RANDOM.BAS 2194 statements, 1940 lines Compile time: 00:10.1 Compilation speed: 12600 stmts/minute 33328 bytes code, 4704 bytes data, 3072 bytes stack Segments(1): 34k C:\>

The first step is to create random data on disk that will be used as a one-time cipher. RANDOM.EXE uses three randomness generation algorithms (one of which uses a user-entered random key).

Encryption and decryption are performed through TECOD.EXE, which is password protected.

Although the password is built into the program and is quite simple, Tim Jenkin obfuscated it as follows:

DIM PW$(PL)
PW$(9)=CHR$(66):PW$(4)=CHR$(66):PW$(1)=CHR$(84):PW$(5)=CHR$(79):PW$(2) = CHR$(73)
PW$(3)=CHR$(77):PW$(6)=CHR$(66):PW$(8)=CHR$(77):PW$(10)=CHR$(79):PW$(7)=CHR$(73)

In this particular version of the program, the main menu is accessed after entering the TIMBOBIMBO password. It is worth noting that each version of these programs was distributed to different ANC members and had different passwords.

If you want to run these programs yourself, you can use

management

.

Here are screenshots from three short videos demonstrating the creation of random data in RANDATA.1 for the key using RANDOM.EXE and then encrypting the message saved in PLAIN.TXT on the RAM disk (all cryptographic operations had to occur on the RAM disk), which was converted to PLAIN.BIN (and vice versa). The videos themselves can be viewed at original articles.

Generating random data to use as an encryption key

File encryption

Here the programs (TECOD.EXE/TECOD.CNF) are on floppy disk A:, the data disk (containing the key file created above) is on disk B:; There is also a RAM disk for R:. For this to work, the RANDATA.1 file created in the previous step must be renamed SNUM.

File decryption

Here the programs (TECOD.EXE/TECOD.CNF) are on floppy disk A:, the data disk (containing the key file created above) is on B:; There is also a RAM disk for R:. The RANDATA.1 file should be named RNUM on B:.

There are many more interesting details about how these programs work that deserve a separate long post. For example, key material is destroyed after use, and the RANDOM.EXE program can create randomness in various ways; there is also code to check the distribution of the generated random bytes. When performing all cryptographic operations, the emphasis is on using the RAM disk.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *