firmware.c
1 #include <stdint.h> 2 #include <string.h> 3 #include <stdio.h> 4 5 typedef uint8_t bool; 6 7 // Addresses 8 // 0x25 [8] copy of LFSR/cryptovariable 9 // 0x25 is set to 0x9c at the beginning of the mainloop. 10 // 0x2d [8] LFSR/crypto variable 11 // 0x35 [7] effective crypto variable 12 // 0x3f [1] index into cipherblock for next byte to xor with, 0x2c..0x34 13 // 0x7f41 [8] = cryptovariable/state 14 // 0x72d7 [15] crypto key - keyed in via keyboard 15 16 static uint8_t ctrlvar[7]; // INTMEM[0x35..0x3c] 17 static uint8_t cipherblock_idx; // INTMEM[0x3f] 18 static uint8_t cipherblock[8]; // INTMEM[0x2d..0x34] 19 static uint8_t state[8]; // EXTMEM[0x7f41..0x7f49] 20 21 uint8_t INTMEM[256] = {0}; 22 uint8_t EXTMEM[65536] = {0}; 23 uint8_t PROGMEM[32768] = {0}; 24 25 static const uint8_t fixed_key[15]="2V58RGKLXN49TKD"; // 0x2c4d 26 27 #define TRACE(pc) printf("PC: %04x ", pc); \ 28 printf(" ");\ 29 for(int iter=0;iter<8;iter++) { \ 30 if(iter>0 && iter%4==0) \ 31 printf(" "); \ 32 printf("%02x", INTMEM[0x25+iter]); } \ 33 printf(" "); \ 34 for(int iter=0;iter<8;iter++) { \ 35 if(iter>0 && iter%4==0) \ 36 printf(" "); \ 37 printf("%02x", cipherblock[iter]); } \ 38 printf(" "); \ 39 for(int iter=0;iter<7;iter++) { \ 40 if(iter>0 && iter%4==0) \ 41 printf(" "); \ 42 printf("%02x", ctrlvar[iter]); } \ 43 printf("\n"); 44 45 const uint8_t SBOX[128] = {0xF4, 0xAF, 0x8A, 0xD1, 0x3B, 0x02, 0xE8, 0x20, 46 0xCD, 0x65, 0x96, 0x1C, 0x47, 0xB3, 0x79, 0x5E, 47 0x18, 0x8B, 0xE3, 0xAE, 0x7D, 0x4A, 0x94, 0xDF, 48 0x69, 0x30, 0xBC, 0x56, 0xF5, 0x07, 0x21, 0xC2, 49 0xBD, 0x72, 0x9C, 0x59, 0xAE, 0x17, 0xF3, 0x61, 50 0x24, 0xC8, 0x40, 0xDF, 0xE6, 0x8A, 0x35, 0x0B, 51 0x27, 0x4D, 0x56, 0xC8, 0x91, 0xB3, 0x70, 0x84, 52 0xF5, 0xEF, 0xD2, 0xAE, 0x3A, 0x1C, 0x0B, 0x69, 53 0x47, 0x9F, 0x80, 0x5C, 0x0A, 0x68, 0xA1, 0xEB, 54 0xB9, 0x2D, 0x75, 0xF3, 0x1E, 0x32, 0xD6, 0xC4, 55 0xB3, 0xAE, 0xED, 0x09, 0x91, 0xD4, 0x38, 0x26, 56 0x6A, 0xC0, 0xFB, 0x75, 0x82, 0x5F, 0x4C, 0x17, 57 0x59, 0x27, 0x16, 0x4D, 0xDB, 0xEF, 0x04, 0x9C, 58 0xF0, 0xB8, 0x62, 0xCE, 0x3A, 0xA1, 0x73, 0x85, 59 0x18, 0x5D, 0x47, 0x6E, 0xC5, 0xA0, 0x9B, 0xFA, 60 0x32, 0xE3, 0x8C, 0x01, 0xDF, 0x74, 0x29, 0xB6}; 61 62 #define BITv(B,n) ((B >> n) & 1) 63 #define BYTE(B7,B6,B5,B4,B3,B2,B1,B0) ((B7 << 7) | (B6 << 6) | (B5 << 5) | (B4 << 4) | (B3 << 3) | (B2 << 2) | (B1 << 1) | B0) 64 65 static uint8_t assign_bit(const uint8_t dst, const int bit, const int pos) { 66 return (dst & ~(1U << pos)) | (bit << pos); 67 } 68 69 static uint8_t rrc(const uint8_t val, const uint8_t cf_in, uint8_t *cf_out) { 70 *cf_out = val & 1; 71 return (cf_in << 7) | (val >> 1); 72 } 73 74 75 76 /*?*/ void sbt(uint8_t cb_start) { // fn_1d20 77 // main function doing the dance called only from sbt_full() and sbt_short() 78 // short: sbt(0x7f44, 0x30); 79 // full: sbt(0x7f41, 0x2d); 80 81 uint8_t cf = 0; // carry flag 82 uint8_t tmp, r1, tmp1; 83 84 // initialize LFSR 85 // workbuf, state 86 memcpy(cipherblock + cb_start, state + cb_start, 8-cb_start); // 1d27 87 TRACE(0x1d27); 88 89 // step 1 - initial fill - LFSR (1 + x^32 + x^63) 64 steps 90 // workbuf 91 for(int i = 0; i<8; i++) { 92 tmp = (cipherblock[0] ^ cipherblock[4]) >> 1 | (cipherblock[1] ^ cipherblock[5]) << 7; 93 for(int j = 7; j >= 0; j--) { 94 tmp1 = cipherblock[j]; 95 cipherblock[j] = tmp; 96 tmp = tmp1; 97 } 98 } // 1d3c 99 TRACE(0x1d3c); 100 101 // copy back LFSRed key to extmem src. 102 // workbuf, state 103 memcpy(state, cipherblock, 8); // 1d48 104 TRACE(0x1d48); 105 106 // copy work-array to bitmapped area, as a copy from which to 107 // calculate the fixed permutation of the next step. 108 uint8_t fillcopy[8]; 109 memcpy(fillcopy, cipherblock, 8); // 1d60 110 TRACE(0x1d60); 111 112 // step 2 - fixed bit permutation 113 cipherblock[0] = BYTE(BITv(fillcopy[4],4),BITv(fillcopy[1],5),BITv(fillcopy[3],1),BITv(fillcopy[7],6),BITv(fillcopy[0],5),BITv(fillcopy[6],0),BITv(fillcopy[5],7),BITv(fillcopy[2],3)); 114 cipherblock[1] = BYTE(BITv(fillcopy[3],2),BITv(fillcopy[0],7),BITv(fillcopy[7],1),BITv(fillcopy[1],0),BITv(fillcopy[6],3),BITv(fillcopy[4],5),BITv(fillcopy[5],4),BITv(fillcopy[2],0)); 115 cipherblock[2] = BYTE(BITv(fillcopy[7],5),BITv(fillcopy[3],3),BITv(fillcopy[1],3),BITv(fillcopy[5],1),BITv(fillcopy[0],3),BITv(fillcopy[2],4),BITv(fillcopy[6],2),BITv(fillcopy[4],1)); 116 cipherblock[3] = BYTE(BITv(fillcopy[5],5),BITv(fillcopy[3],0),BITv(fillcopy[0],1),BITv(fillcopy[4],3),BITv(fillcopy[1],6),BITv(fillcopy[6],7),BITv(fillcopy[2],2),BITv(fillcopy[7],3)); 117 cipherblock[4] = BYTE(BITv(fillcopy[2],5),BITv(fillcopy[6],4),BITv(fillcopy[4],7),BITv(fillcopy[0],6),BITv(fillcopy[5],6),BITv(fillcopy[7],7),BITv(fillcopy[3],5),BITv(fillcopy[1],2)); 118 cipherblock[5] = BYTE(BITv(fillcopy[6],5),BITv(fillcopy[4],2),BITv(fillcopy[3],6),BITv(fillcopy[5],2),BITv(fillcopy[1],7),BITv(fillcopy[2],6),BITv(fillcopy[7],4),BITv(fillcopy[0],2)); 119 cipherblock[6] = BYTE(BITv(fillcopy[5],0),BITv(fillcopy[7],2),BITv(fillcopy[1],4),BITv(fillcopy[3],4),BITv(fillcopy[4],6),BITv(fillcopy[6],1),BITv(fillcopy[0],0),BITv(fillcopy[2],1)); 120 cipherblock[7] = BYTE(BITv(fillcopy[6],6),BITv(fillcopy[0],4),BITv(fillcopy[1],1),BITv(fillcopy[7],0),BITv(fillcopy[3],7),BITv(fillcopy[2],7),BITv(fillcopy[4],0),BITv(fillcopy[5],3)); 121 TRACE(0x1e30); 122 123 // 1e30 124 // main loop 125 uint8_t thingy, // wth is thingy 126 ctrlvar_iter_ctrl = 0x9c; // 1e32 127 for(int round = 0; round < 8; round++) { 128 129 // update control variable 130 for(int i=(ctrlvar_iter_ctrl & 0x80)?5:2;i!=0; i--) { // 1e35, 1e3b, 1e59 131 // ctrlvar_iter_ctrl has this binary value: 10011100 so 4x2 132 // and 4x5 iterations 133 cf = BITv(ctrlvar[3],4); // 1e44 134 TRACE(0x1e46); 135 for(int i=0; i<7; i++) { 136 ctrlvar[i] = rrc(ctrlvar[i], cf, &cf); // 1e4a 137 TRACE(0x1e4e); 138 } // 1e4e 139 TRACE(0x1e57); 140 ctrlvar[3] = assign_bit(ctrlvar[3],cf,3); // 1e57 141 } 142 // rotate ctrlvar_iter_ctrl left 143 ctrlvar_iter_ctrl = ctrlvar_iter_ctrl << 1 | ctrlvar_iter_ctrl >> 7; // 1e5c .. 1e5f 144 TRACE(0x1e61); 145 146 // 1e61 .. 1e8e 147 uint8_t nibble_swap_ctrl_words[4]; 148 for(int i=0;i<4;i++) nibble_swap_ctrl_words[i] = state[3-i]; 149 // rotate state right 8x 150 tmp = state[7]; 151 memmove(state+1,state,7); 152 state[0]=tmp; 153 154 TRACE(0x1e8e); 155 // 1f1c 156 nibble_swap_ctrl_words[0] ^= BYTE(BITv(ctrlvar[1], 5), BITv(ctrlvar[4], 1), BITv(ctrlvar[1], 2), BITv(ctrlvar[5], 6), BITv(ctrlvar[2], 7), BITv(ctrlvar[5], 3), BITv(ctrlvar[2], 4), BITv(ctrlvar[5], 0)); 157 nibble_swap_ctrl_words[1] ^= BYTE(BITv(ctrlvar[2], 1), BITv(ctrlvar[6], 5), BITv(ctrlvar[3], 6), BITv(ctrlvar[6], 2), BITv(ctrlvar[0], 7), BITv(ctrlvar[3], 3), BITv(ctrlvar[0], 4), BITv(ctrlvar[3], 0)); 158 nibble_swap_ctrl_words[2] ^= BYTE(BITv(ctrlvar[0], 1), BITv(ctrlvar[4], 5), BITv(ctrlvar[1], 6), BITv(ctrlvar[4], 2), BITv(ctrlvar[1], 3), BITv(ctrlvar[5], 7), BITv(ctrlvar[1], 0), BITv(ctrlvar[5], 4)); 159 nibble_swap_ctrl_words[3] ^= BYTE(BITv(ctrlvar[2], 5), BITv(ctrlvar[5], 1), BITv(ctrlvar[2], 2), BITv(ctrlvar[6], 6), BITv(ctrlvar[3], 7), BITv(ctrlvar[6], 3), BITv(ctrlvar[3], 4), BITv(ctrlvar[6], 0)); // 1f2c 160 TRACE(0x1f2c); 161 int nibble_swap_index = 0; 162 163 for(int i = 0; i < 4; i++) { // 1f34 164 TRACE(0x1f36); 165 uint8_t nibble_swap_ctrl = nibble_swap_ctrl_words[i]; // 1f36 166 while(1) { // really true? nah there's a break at the end, 167 // but it's not trivial to convert to for(;;) 168 // basically this loops 4 times, based on INTMEM[0x28] % 4 == 0 169 170 tmp = cipherblock[nibble_swap_index >> 1]; 171 if(!(nibble_swap_index & 1)) { 172 tmp >>= 4; 173 } 174 tmp &= 0xf; 175 thingy = tmp; 176 177 if(nibble_swap_ctrl >> 6 == 0) { 178 if((tmp & 0xc) == 0) { // 1f52 179 tmp = cipherblock[(nibble_swap_index ^ 8) >> 1]; // 1f60 .. 1f64 180 TRACE(0x1f64); 181 if(!((nibble_swap_index ^ 8) & 1)) { 182 // swap nibbles 183 TRACE(0x1f6b); 184 tmp >>= 4; // 1f6b 185 } 186 tmp &= 0xf; // 1f6c 187 188 thingy += tmp & 3; // 1f6f 189 190 thingy = ((((tmp << 6) | (tmp >> 2)) + thingy) & 3) | 0xc; // 1f78 .. 1f7e 191 TRACE(0x1f80); 192 } else { 193 TRACE(0x1f52); 194 thingy -= 4; 195 } 196 197 } else if(nibble_swap_ctrl >> 6 == 1) { 198 if((tmp & 0x3) == 0) { // 1f94 .. 1f96 199 thingy = (thingy << 6) | (thingy >> 2); // 1fa2 .. 1fa6 200 201 tmp = cipherblock[(nibble_swap_index ^ 2) >> 1]; 202 TRACE(0x1fb1); 203 if(!((nibble_swap_index ^ 2) & 1)) { 204 TRACE(0x1fb3); 205 tmp >>= 4; // 1fb3 206 } 207 TRACE(0x1fb4); 208 tmp &= 0xf; // 1fb4 209 210 thingy += tmp & 3; // 1fb7, 1fbb 211 212 tmp = ((((tmp << 6) | (tmp >> 2)) + thingy) & 3); 213 thingy = ((tmp >> 6) | (tmp << 2)) | 3; // 1fbd .. 1fc8 214 215 TRACE(0x1fca); 216 } else { 217 thingy-=1; // 1f98 .. 1f9d 218 TRACE(0x1f9f); 219 } 220 221 } else if(nibble_swap_ctrl >> 6 == 2) { 222 if((tmp & 0xc) == 0xc) { // 1fde .. 1fe0 223 TRACE(0x1fe3); 224 thingy &= 3; // 1fe3 .. 1fe7 225 226 tmp = cipherblock[(nibble_swap_index ^ 4) >> 1]; // 1fe9 .. 1ff1 227 TRACE(0x1ff1); 228 if(!((nibble_swap_index ^ 4) & 1)) { 229 TRACE(0x1ff4); 230 tmp >>= 4; // 1ff4 231 } 232 TRACE(0x1ff5); 233 tmp &= 0xf; // 1ff5 234 235 thingy += tmp & 3; // 1ff8, 1fbb 236 237 thingy = ((((tmp << 6) | (tmp >> 2)) + thingy) & 3); // 1ffe .. 2005 238 TRACE(0x2007); 239 } else { 240 thingy += 4; // 200a .. 200e 241 TRACE(0x2010); 242 } 243 244 } else { 245 if((tmp & 3) == 3) { // 2021 .. 2023 246 thingy = (thingy >> 2) & 3; // 202c 247 248 TRACE(0x202e); 249 tmp = cipherblock[(nibble_swap_index ^ 1) >> 1]; // .. 202e..2036 250 TRACE(0x2036); 251 if(!((nibble_swap_index ^ 1) & 1)) { 252 TRACE(0x2039); 253 tmp >>= 4; // 2039 254 } 255 tmp &= 0xf; // 203a 256 257 thingy += tmp & 3; // 203d, 2041 258 259 tmp = ((((tmp << 6) | (tmp >> 2)) + thingy) & 3); // 2043 .. 2048 260 261 thingy = ((tmp << 2) | (tmp >> 6)) ; // 204a .. 204c 262 TRACE(0x204e); 263 } else { 264 thingy++; 265 } 266 } 267 TRACE(0x2052); 268 r1 = nibble_swap_index >> 1; 269 tmp = cipherblock[r1]; // 2058 270 TRACE(0x2058); 271 if(!(nibble_swap_index & 1)) { 272 tmp &= 0xf; 273 cipherblock[r1] = tmp; // 205d 274 TRACE(0x205d); 275 tmp = thingy; 276 tmp = (tmp <<4) | (tmp >> 4); // 2060 277 } else { 278 TRACE(0x2063); 279 tmp &= 0xf0; // 2063 .. 280 cipherblock[r1] = tmp; 281 TRACE(0x2066); 282 tmp = thingy; // 2066 283 } 284 285 TRACE(0x2068); 286 cipherblock[r1] |= tmp; // 2068 .. 2069 287 nibble_swap_index++; 288 if((nibble_swap_index & 3) == 0) { 289 break; 290 } 291 nibble_swap_ctrl = (nibble_swap_ctrl << 2) | (nibble_swap_ctrl >> 6); // 2072 .. 2076 292 TRACE(0x2076); 293 } 294 } 295 296 TRACE(0x2087); 297 // step 6. fix byte permutation 298 tmp = cipherblock[0]; // 2087 .. 299 cipherblock[0] = cipherblock[3]; 300 cipherblock[3] = cipherblock[4]; 301 cipherblock[4] = cipherblock[6]; 302 cipherblock[6] = cipherblock[7]; 303 cipherblock[7] = cipherblock[2]; 304 cipherblock[2] = cipherblock[1]; 305 cipherblock[1] = cipherblock[5]; 306 cipherblock[5] = tmp; // .. 2097 307 308 // step 8 nibble switch 309 tmp = BYTE(BITv(ctrlvar[3], 5), BITv(ctrlvar[6], 1), BITv(ctrlvar[0], 6), BITv(ctrlvar[3], 2), 310 BITv(ctrlvar[0], 3), BITv(ctrlvar[4], 7), BITv(ctrlvar[0], 0), BITv(ctrlvar[4], 4)); 311 312 TRACE(0x20c1); 313 cf = BITv(ctrlvar[6], 1); 314 for(int i = 0; // 20c3 315 i < 8; // 20cc 316 i++) { // 20cb 317 tmp = rrc(tmp, cf, &cf); // 20c5 318 tmp1 = cipherblock[i]; 319 cipherblock[i] = tmp; 320 tmp = tmp1; 321 if(cf) { 322 // swap nibbles 323 tmp = ((tmp & 0xf) <<4) | ((tmp & 0xf0) >> 4); // 20c9 324 } 325 tmp1 = cipherblock[i]; // 326 cipherblock[i] = tmp; // 20ca 327 tmp = tmp1; // 328 TRACE(0x20cb); 329 } 330 TRACE(0x20d2); 331 // step 10 SBOXes 332 for(int i = 0; // 20d2 333 //ptr = 0x2102; // 20cf 334 // ptr = 0; // 20cf 335 i < 8; // 20ef 336 i++) { // 20e3 337 //ptr+=0x10) { // 20e4 .. 20ed 338 TRACE(0x20d4); 339 tmp1 = SBOX[(i*16) + (cipherblock[i] & 0xf)] & 0xf; // 20d4 .. 20d8 340 tmp = cipherblock[i]; 341 cipherblock[i] = tmp1; // 20da 342 TRACE(0x20db); 343 tmp = ((tmp & 0xf) <<4) | ((tmp & 0xf0) >> 4); // 20db 344 tmp &= 0xf; 345 cipherblock[i] |= (SBOX[tmp + (i*16)] & 0xf0); // 20de .. 20e2 346 TRACE(0x20e3); 347 } 348 } 349 TRACE(0x20f9); 350 } 351 352 void sbt_short(void) { // 1d13 353 // (deep) entry point 354 // called from 25b4 355 //sbt(0x7f44, 3); 356 sbt(3); 357 } 358 359 void sbt_full(void) { // 1d04 360 // called from prepare() 2x and from crypt_byte() 361 //sbt(0x7f41, 0); 362 sbt(0); 363 } 364 365 366 uint8_t crypt_byte(uint8_t res) { // 1cf5 367 // entry point 368 // called from: 1b77 1bea 2368 247a 261b 2731 369 res ^= cipherblock[/*r1*/cipherblock_idx++]; 370 cipherblock_idx++; 371 if(cipherblock_idx == 7) { 372 sbt_full(); 373 cipherblock_idx=0; 374 } 375 return res; 376 } 377 378 void sbt_init(uint8_t *output, const uint8_t *key) { 379 // only called from default_entry() and parametric_entry() 380 if(key == NULL) { 381 key = fixed_key; 382 } 383 384 // preliminary fill = key[:8] ^ intmem[0x2d:0x30] 385 //for(i=0x2d;i<0x35;i++, ptr++) { 386 for(int i=0;i<8;i++) { 387 if(i<3) { 388 cipherblock[i] ^= key[i]; // 1c91 389 } else { 390 cipherblock[i]= key[i]; 391 } 392 } // 1c98 393 394 // preliminary control (56 bits) = key[8:] 395 memcpy(ctrlvar, key+8, 7); // 1c9f 396 TRACE(0x1ca2); 397 398 // preserve preliminary fill 399 memcpy(state, cipherblock, 8); // 1cab 400 TRACE(0x1cae); 401 402 sbt_full(); 403 TRACE(0x1cb1); 404 405 // hard coded fixed fill at 0x2c5c 406 uint8_t fixed_fill[8] = { 0xf5, 0xc0, 0x7a, 0x10, 0x8a, 0xaf, 0x17, 0xcf }; 407 408 // output of sbt_full becomes control variable 409 memcpy(ctrlvar, cipherblock, 7); 410 // initial fill becomes fixed_fill 411 memcpy(cipherblock, fixed_fill, 8); // 1cbf, 1cc4 412 TRACE(0x1cc2); 413 414 // 0x7f41 also becomes fixed fill 415 memcpy(state, cipherblock, 8); 416 TRACE(0x1cd1) 417 418 sbt_full(); 419 TRACE(0x1cd4); 420 421 memcpy(INTMEM + 0x25, output,3); 422 cipherblock_idx=0; 423 memcpy(state + 5, output, 3); 424 TRACE(0x1cf4) 425 } 426 427 void default_entry(void) { // 1c5d 428 // entry point 429 // called from 1aad if (EXTMEM[0x7308] & 1) 430 // 1aad seems to print the "key: {key}" 431 // push 0x7f41 // 1c5d .. 1c63 432 memset(INTMEM+0x2d, 0, 3); // 1c67 .. 1c6b 433 sbt_init(state, PROGMEM + 0x72d7); 434 } // 1c6d 435 436 /*?*/ void parametric_entry(uint8_t *output, const uint8_t *key) { // 1c6f 437 // entry point 438 // called from 1b42, 1bc3, 2362, 25d6 439 // input is dptr, flag is passed in the carry flag of the psw 440 // push input // 1c6f .. 1c71 441 memcpy(cipherblock, output, 3); 442 sbt_init(output, key); 443 } 444 445 /* 446 * checks if what ever intmem[42:43] points to at is 5 letter codes 447 * seperated by spaces and terminated by \xfe. if so, uses the first 448 * 5 letter block with parametric_entry() and then does something 449 * weird with each remaining letter block with bitwise manipulations 450 * together with intmem[0x4a:0x4c] and calls crypt byte on the result 451 * of the manipulation. 452 */ 453 void decrypt() { 454 uint8_t r6, tmp, r2, r3; //, r5=1; 455 uint8_t tbit, CY; 456 // r5 = print_output_query(); 457 uint16_t dptr = INTMEM[42] << 8 | INTMEM[43]; 458 do { 459 for(int i=6;i>0;i--) { 460 tmp = EXTMEM[dptr]; 461 if(tmp == 0xfe) break; 462 dptr++; 463 if((i!=1 && tmp & 0x80) || tmp!=' ') { 464 INTMEM[44] = dptr >> 8; 465 INTMEM[45] = dptr & 0xff; 466 printf("ERROR IN TEXT, PRESS LEFT ARROW!"); 467 return; 468 } 469 } 470 } while(EXTMEM[dptr]!=0xfe); 471 472 parametric_entry(&EXTMEM[INTMEM[42]<<8|INTMEM[43]],0); 473 r6=0; 474 dptr = (INTMEM[42] << 8 | INTMEM[43]) + 6; 475 // see sketchy.py for how the bits of *dptr and *intmem[4a..4c] are processed before output 476 do { 477 uint8_t r0 = 0x4a; 478 for(r2 = 5; r2>0; r2--) { 479 tmp = EXTMEM[dptr]; // 1b58 480 CY=tmp<0xfe; // set carry due to CJNE at 1b59 481 if(tmp!=0xfe) dptr++; 482 tmp--; // 1b5f dec a 483 tmp = (tmp << 4) | (tmp >> 4); // 1b60 swap a 484 for(r3 = 4;r3>0;r3--) { 485 // 1b61 rlc a 486 tbit=CY; 487 CY=tmp & 0x80; 488 tmp=(tmp<<1) | tbit; 489 // 1b62 xchg A, INTMEM[r0] 490 uint8_t tmp1 = tmp; 491 tmp=INTMEM[r0]; 492 INTMEM[r0]=tmp1; 493 // 1b63 rrc a 494 tbit = CY; 495 CY = tmp & 1; 496 tmp = tbit | (tmp >> 1); 497 // 1b64 xchg a, intmem[r0] 498 tmp1 = tmp; 499 tmp=INTMEM[r0]; 500 INTMEM[r0]=tmp1; 501 r0++; 502 CY=r0<0x4d; 503 if(r0==0x4d) r0=0x4a; 504 } 505 } 506 for(r0 = 0x4a;r0!=0x4d;r0++) { 507 tmp = INTMEM[r0]; // 1b71 508 CY=r0<0x4c; 509 if(r0==0x4c) { 510 // 1b75 rrc a 511 tbit=CY; 512 CY=tmp&1; 513 tmp = (tbit << 7) | (tmp >> 1); 514 } 515 516 // 1b76 rrc a 517 tbit=CY; 518 CY=tmp&1; 519 tmp = (tbit << 7) | (tmp >> 1); 520 521 tmp = crypt_byte(tmp); 522 523 tmp &= 0x3f; // 1b7a 524 printf("%c", tmp); // really putc_maybe_print() 525 } 526 r6++; 527 //if(((r6 & 3)==0) && (r5!=0)) get_keypress(); // r5 == skip_print 528 529 // 1b91.. 530 } while (EXTMEM[dptr++]!=0xfe && EXTMEM[dptr]!=' ' && EXTMEM[dptr]!=0xfe); 531 //if(r5!=0) { 532 // print_crlf(); 533 //} 534 } 535 536 void encrypt(uint8_t *xram, uint8_t *ram) { 537 // skip_print = print_output_query(); 538 uint16_t dptr = 0x72d2; //&DAT_EXTMEM_72d2; 539 uint8_t tmp, in_PSW=0; 540 541 // get 5 values [1..16] by xoring what is in ram 542 // with the value of the 8bit reloading TL0 timer 543 // this is like a "nonce/iv" but quite predictable 544 // since this loop is static, if there are no interrupts 545 // then TL0 increases by 11 in each iteration. 546 // unless there are interrupts... 547 // see also emu-timer-1ba8.py 548 549 // the following are "nonces" from original hw 550 // BAMLK HCAMM EGLLA LEEIC JDMNJ 551 552 for(int i = 5; i>0; i--, dptr++) { 553 tmp = 19; //TL0; 554 tmp = (xram[dptr] ^ tmp) & 0xf; 555 in_PSW = (in_PSW & 0xdd) | (tmp == 0) << 1; 556 tmp = tmp + 1; 557 *xram = tmp; 558 //putc_maybe_print(tmp,skip_print); 559 } 560 //putc_maybe_print(' ',skip_print); 561 //parametric_entry(0x72d2,0); 562 563 //copy result of parametric_entry to 0x72d2 564 memcpy(xram+0x72d2, ram+0x2d, 5); //1bc6..1bcf 565 566 uint8_t tbit, CY; 567 uint8_t r6=0; 568 dptr = ram[0x42] << 8 | ram[0x43]; 569 // see sketchy.py for how the bits of *dptr and *intmem[4a..4c] are processed before ouptu 570 while(xram[dptr]!=0xfe) { 571 for(uint8_t r0 = 0x4a;r0<0x4d;r0++) { 572 tmp = xram[dptr++]; 573 if(tmp == 0xfe) { 574 tmp = 0x5f; 575 } else { 576 tmp++; 577 } 578 tmp = crypt_byte(tmp); 579 ram[r0] = tmp; 580 } 581 uint8_t r0 = 0x4a; 582 CY = 0; // the cjne at 1bef clears CY due to r0==0x4d 583 for(uint8_t r2 = 5; r2>0; r2--) { 584 tmp = 0; // 1bf8 585 for(uint8_t r3 = 4;r3>0;r3--) { 586 // 1bf9 xchg a, intmem[r0] 587 uint8_t tmp1 = tmp; 588 tmp=ram[r0]; 589 ram[r0]=tmp1; 590 591 // 1bfa rrc a 592 tbit = CY; 593 CY = tmp & 1; 594 tmp = tbit | (tmp >> 1); 595 596 // 1bfb xchg a, intmem[r0] 597 tmp1 = tmp; 598 tmp=ram[r0]; 599 ram[r0]=tmp1; 600 601 // 1bfc rlc a 602 tbit=CY; 603 CY=tmp & 0x80; 604 tmp=(tmp<<1) | tbit; 605 606 if(++r0 == 0x4d) r0 = 0x4a; 607 } 608 tmp++; 609 //putc(tmp); // really putc_maybe_print() 610 } 611 //putc(' '); // really putc_maybe_print(' ') 612 tmp = ++r6; // 1c10 .. 1c11 613 //if (((tmp & 1) != 1) && (r5 != '\0')) get_keypress(); // r5 = skip_print 614 } 615 // if(r5==0) print_crlf(); // r5 := skip_print 616 } 617 618 uint8_t compact_str(uint8_t param, uint8_t *ptr, uint8_t op) { // 279f - 27d4 619 // compact 6 bit symbol param at address ptr 620 INTMEM[0x21] &= ~(1<<3); // clr 21.3 621 switch(op) { 622 case 0: { // just store the lower 6 bits at the lower 6 bits of the destination. 623 INTMEM[*ptr] = param & 0x3f; 624 if(*ptr == 0x49) { 625 INTMEM[0x21] |= (1 << 3); // set 21.3 626 } 627 return 1; 628 } 629 case 1: { // store the lowest 2 bits at the top 2 bits of the destination 630 // store the bits 3-6 at the low nibble at dest+1 631 uint8_t tmp = (param >> 2 | param << 6); 632 INTMEM[*ptr++] |= (tmp & 0xc0); 633 INTMEM[*ptr] = (INTMEM[*ptr] & 0xf0) | (tmp & 0xf); 634 return 2; 635 } 636 case 2: { // store the low nibble at the hi nibble of dest 637 // and the high nibble at the low nibble of dest 638 INTMEM[*ptr] = (INTMEM[*ptr] & 0xf) | (param << 4); 639 INTMEM[++*ptr] = param >> 4; 640 return 3; 641 } 642 default: { // store the low 6 bits at the high 6 bits of dest 643 INTMEM[*ptr++] |= ((param >> 2) | (param << 6)) & 0xfc; 644 return 0; 645 } 646 } 647 } 648 649 uint16_t fn_2807(uint16_t ptr) { 650 INTMEM[0x49] &= 0x3f; 651 //EXTMEM[ptr] = INTMEM[0x40]; 652 //for(int r0 = 0x41; r0 != 0x4a; r0++) { 653 // EXTMEM[++ptr] = INTMEM[r0]; 654 //} 655 memcpy(EXTMEM + ptr, INTMEM + 40, 10); 656 uint8_t last; 657 for(int r3 = 78; r3 != 0; r3--) { 658 // shift 80 bits INTMEM[0x49:0x40:-1] to the right by 1, 659 // shifting the last bit into the carry 660 bool cf=0; 661 for(int r0 = 0x49, r4 = 0xa; r4 != 0; r4--, r0--) { 662 last = rrc(INTMEM[r0], cf, &cf); 663 INTMEM[r0] = last; 664 } 665 if(cf) { 666 INTMEM[0x40] ^= 0x26; 667 INTMEM[0x41] ^= 0x3; 668 INTMEM[0x42] ^= 0x10; 669 INTMEM[0x43] ^= 0x37; 670 INTMEM[0x44] ^= 0x1a; 671 INTMEM[0x45] ^= 0x64; 672 INTMEM[0x46] ^= 0x1; 673 } 674 } 675 // INTMEM[0x40..0x48] = [last] + INTMEM[0x40:0x47] 676 for(int r0 = 0x40, tmp = last; ++r0 != 0x48;) { 677 // swap tmp and intmem[r0] 678 int tmp1 = INTMEM[r0]; 679 INTMEM[r0] = tmp; 680 tmp = tmp1; 681 } 682 683 // the CJNZ at 0x2840 (previous loop) clears CY when falling through 684 bool cf = 0; 685 for(int r3 = 2;r3 != 0; r3--) { 686 // rotate INTMEM[0x47:0x40:-1] right 687 for(int r0 = 0x47, r4 = 8; r4 != 0; r4--, r0--) { 688 INTMEM[r0] = rrc(INTMEM[r0],cf,&cf); 689 } 690 } 691 INTMEM[0x40] &= 0xc0; 692 EXTMEM[ptr++] |= INTMEM[0x40]; 693 for(int r0 = 0x41; r0 != 0x47; r0++, ptr++) { 694 EXTMEM[ptr] = INTMEM[r0]; 695 } 696 return ptr; 697 } // 2862 698 699 bool fn_2beb(uint8_t param) { 700 uint16_t ptr = (*((uint16_t*)(INTMEM + 0x52)) + 1) & 0xfbff ; 701 if(INTMEM[0x54] != (ptr>>8) || INTMEM[0x55] != (ptr&0xff)) { 702 EXTMEM[ptr]=param; 703 // disable interrupts 704 *((uint16_t*) INTMEM + 0x52) = ptr; 705 // enable interrupts 706 return 0; 707 } 708 return 1; 709 } // 2c1e 710 711 void fn_259c(const uint8_t *key) { 712 // does it all, first calls sbt_short, then parametric_entry, then crypt_byte 713 INTMEM[0x21] &= 0xef; // clear bit 4 714 715 EXTMEM[0x840a] = 2; // 259e .. 25a3 716 717 INTMEM[0x2d] = EXTMEM[0x8410]; 718 INTMEM[0x2e] = EXTMEM[0x8411]; 719 INTMEM[0x2f] = EXTMEM[0x7104]; 720 sbt_short(); // 25b4 721 INTMEM[0x2f] &= 0xfe; // 25b7 722 723 uint8_t r0 = 0x40, r1 = 0x2d; 724 uint16_t ptr = 0x7104; 725 for(;r1 != 0x30; r0++, r1++, ptr++) { 726 EXTMEM[ptr] = INTMEM[r1]; 727 INTMEM[r0] = INTMEM[r1]; 728 } 729 730 INTMEM[0x42] |= EXTMEM[0x7308] & 1; 731 732 // originally EXTMEM[0x7308] & 1 was used as a param to 733 // parametric_entry to toggle the hardcoded fixed key 734 parametric_entry(EXTMEM + 0x7104, key); // 25d6 735 // fn_0d58 inlined 736 // calls fn_d84(*((uint16_t*) (EXTMEM+0x7163))) 737 uint8_t r2, r3, r6, tmp; 738 uint8_t r4 = EXTMEM[0x7163]; 739 uint8_t r5 = EXTMEM[0x7164]; 740 // fn_d84 inlined 741 // uint16_t fn_0d84(uint16_t r4r5) 742 do { 743 r6 = EXTMEM[0x8412]; 744 r3 = ~r6 + 1; 745 r2 = ~EXTMEM[0x8413] + (r3==0); 746 } while(EXTMEM[0x8412] != r6); // if 0x8412 changed since the start of the loop repeat the calc. 747 r3 = r3 - r5; 748 tmp = r2 - r4; // d9e 749 if(r2 < r4) tmp+=0x90; 750 if(0x8f < tmp) tmp+=0x70; 751 uint16_t fn_0d58res = (tmp << 8) | r3; 752 // eofn fn_d84 - might be buggy, but is close enough. 753 *((uint16_t*) (INTMEM + 0x44)) = fn_0d58res; // 25dc .. 25df 754 INTMEM[0x43] = INTMEM[0x18]; // INTMEM[0x18] == BANK3_R0 755 if(INTMEM[0x43] == 0) { 756 tmp = (INTMEM[0x19] & 3); 757 if(tmp & 2) { 758 ptr = 0x72cf; 759 } else { 760 ptr = 0x72f7; 761 } 762 } else { 763 ptr = 0x7102; 764 tmp = 0; 765 } 766 INTMEM[0x46]=tmp; 767 uint8_t code = 1; 768 uint8_t iptr = 0x46; 769 code = compact_str(EXTMEM[ptr], &iptr, code); 770 code = compact_str(EXTMEM[++ptr], &iptr, code); 771 ptr = 0x7300; 772 code = compact_str(EXTMEM[ptr++], &iptr, code); 773 compact_str(EXTMEM[ptr], &iptr, code); 774 775 for(r0=0x44;r0!=0x4a;r0++) { 776 crypt_byte(INTMEM[r0]); 777 } 778 fn_2807(0x7600); 779 INTMEM[0x52]=0x78; 780 INTMEM[0x53]=0x78; 781 INTMEM[0x54]=0; 782 INTMEM[0x55]=0; 783 for(int i=16, ptr=0x7600;i!=0;i--, ptr++) { 784 fn_2beb(EXTMEM[ptr]); 785 } 786 } // 2641 787 788 void fn_2362(const uint8_t *key) { 789 // todo starts really at 22f0 790 // calls parametric_entry and in a loop crypt_byte 791 // ... 792 EXTMEM[0x7107] = INTMEM[0x40]; // 234d 793 EXTMEM[0x7108] = INTMEM[0x41]; 794 //bool cf = INTMEM[0x42] & 1; // INTMEM[0x42] & 1 determines if key is default or daily. 795 EXTMEM[0x7109] = INTMEM[0x41] & 0xfe; 796 797 parametric_entry(EXTMEM + 0x7107, key); // 2362 // instead of key, CY is passed as param, toggling the fixed key 798 799 for(uint8_t r0 = 0x44; // 2365 800 r0 != 0x4a; 801 r0++) { 802 crypt_byte(INTMEM[r0]); 803 } 804 805 INTMEM[0x18 /* BANK3_R0 */] = INTMEM[0x43]; 806 INTMEM[0x40] = INTMEM[0x46]; // 2373 807 // fn_27d5(0x46, 1) inlined below 808 INTMEM[0x21] &= 0xf7; // clear bit 3 809 uint8_t tmp = INTMEM[0x46] & 0xc0; // 27e8 .. 27e9 810 // exchange low nibble of tmp with INTMEM[0x47] // 27ec 811 tmp = (tmp & 0xf0) | (INTMEM[0x47] & 0xf); 812 INTMEM[0x47] = (INTMEM[0x47] & 0xf0); // no lower nibble from tmp necessary since it has been &ed with 0xc0 813 // rotate 2x left 814 uint8_t r3 = (tmp >> 2) | (tmp << 6); (void)r3; 815 // fn_27d5(0x47, 2) inlined below 816 tmp = (INTMEM[0x48] & 3 ) | INTMEM[0x47]; // 27f3 .. 27fa 817 // swap nibbles of tmp 818 uint8_t r4 = (tmp >> 4) | (tmp << 4); (void)r4; 819 // .... 820 // todo ends at 2563 821 } 822 823 int main(void) { 824 //const uint8_t foo[16]="\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\xa5"; 825 //memcpy(EXTMEM + 0x7f41, foo, sizeof foo); 826 827 //sbt(); 828 const uint8_t key[15]="\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"; 829 memcpy(PROGMEM + 0x72d7,key, sizeof key); 830 831 default_entry(); 832 833 printf("result of sbt: "); 834 for(int i=0;i<8;i++) { 835 printf("%02x ", cipherblock[i]); 836 } 837 printf("\n"); 838 for(int i=7;i>0;i-=2) { 839 putchar((((cipherblock[i]>>4^cipherblock[i-1]) & 0xf) | 0x40) + 1); 840 } 841 printf("\n"); 842 843 return 0; 844 }