/ emu-encrypt.py
emu-encrypt.py
1 #!/usr/bin/env python3 2 3 import sys, itertools 4 from mcu import Operation, Microcontroller 5 6 getc = [ord(c) for c in reversed("5\n23\n42\n13\nY\n")] 7 8 def putc(c): 9 c = int(mcu.mem.a) 10 if c & 0x80: # unescaping in case we come from putc_raw 11 c &= 0x3f 12 c = (0x40 | c ) if c<27 else c 13 #print(f"putc({repr(chr(c))})") 14 print(chr(c), end="") 15 16 mcu = Microcontroller() 17 def run(mcu, end, trace): 18 isns = 0 19 while mcu.pc not in end: 20 isns+=1 21 op = Operation(mcu.rom[int(mcu.pc)]) 22 op.args = mcu.rom[int(mcu.pc + 1):int(mcu.pc + len(op))] 23 24 if trace: 25 print(f"{isns:5} {int(mcu.pc):04x} {str(op):<30} | " 26 f"{int(mcu.mem.a):02x} " 27 f"{int(mcu.mem.r0):02x} " 28 f"{int(mcu.mem.r1):02x} " 29 f"{int(mcu.mem.r2):02x} " 30 f"{int(mcu.mem.dptr):04x} " 31 f"{int(mcu.mem[0xd0]) & 0xfe:02x} " 32 f"{int(mcu.mem[0xd1]):02x} ", end='') 33 for i in range(23): 34 if i>0 and i % 4==0: print(" ", end='') 35 print(f"{mcu.mem._data[0x25+i]:02x}", end='') 36 print() 37 38 if op.opcode == 0x12: # lcall 39 if op.args == [0x03,0x7a]: # putc 40 putc(mcu.mem.a) 41 mcu.pc += len(op) 42 continue 43 elif op.args == [0x05,0x65]: # getc 44 if trace: 45 print("getc()") 46 mcu.pc += len(op) 47 mcu.mem.a = getc.pop() 48 continue 49 if op.opcode == 0x2: # jmp 50 if op.args == [0x03,0x7a]: # putc 51 putc(mcu.mem.a) 52 mcu._exec_34() # ret 53 continue 54 elif op.args == [0x05,0x65]: # getc 55 if trace: 56 print("getc()") 57 mcu.mem.a = getc.pop() 58 mcu._exec_34() # ret 59 continue 60 61 # catch putc if not jmp/call 62 if int(mcu.pc)==0x37a: 63 putc(mcu.mem.a) 64 mcu._exec_34() # ret 65 continue 66 67 mcu.next_cycle() 68 if trace: 69 print() 70 print("end, total insn", isns) 71 return isns 72 73 def usage(ret): 74 print("sbt encrypt") 75 print("\t-k=<15chars>\t\t - key, only A-Z0-9,.-") 76 print("\t-n=<5chars>\t\t - previous nonce, only letters") 77 print("\t-p=<text>\t\t - plaintext, only A-Z0-9,.-") 78 exit(ret) 79 80 def is_valid_str(s): 81 valid = set(c if isinstance(c,str) else chr(c) for c in itertools.chain(range(ord('A'), ord('Z')+1), range(ord('0'), ord('9')+1), [',', '.', '-', ' '])) 82 return (set(s.upper()) - valid) == set() 83 84 prev_nonce="ABCDE" 85 plaintext="HELLO WORLD" 86 key="AAAAAAAAAAAAAAA" 87 88 for arg in sys.argv[1:]: 89 if arg == '-h': 90 usage(0) 91 if arg.startswith("-k="): 92 if not is_valid_str(arg[3:]) or len(arg[3:])!=15: usage(1) 93 key=arg[3:].upper() 94 continue 95 if arg.startswith("-n="): 96 if not arg[3:].isalpha() or len(arg[3:])!=5: usage(1) 97 prev_nonce=arg[3:].upper() 98 continue 99 if arg.startswith("-p="): 100 if not is_valid_str(arg[3:]): usage(1) 101 plaintext=arg[3:].upper() 102 continue 103 104 # reset 105 mcu.reset_ram() 106 107 # load rom image 108 with open('SBT.rom','rb') as fd: 109 code = fd.read() 110 for i, b in enumerate(code): 111 mcu.rom[i] = b 112 113 # init key 114 for i, c in enumerate(key): mcu.rom[0x72d7+i] = ord(c) & 0x3f 115 mcu.pc = 0x1aad 116 steps = run(mcu, [0x1ac9], False) 117 print() 118 119 mcu.pc = 0x1ba8 # we skip the query to print the output at 1aed 120 for i,c in enumerate(plaintext + "\xfe"): 121 mcu.xmem[0x3000+i]=(ord(c) & 0x3f) if c!='\xfe' else 0xfe 122 mcu.mem[0x42]=0x30 123 mcu.mem[0x43]=0x00 124 mcu.mem.r5=1 125 126 mcu.mem[0x4a]=0x00 127 mcu.mem[0x4b]=0x00 128 mcu.mem[0x4c]=0x00 129 130 # previous nonce 131 for i,c in enumerate(prev_nonce): 132 mcu.xmem[0x72d2+i]=ord(c) & 0x3f 133 134 steps = run(mcu, [0x1c25], False) 135 print()