/ notes.org
notes.org
1 * diff between original and backdoored 2 3 #+BEGIN_EXAMPLE 4 radiff2 des-variant/ROM.bin ROM.BIN ──(Tue,Jun14)─┘ 5 0x00000242 ab => 12 0x00000242 6 0x00001b44 67 => 6f 0x00001b44 7 0x00001b79 b1 => f5 0x00001b79 8 0x00001bc5 67 => 6f 0x00001bc5 9 0x00001bec b1 => f5 0x00001bec 10 0x00001c5d c3e4f52df52ef52f800be0a3 => 747fc0e07441c0e0c3e4f52d 0x00001c5d 11 0x00001c6a 2de0a3f52ee0f52f5005902c4d80039072d7792de493b93000500167f7a309b935f27935e493f7a309b93cf8121cc0902c5c792d7835e493c7f6a30908b83cf6121cc0753f2d22a93f67053fb93406121cc0753f2d22c0e0c082c083852d25852e26852f2785302885312985322a85332b85342ca26113a25913a25113a24913a24113a23913a23113a22913f531a26313a25b13a25313a24b13a24313a23b13a23313a22b13f532a26513a25d13a25513a24d13a24513a23d13a2 12 187 => 2ef52f800fc083c082e0a3f52de0a3f52ee0f52f5005902c4d80039072d7792de493b93000500167f7a309b935f27935e493f7a309b93cf8907f41782de6f0a308b835f9121d04902c5c792d7835e493c7f6a30908b83cf6e493f7907f41782de6f0a308b835f9121d04d082d083e0f525a3e0f526a3e0f527907f46e525f0a3e526f0a3e527f0753f2d22a93f67053fb93406121d04753f2d22c0e0c082c083c000907f41782d800dc0e0c082c083c000907f447830e0f6a308b8 0x00001c6a 13 14 one byte (0x35) same 15 16 0x00001d26 13a22d13f533a26713a25f13a25713a24f13a24713a23f13a23713a22f13f534a26013a25813a25013a24813a24013a23813a23013a22813f52d 17 58 => f97808e52e653213e52d6531137934c719b92cfbd8ed907f41782de6f0a308b835f9852d25852e26852f2785302885312985322a85332b85342c 0x00001d26 18 0x00001d61 62 => 32 0x00001d61 19 0x00001d64 5a => 45 0x00001d64 20 0x00001d67 52 => 67 0x00001d67 21 0x00001d6a 4a => 56 0x00001d6a 22 0x00001d6d 42 => 2e 0x00001d6d 23 0x00001d70 3a => 4f 0x00001d70 24 0x00001d73 32 => 5c 0x00001d73 25 0x00001d76 2a => 3d 0x00001d76 26 0x00001d79 2e => 31 0x00001d79 27 0x00001d7b 64 => 2a 0x00001d7b 28 0x00001d7e 5c => 64 0x00001d7e 29 0x00001d81 54 => 3e 0x00001d81 30 0x00001d84 4c => 37 0x00001d84 31 0x00001d87 44 => 52 0x00001d87 32 0x00001d8a 3c => 46 0x00001d8a 33 0x00001d8d 34 => 4a 0x00001d8d 34 0x00001d90 2c => 5d 0x00001d90 35 0x00001d93 2f => 32 0x00001d93 36 0x00001d95 66 => 39 0x00001d95 37 0x00001d98 5e => 28 0x00001d98 38 0x00001d9b 56 => 59 0x00001d9b 39 0x00001da1 46 => 44 0x00001da1 40 0x00001da4 3e => 34 0x00001da4 41 0x00001da7 36 => 62 0x00001da7 42 0x00001daa 2e => 50 0x00001daa 43 0x00001dad 307910e92403837012803d00010101010101000101010101010000e538a2e4e53b13f53be53a 44 38 => 33a25313a24813a23f13a24713a26013a23113a22c13a25e13f534a23b13a25713a25813a22d 0x00001dad 45 0x00001dd4 f53ae53913f539e53813f538e53713f537e536 46 19 => a26613a24113a23513a24c13f52da23813a254 0x00001dd4 47 0x00001de8 f536e53513f535e53892e3f538e538 48 15 => a24d13a25b13a23013a26113a22f13 0x00001de8 49 0x00001df8 e4e53b13f53be53a13f53ae53913f539e538 50 18 => 4213f52ea24913a25a13a23c13a22b13a251 0x00001df8 51 0x00001e0b f538e53713f537e53613f536e53513f535e53892e3f538e535 52 25 => a23313a24313a26513f52fa26313a23a13a25f13a23613a24b 0x00001e0b 53 0x00001e25 922c => a229 0x00001e25 54 0x00001e28 9245 => a240 0x00001e28 55 0x00001e2b 9230 => a255 0x00001e2b 56 0x00001e2e 923b13922d13923313924113923de5361313923513922a13923a13924413 57 30 => f530780875259c752602302f037526057935e538a2e4923fa23fe713f709 0x00001e2e 58 0x00001e4d 28139232139240e537139229131392391392431392341313923813922be5381313923c13924213923113926413925013924a139265e53913925413925c1313926313924b1313925a13 59 73 => 3fb93cf5e538a23f92e3f538d526e2e52523f525907f417927e0f7c526f0a309b92df6e0c526f0a3e0c526f0907f41e526f085272c85282be52a85292af529a925e53ba2e09240a2e2 0x00001e4d 60 0x00001e97 51e53a13924813 => 34a2e39242a2e5 0x00001e97 61 0x00001e9f 611313 => 36a2e6 0x00001e9f 62 0x00001ea3 5813925313 => 44e53aa2e0 0x00001ea3 63 0x00001ea9 6013924c139255e53b13925913926213925213 64 19 => 28a2e19246a2e3922aa2e49238a2e6922ca2e7 0x00001ea9 65 0x00001ebd 4913925d1313924d13 => 3ae539a2e1922ea2e2 0x00001ebd 66 0x00001ec7 5b9020c2e53033e52d336525543f93540ff525e52e13e52d1313136526543f9354f04225902102e52d33 67 42 => 3ca2e5923ee538a2e09230a2e39232a2e49241a2e69235a2e79243e537a2e19237a2e29245a2e49229a2 0x00001ec7 68 0x00001ef2 2e336527543f93540ff526e52f13e52e1313136528543f9354f04226902142e52e33e52f336529543f93540ff527 69 46 => 9247a2e7922be536a2e09239a2e2922da2e3923ba2e5922fa2e6923de535a2e1923fa2e49231a2e79233e5256229 0x00001ef2 70 0x00001f21 3013e52f131313652a543f9354f04227902182e52f33e53033652b543f93540ff528e52d13e530 71 39 => 26622ae527622be528622c8925752800752629a9268729e4a24f92e1a24e92e0b4003fe528245a 0x00001f21 72 0x00001f49 1313652c543f9354f04228a23713a22e13a23b13a23c13a24413a23313a24313a238136531c52df531a22813a23613a23e13a24113a22c13a23913a24613a231136532c52ef532a22913a22f13a23f13a23513a24713a24213a22a13a230136533c52ff533a23a13a23413a24513a22d13a23d13a23213a22b13a240136534c530f53419e96003021db0852d25852e26852f2785302885312985322a85332b85342ca24f13a22f13a25713a23713a25f13a23f13a26713a24713f52da24e13a22e13a25613a23613a25e13a23e13a26613a24613f52ea24d13a22d13a25513a23513a25d13a23d13a26513a24513f52fa24c13a22c13a25413a23413a25c13a23c13a26413a24413f530a24b13a22b13a25313a23313a25b13a23b13a26313a24313f531a24a13a22a13a25213a23213a25a13a23a13a26213a24213f532a24913a22913a25113a23113a25913a23913a26113a24113f533a24813a22813a25013a23013 73 356 => f9e74001c4540ff527540c600ae527c39404f527022052e5286408245a13f9e74001c4540ff954032527f527e9030325275403440cf527022052b40147e528245a13f9e74001c4540ff5275403600ae527c39401f527022052e5270303f527e5286402245a13f9e74001c4540ff954032527f527e903032527540323234403f527022052b40243e528245a13f9e74001c4540ff527540cb40c27e5275403f527e5286404245a13f9e74001c4540ff954032527f527e9030325275403f527022052e5272404f527022052e528245a13f9e74001c4540ff5275403b4032ae527540c0303f527e5286401245a13f9e74001c4540ff954032527f527e90303252754032323f52780020527e528245a13f9e74008540ff7e527c4800554f0f7e52747f70528e52854036009e5292323f529021f380526a926b92d028003021f36e52dc532c52ec52fc534c533c531c530f52de535a2e09231a2e39233a2e69235e538a2e29234 0x00001f49 74 0x000020ae 5813a23813 => e59237e539 0x000020ae 75 0x000020b4 6013a24013f534d083d082d0e022f7029caf645b3a9c1be74639cdb4a04a8278e513df2609c578d1b36e218d5ef0c0bf35daf7c269052e51 76 56 => e49230a2e79232e53ba2e19236e526792d13c75001c4c709b935f6902102792de7540f93540fc7c4540f9354f047f70974102582f582e435 0x000020b4 77 0x000020ed ec1b28dc76bf13066d44f99aa0e2845d37784ea19be55b88fd0631ddaa799213c49fec2417b0664b886cdf3245c709ae735ab0f12ebbc824926c56833dd00b4aa706b17f441ef5e12ff2895deaa96037dcc51e9873349201ef9e457b8652f8cc236d3ea7d08374ba 78 104 => f583b935e2d8028003021e35d000d083d082d0e022f4af8ad13b02e820cd65961c47b3795e188be3ae7d4a94df6930bc56f50721c2bd729c59ae17f36124c840dfe68a350b274d56c891b37084f5efd2ae3a1c0b69479f805c0a68a1ebb92d75f31e32d6c4b3aeed 0x000020ed 79 0x00002156 451be0bcf8ad2f5a16c1d967572d6ad6e2980c652443bf809bf4c11afdc1807f3ea7d902433e75e9a85b16bc 80 44 => 91d438266ac0fb75825f4c175927164ddbef049cf0b862ce3aa17385185d476ec5a09bfa32e38c01df7429b6 0x00002156 81 0x000021c1 d3 => 82 0x000021c1 82 0x00002364 67 => 6f 0x00002364 83 0x0000236a b1 => f5 0x0000236a 84 0x0000247c b1 => f5 0x0000247c 85 0x000025b5 1cc0 => 1d13 0x000025b5 86 0x000025d8 67 => 6f 0x000025d8 87 0x0000261d b1 => f5 0x0000261d 88 0x00002733 b1 => f5 0x00002733 89 90 #+END_EXAMPLE 91 92 one value at 0x242 changed from 0xAB to 0x12 93 94 this is in this function: 95 96 #+begin_SRC c 97 char FUN_CODE_0241(char *param_1,char param_2) { 98 char cVar1 = 0x12; 99 if ((char)((ushort)param_1 >> 8) == 0x40) { 100 return 0x40; 101 } 102 do { 103 cVar1 += *param_1++; 104 } while (param_2 != (char)((ushort)param_1 >> 8)); 105 return cVar1 + -1; 106 } 107 #+END_SRC 108 109 this looks like a checksum function? the one that returns the same 110 output for both firmwares? 111 112 the blob that changed is between 1c5d - 2181 113 114 there is one changed byte at 21c1 which is at the end of an unknown 115 section. quite outside of the main blob. 116 117 all other diffs are calls inside the main blob, which makes sense, 118 that in the des version functions were starting at different 119 addresses. targets of these calls are: 120 - 5 times: 1c6f (parametric entry) 121 - 7 times: 1cf5 (crypt_byte) 122 - once 1d13 (sbt_short) 123 124 calls to 1c6f always are followed by calls to 1cf5, however there is 125 two calls to 1cf5 where no preceeding 1c6f call is nearby. 126 127 1c5d set_key() calls prepare(0x7f41, 0) called from .1aad. 128 is used for calculating the 4 char key ID (15xA == JJDI) 129 zeroes 0x2d-0x2f - which seems to be the "nonce" 130 pushes 0x7f41 to the stack before joining with parametric_entry 131 1c6f parametric_entry(input, flag) calls prepare(input, flag); called from 1b42 1bc3 2362 25d6 132 depending on the flag, it either selects a 15 char password 133 from 0x72d7, or a fixed one from 0x2c4d ("2V58RGKLXN49TKD") 134 1cf5 crypt_byte called from 1b77 1bea 2368 247a 261b 2731 135 136 1c7e prepare() does some magic, calls sbt_full() 2x 137 1d04 sbt_full called from prepare 2x and from crypt_byte 138 1d13 sbt_short called from 25b4 139 140 in same fn: p_e xmsf xmsf 141 1aed 1b42 1b77 called from a switch(acc) case 0x1f !!! decrypt !!! 142 1ba5 1bc3 1bea called from a switch(acc) case 0x9f (assume 0x80 is shift key?) !!! encrypt !!! 143 22f0 2362 2368 247a (not called from anywhere?) 144 259c 25d6 261b (called from two locs, one is the fn below) 145 267e 2731(calls fn containing prev line before) 146 147 * decompiled 148 149 by hand and verified 150 151 1aed - 2182 152 153 2362 - 2563 154 259c - 2641 155 279f - 27d4 156 2807 - 2862 157 2beb - 2c1e 158 159 * fn at 1cf5 160 161 original assembly: 162 #+begin_src asm 163 ************************************************************** 164 * * 165 * FUNCTION * 166 ************************************************************** 167 undefined __stdcall FUN_CODE_1cf5(byte param_1) 168 undefined ACC:1 <RETURN> 169 byte ACC:1 param_1 170 FUN_CODE_1cf5 XREF[6]: CODE:1b77(c), CODE:1bea(c), 171 CODE:2368(c), CODE:247a(c), 172 FUN_CODE_259c:261b(c), 173 FUN_CODE_2677:2731(c) 174 CODE:1cf5 a9 3f MOV R1,DAT_INTMEM_3f = ?? 175 CODE:1cf7 67 XRL A,@R1 176 CODE:1cf8 05 3f INC DAT_INTMEM_3f = ?? 177 CODE:1cfa b9 34 06 CJNE R1,#0x34,LAB_CODE_1d03 178 CODE:1cfd 12 1d 04 LCALL FUN_CODE_1d04 undefined FUN_CODE_1d04(undefine 179 LAB_CODE_1d03 XREF[1]: CODE:1cfa(j) 180 CODE:1d03 22 RET 181 #+end_src 182 183 My interpretation: 184 #+begin_src c 185 byte INTMEM[256]; 186 187 byte xor_maybe_1d04(byte res) { 188 byte r1 = INTMEM[0x3f]; 189 res ^= INTMEM[r1]; 190 INTMEM[0x3f]++; 191 if(r1 == 0x34) { 192 fn_1d04(res); 193 INTMEM[0x3f]=0x2d; 194 } 195 return res; 196 } 197 #+end_src 198 Interestingly ghidra decompiles this differently 199 #+begin_src c 200 void FUN_CODE_1cf5(byte param_1) { 201 byte bVar1; 202 byte *pbVar2; 203 204 pbVar2 = DAT_INTMEM_3f; 205 bVar1 = *DAT_INTMEM_3f; 206 DAT_INTMEM_3f = DAT_INTMEM_3f + 1; 207 if (pbVar2 == &DAT_INTMEM_34) { 208 FUN_CODE_1d04(param_1 ^ bVar1); 209 DAT_INTMEM_3f = &DAT_INTMEM_2d; 210 } 211 return; 212 } 213 #+end_src 214 * fn at 2cd1 215 216 looks like some kind of virtual machine? 217 the opcodes seem to have the following structure 218 0x80 is end of "program" 219 if top bit is set, then there is no "param", and bottom nibble contains the offset in the jmptbl 220 if not, copy 4 byte param from 0x7fxx (where xx is derived from low 4 bits of opcode) to intmem 0x2e 221 top for bits in opcode is the address in the jumptable for the op 222 223 0x2a seems to be the 32bit Accumulator, 224 0x2e the 32bit B register. 225 0x25 seems to be treated like a flag register, where 226 .0 is the sign bit 227 .1 is for zero (Z) 228 .2 is for signed overflow(OV) 229 0x32-33 seems to be the IP/PC 230 231 void fn2cd1(uint16_t sp) { 232 *((uint16*) INTMEM + 32) = *((uint16_t*) (INTMEM + sp)); 233 uint16_t ptr = sp; 234 uint8_t tmp = PROGMEM[ptr++]; 235 *((uint16*) INTMEM + 32) = ptr; 236 if(tmp & 0x80) { 237 tmp &= 7f; // clear top bit since it was a JBC opcode 238 // continue at 2d02 239 if(tmp == 0) return; // to one byte after call to this fn 240 // all this does if after the call is 0x80 241 // is to set INTMEM[32] to the address of the 0x80 242 tmp >>= (tmp >> 1) | (tmp << 7); 243 } else { 244 uint8_t tmp1 = tmp & 0xf; 245 tmp1 = (tmp1 >> 2) | (tmp1 << 6); 246 ptr = (0x7f << 8) | tmp1; 247 memcpy(INTMEM + 0x2e; EXTMEM + ptr; 4); 248 249 tmp = (tmp << 4) | (tmp >> 4); 250 tmp = ((tmp >> 1) | (tmp << 7)) & 0x1e; 251 } 252 253 tmp1 = tmp + 0xa; 254 // push 0x2cd5; the start of this function - the pop into intmem+32 255 // push table[tmp1] \ might be -1 and 0 the next. 256 // push table[tmp1+1] / 257 } 258 259 the vm sub op at 2dc8 essentially executes 260 a = ((a*b) >> 16) & 0xffffffff; 261 where a and b are 32bit, the result of the multiplication is 64, 262 and thus the result is the middle 32 bits of the multiplication. 263 264 * printing strings 265 266 lcall puts_and_jump() 267 string terminated by 0x80 bit 268 then jumps to location after end of string 269 12 05 3e is the prefix (call to puts_and_jmp) to each string 270 271 asm code looks like this: 'call print; ds "string\0";' print() pops the return address for the string, prints it, then jumps to the address after the string. ghidra: "Flow Override: CALL_RETURN (CALL_TERMINATOR)" - any idea how to fix the flow? 272 273 * deleted message 274 275 0x23 xx 0xfe 0xff 276 xx possibly message id 1-9 277 278 if xx == 0 then clear message is 279 280 0xfe 0xff 281 282 at wherever (BANK3_R2 << 8 | BANK3_R3) points (INTMEM[0x19:0x1a]) 283 284 * test vectors 285 286 (truncated) HELLO WORLD -> BAMLK GAFFJ EDBCP 287 setting the Nonce to BAMLK and encrypting "HELLO WORLD" gives this 288 BAMLK GAFFJ EOBCP EEIMP CDAFP 289 290 NAVEL PLUIS 291 (truncated) HCAMM MBKJO DGCNC 292 (truncated) EGLLA IKMHG PHHJL 293 LEEIC BITKY DBCFE DPKLB ECILE 294 JDMNJ REJHP CPBLO JPJDD BEDNG 295 296 * key strength 297 - the key entered on the console is 15 chars long, 298 - and each char can be one of 39 values (a-z0-9.,- ) 299 - total key entropy: log(39**15,2) = 79.28103328293373 300 301 * output 302 303 - one iteration of the sbt is an 8 byte cipherstream 304 - of which the top 2 bits of each byte are discarded during the 305 XORing over the plaintext 306 - each 8 chars of plaintext are thus xored with 48bit of keystream 307 - the first 5 bytes of the keystream are leaked via the nonce, see 308 next section 309 310 * nonces? 311 312 only the first 3 letters are used as nonce, the last two are not used 313 for anything.. and only the bottom nibble of the bytes are used for 314 the "nonce" 315 316 12 bit nonce - birthday collision 50% at 64 messages 317 318 the nonces are sampled from the timer, which if no interrupt happens 319 means that each value is increased by 11 - also these 5 bytes are 320 xored with the first 5 bytes of the previous encryptions first 321 cipherblock - and thus can potentially leak those - but! 322 - only the bottom 4 bits of the cipherblock for each byte is leaked 323 - this was already like this in the non-backdoored version. - was it really? 324 325 example nonces - generated by a real device: 326 327 BAMLK 328 HCAMM 329 EGLLA 330 LEEIC 331 JDMNJ 332 333 see this from the reimplementation: 334 #+BEGIN_SRC c 335 uint8_t nonce[5]; 336 uint16_t dptr = 0; 337 338 for(int i = 5; i>0; i--, dptr++) { 339 tmp = i*11; //TL0; 340 tmp = (nonce[dptr] ^ tmp) & 0xf; 341 #+END_SRC 342 here we xor with the previous cipherblock 5 bytes... 343 #+BEGIN_SRC c 344 tmp = tmp + 1; 345 nonce[dptr] = tmp; 346 //printf("%c", 0x40|tmp); //putc_maybe_print(tmp,skip_print); 347 output[optr++]=0x40|tmp; 348 } 349 //printf(" "); //putc_maybe_print(' ',skip_print); 350 output[optr++]=' '; 351 parametric_entry(nonce,key); 352 #+END_SRC 353 here we initialize the state and generate the 1st cipherblock 354 #+BEGIN_SRC c 355 //copy result of parametric_entry to 0x72d2 356 memcpy(nonce, cipherblock, 5); //1bc6..1bcf 357 #+END_SRC 358 in the last line we copy the cipherblock 5 bytes to the nonce, which 359 will be used in line 6 of the example 360 361 trying to figure out from the testvector nonces if TL0 actually always 362 increases by 11, but it seems to be rather 15 363 364 #+BEGIN_SRC c 365 uint8_t key[15]="\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"; 366 367 uint8_t nonce[5][5]={{2, 1, 13, 12, 11}, // BAMLK 368 {8, 3, 1, 13, 13}, // HCAMM 369 {5, 7, 12, 12, 1}, // EGLLA 370 {12, 5, 5, 9, 3}, // LEEIC 371 {10, 4, 13, 14, 10}};// JDMNJ 372 for(int n = 0; n<4;n++) { 373 parametric_entry(nonce[n],key); 374 for(int i=0;i<5;i++) { 375 fprintf(stderr, "%02x ", ((nonce[n+1][i]-1) ^ crypt_byte(0)) & 0xf); 376 } 377 fprintf(stderr,"\n"); 378 } 379 #+END_SRC 380 381 382 * 1aed - decrypt 383 384 checks if what ever intmem[42:43] points to at is 385 5 letter codes seperated by spaces and terminated by \xfe. 386 if so, uses the first 5 letter block with 387 parametric_entry() and then does something weird with each 388 remaining letter block with bitwise manipulations together 389 with intmem[0x4a:0x4c] and calls crypt byte on the result 390 of the manipulation. 391 392 #+BEGIN_SRC c 393 uint8_t r6, tmp, r2, r3; 394 uint8_t tbit, CY; 395 uint16_t dptr = INTMEM[42:43]; 396 uint8_t tmp; 397 do { 398 for(int i=6;i>0;i--) { 399 tmp = EXTMEM[dptr]; 400 if(tmp == 0xfe) continue; 401 dptr++; 402 if((i==1 && tmp & 0x80) || tmp!=' ') { 403 INTMEM[44:45] = dptr; 404 printf("ERROR IN TEXT, PRESS LEFT ARROW!"); 405 return; 406 } 407 } 408 if(EXTMEM[dptr]!=0xfe) continue; 409 parametric_entry(INTMEM[42:43],0); 410 r6=0; 411 dptr = INTMEM[42:43] + 6; 412 do { 413 uint8_t r0 = 0x4a; 414 for(uint8_t r2 = 5; r2>0; r2--) { 415 tmp = EXTMEM[dptr]; // 1b58 416 CY=tmp<0xfe; // set carry due to CJNE at 1b59 417 if(tmp!=0xfe) dptr++; 418 tmp--; // 1b5f dec a 419 tmp = (tmp << 4) | (tmp >> 4); // 1b60 swap a 420 for(r3 = 4;r3>0;r3--) { 421 // 1b61 rlc a 422 tbit=CY; 423 CY=tmp & 0x80; 424 tmp=(tmp<<1) | tbit; 425 // 1b62 xchg A, INTMEM[r0] 426 uint8_t tmp1 = tmp; 427 tmp=INTMEM[r0]; 428 INTMEM[r0]=tmp1; 429 // 1b63 rrc a 430 tbit = CY; 431 CY = tmp & 1; 432 tmp = tbit | (tmp >> 1); 433 // 1b64 xchg a, intmem[r0] 434 tmp1 = tmp; 435 tmp=INTMEM[r0]; 436 INTMEM[r0]=tmp1; 437 r0++; 438 CY=r0<0x4d; 439 if(r0==0x4d) r0=0x4a; 440 } 441 } 442 for(r0 = 0x4a;r0!=0x4d;r0++) { 443 tmp = INTMEM[r0]; // 1b71 444 CY=r0<0x4c; 445 if(r0==0x4c) { 446 // 1b75 rrc a 447 tbit=CY 448 CY=tmp&1; 449 tmp = (tbit << 7) | (tmp >> 1); 450 } 451 452 // 1b76 rrc a 453 tbit=CY 454 CY=tmp&1; 455 tmp = (tbit << 7) | (tmp >> 1); 456 457 tmp = crypt_byte(tmp); 458 459 tmp &= 0x3f; // 1b7a 460 putc(tmp); // really putc_maybe_print() 461 } 462 } 463 r6++; 464 if(((r6 & 3)==0) && (r5!=0)) get_keypress(); // r5 == skip_print 465 466 // 1b91.. 467 } while (EXTMEM[dptr++]!=0xfe && EXTMEM[dptr]!=' ' && EXTMEM[dptr]!=0xfe); 468 if(r5!=0) { 469 print_crlf(); 470 } 471 return 472 #+END_SRC 473 474 ** what is the sketchy part doing? 475 476 see also sketchy.py 477 478 tmp CY 0x4a 0x4b 0x4c 479 abcd efgh 1 ABCD EFGH 0123 4567 qrst uvwx 480 efgh abcd 1 ABCD EFGH 0123 4567 qrst uvwx // swap a 481 fgha bcd1 e ABCD EFGH 0123 4567 qrst uvwx // rlc a 482 ABCD EFGH e fgha bcd1 0123 4567 qrst uvwx // XCHG a, @r0 483 eABC DEFG H fgha bcd1 0123 4567 qrst uvwx // rrc a 484 fgha bcd1 H eABC DEFG 0123 4567 qrst uvwx // xchg a, @r0++ 485 // loop 486 ghab cd1H f eABC DEFG 0123 4567 qrst uvwx // rlc a 487 0123 4567 f eABC DEFG ghab cd1H qrst uvwx // xchg a,@rc0 488 f012 3456 7 eABC DEFG ghab cd1H qrst uvwx // rrc a 489 ghab cd1H 7 eABC DEFG f012 3456 qrst uvwx // xchg a,@r0++ 490 // loop 491 habc d1H7 g eABC DEFG f012 3456 qrst uvwx // rlc a 492 qrst uvwx g eABC DEFG f012 3456 habc d1H7 // xchg a,@r0 493 gqrs tuvw x eABC DEFG f012 3456 habc d1H7 // rrc a 494 habc d1H7 x eABC DEFG f012 3456 gqrs tuvw // xchg a,@r0++ 495 // loop, r0=0x4a 496 abcd 1H7x h eABC DEFG f012 3456 gqrs tuvw // rlc a 497 eABC DEFG h abcd 1H7x f012 3456 gqrs tuvw // xchg a,@r0 498 heAB CDEF G abcd 1H7x f012 3456 gqrs tuvw // rrc a 499 abcd 1H7x G heAB CDEF f012 3456 gqrs tuvw // xchg a,@r0++ 500 501 * addresses in external ram 502 503 e0..ff used in putc 504 505 6000 506 507 6800 508 6802,04 both are uint16_t 509 510 7000 511 7100 512 7145 RW 513 7155 =55 514 515 72c9,a 516 517 72d7 contains the 15 char password used at least for the key id calculation 518 519 72f9 520 730e 521 522 730a,d possibly keyboard related? 523 524 8400 - used in int1 handler 525 8402 526 8404-7 527 840a 528 840e 529 8410-19 (ff95ff8f8f8f2525) 530 531 * emulators 532 there is two emulators: 533 - mcu.py 534 - emu8051-cli 535 both seem to have bugs, apparently SUBB is confusing to implement correctly 536 emu-0x3102.py uses mcu, ./emu8051-3102.py uses the binary emulators 537 run both, and diff the output. after SUBB the OV flag differs in both outputs 538 539 540 * ctrlvar changes over 8 rounds 541 542 1 ['abcdefgh', 'ijklmnop', 'qrstuvwx', 'yzAB CDEF', 'GHIJKLMN', 'OPQRSTUV', 'WXYZ0123'] 543 0 ['xyzABabc', 'defghijk', 'lmnopqrs', 'tuvw Z012', '3CDEFGHI', 'JKLMNOPQ', 'RSTUVWXY'] 544 0 ['vwxyzABa', 'bcdefghi', 'jklmnopq', 'rstu XYZ0', '123CDEFG', 'HIJKLMNO', 'PQRSTUVW'] 545 1 ['tuvwxyzA', 'Babcdefg', 'hijklmno', 'pqrs VWXY', 'Z0123CDE', 'FGHIJKLM', 'NOPQRSTU'] 546 1 ['opqrstuv', 'wxyzABab', 'cdefghij', 'klmn QRST', 'UVWXYZ01', '23CDEFGH', 'IJKLMNOP'] 547 1 ['jklmnopq', 'rstuvwxy', 'zABabcde', 'fghi LMNO', 'PQRSTUVW', 'XYZ0123C', 'DEFGHIJK'] 548 0 ['efghijkl', 'mnopqrst', 'uvwxyzAB', 'abcd GHIJ', 'KLMNOPQR', 'STUVWXYZ', '0123CDEF'] 549 0 ['cdefghij', 'klmnopqr', 'stuvwxyz', 'ABab EFGH', 'IJKLMNOP', 'QRSTUVWX', 'YZ0123CD'] 550 1 ['abcdefgh', 'ijklmnop', 'qrstuvwx', 'yzAB CDEF', 'GHIJKLMN', 'OPQRSTUV', 'WXYZ0123'] 551 552 * sbt data flow 553 554 0. input: state, message_key 555 1. state = lfsr(64) 556 1.a output state state is fully known 557 2. cipherblock = fix_bit_perm(state) cipherblock is fully known 558 3. iterate 8 times 559 a rotate right both 28b halves of the message key by [5, 2, 2, 5, 5, 5, 2, 2] 560 b ctrl_words[i:0..3] = state[3-i] ^ msgkey_bits(some permutation) message key 561 c rotate state right by one byte 562 d for each nibble of the cipherblock, modify it based on ctrl_words & cipherblock message key 563 e permute cipherblock bytes, new order: 3 4 6 7 2 1 5 564 f nibble swap cipherblock bytes if bits 26, 54, 1, 29, 4, 32, 7, 35 of message key are set message key 565 g SBOX each cipherblock nibble 566 4. output: cipherblock