The decryption algorithm, graphically

The decryption algorithm, in Python

# # First permutation. Generated sequence is: # [ 1, 4, 7, 2, 5, 0, 3, 6 ] Permutation_A = [ (((13 - pos) * 5) % 8) for pos in range(8) ] # # Second permutation. Generated sequence is: # [ 2, 7, 4, 1, 6, 3, 0, 5 ] Permutation_B = [ (((7 - pos) * 3 + 5) % 8) for pos in range(8) ] def Permute(byte, table): val = 0 for pos in range(8): if byte & (1 << pos): val |= (1 << table[pos]) return val def DecryptBlock(block): if len(block) != 3: raise ValueError("Bad block size. Must be three bytes") # Convert bytes to numbers (a, b, c) = [ ord(byte) for byte in block ] # Permute the middle byte b = Permute(b, Permutation_A) # Pack the three 8-bit bytes into two 12-bit messages ciphertext_msg1 = ((b & 0x0f) << 8) | ((a & 0xff) ) ciphertext_msg2 = ((c & 0xff) << 4) | ((b & 0xf0) >> 4) # RSA decrypt the two 12-bit messages plaintext_msg1 = pow(ciphertext_msg1, 11, 4097) plaintext_msg2 = pow(ciphertext_msg2, 11, 4097) # Unpack the two 12-bit messages into three 8-bit bytes d = ((plaintext_msg1 & 0xff) ) e = ((plaintext_msg1 & 0xf00) >> 8) | ((plaintext_msg2 & 0x00f) << 4) f = ((plaintext_msg2 & 0xff0) >> 4) # Permute all three bytes with permutation B d = Permute(d, Permutation_B) e = Permute(e, Permutation_B) f = Permute(f, Permutation_B) # Convert the bytes into characters return ''.join([chr(c) for c in (d, e, f)]) plaintext = '' for i in range(0,len(ciphertext),3): block = ciphertext[i:i+3] plaintext += DecryptBlock(block) # Print the plaintext, converting all carriage returns to newlines sys.stdout.write(plaintext.replace('\r', '\n'))

Visual decryption of first two blocks

Snippets of the assembly code

RAM:0010906A RAM:0010906A ; =============== S U B R O U T I N E ======================================= RAM:0010906A RAM:0010906A RAM:0010906A fUN_HAPPEN_IN: ; DATA XREF: RAM:pfUN_HAPPEN_INvo RAM:0010906A ; RAM:0031B468vo RAM:0010906A RAM:0010906A ; FUNCTION CHUNK AT RAM:0037F94E SIZE 00000006 BYTES RAM:0010906A RAM:0010906A jsr CheckThreeArgsAvailable-A5_WORLD(a5) RAM:0010906E move.l $C(a6),d7 RAM:00109072 movea.l pvX1,a0 RAM:00109076 jsr BindLocalVariable-A5_WORLD(a5) RAM:0010907A move.l $14(a6),d7 RAM:0010907E movea.l pvY1,a0 RAM:00109082 jsr BindLocalVariable-A5_WORLD(a5) RAM:00109086 move.l $1C(a6),d7 RAM:0010908A movea.l pvZ1,a0 RAM:0010908E jsr BindLocalVariable-A5_WORLD(a5) RAM:00109092 movea.l pvX1,a0 RAM:00109096 jsr fSafePointerRetrieval-A5_WORLD(a5) RAM:0010909A move.l d7,-(a6) RAM:0010909C movea.l pvY1,a0 RAM:001090A0 jsr fSafePointerRetrieval-A5_WORLD(a5) RAM:001090A4 move.l d7,-(a6) RAM:001090A6 movea.l pvLittle,a0 RAM:001090AA jsr fSafePointerRetrieval-A5_WORLD(a5) RAM:001090AE move.l d7,-(a6) RAM:001090B0 movea.l fmod-A5_WORLD(a5),a0 RAM:001090B4 moveq #8,d6 RAM:001090B6 movea.l (a0),a1 RAM:001090B8 jsr (a1) RAM:001090BA move.l d7,-(a6) RAM:001090BC movea.l pvLot,a0 RAM:001090C0 jsr fSafePointerRetrieval-A5_WORLD(a5) RAM:001090C4 jsr f_multiply-A5_WORLD(a5) RAM:001090C8 jsr f_add-A5_WORLD(a5) RAM:001090CC move.l d7,-(a6) RAM:001090CE movea.l ppfUN_MAKE_DES,a0 RAM:001090D2 moveq #4,d6 RAM:001090D4 movea.l (a0),a1 RAM:001090D6 jsr (a1) RAM:001090D8 move.l d7,-(a6) RAM:001090DA movea.l pvLot,a0 RAM:001090DE jsr fSafePointerRetrieval-A5_WORLD(a5) RAM:001090E2 move.l d7,-(a6)