trunk/src/mame/machine/315-5881_crypt.c
| r243020 | r243021 | |
| 529 | 529 | UINT16 sega_315_5881_crypt_device::block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data) |
| 530 | 530 | { |
| 531 | 531 | int j; |
| 532 | | int aux,aux2; |
| 533 | | int A,B; |
| 532 | int aux, aux2; |
| 533 | int A, B; |
| 534 | 534 | int middle_result; |
| 535 | 535 | UINT32 fn1_subkeys[4]; |
| 536 | 536 | UINT32 fn2_subkeys[4]; |
| 537 | 537 | |
| 538 | 538 | /* Game-key scheduling; this could be done just once per game at initialization time */ |
| 539 | | memset(fn1_subkeys,0,sizeof(UINT32)*4); |
| 540 | | memset(fn2_subkeys,0,sizeof(UINT32)*4); |
| 539 | memset(fn1_subkeys, 0, sizeof(UINT32) * 4); |
| 540 | memset(fn2_subkeys, 0, sizeof(UINT32) * 4); |
| 541 | 541 | |
| 542 | | for (j=0; j<38; ++j) { |
| 543 | | if (BIT(game_key, fn1_game_key_scheduling[j][0])!=0) { |
| 544 | | aux = fn1_game_key_scheduling[j][1]%24; |
| 545 | | aux2 = fn1_game_key_scheduling[j][1]/24; |
| 546 | | fn1_subkeys[aux2] ^= (1<<aux); |
| 542 | for (j = 0; j < 38; ++j) { |
| 543 | if (BIT(game_key, fn1_game_key_scheduling[j][0]) != 0) { |
| 544 | aux = fn1_game_key_scheduling[j][1] % 24; |
| 545 | aux2 = fn1_game_key_scheduling[j][1] / 24; |
| 546 | fn1_subkeys[aux2] ^= (1 << aux); |
| 547 | 547 | } |
| 548 | 548 | } |
| 549 | 549 | |
| 550 | | for (j=0; j<34; ++j) { |
| 551 | | if (BIT(game_key, fn2_game_key_scheduling[j][0])!=0) { |
| 552 | | aux = fn2_game_key_scheduling[j][1]%24; |
| 553 | | aux2 = fn2_game_key_scheduling[j][1]/24; |
| 554 | | fn2_subkeys[aux2] ^= (1<<aux); |
| 550 | for (j = 0; j < 34; ++j) { |
| 551 | if (BIT(game_key, fn2_game_key_scheduling[j][0]) != 0) { |
| 552 | aux = fn2_game_key_scheduling[j][1] % 24; |
| 553 | aux2 = fn2_game_key_scheduling[j][1] / 24; |
| 554 | fn2_subkeys[aux2] ^= (1 << aux); |
| 555 | 555 | } |
| 556 | 556 | } |
| 557 | 557 | /********************************************************/ |
| 558 | 558 | |
| 559 | 559 | /* Sequence-key scheduling; this could be done just once per decryption run */ |
| 560 | | for (j=0; j<20; ++j) { |
| 561 | | if (BIT(sequence_key,fn1_sequence_key_scheduling[j][0])!=0) { |
| 562 | | aux = fn1_sequence_key_scheduling[j][1]%24; |
| 563 | | aux2 = fn1_sequence_key_scheduling[j][1]/24; |
| 564 | | fn1_subkeys[aux2] ^= (1<<aux); |
| 560 | for (j = 0; j < 20; ++j) { |
| 561 | if (BIT(sequence_key, fn1_sequence_key_scheduling[j][0]) != 0) { |
| 562 | aux = fn1_sequence_key_scheduling[j][1] % 24; |
| 563 | aux2 = fn1_sequence_key_scheduling[j][1] / 24; |
| 564 | fn1_subkeys[aux2] ^= (1 << aux); |
| 565 | 565 | } |
| 566 | 566 | } |
| 567 | 567 | |
| 568 | | for (j=0; j<16; ++j) { |
| 569 | | if (BIT(sequence_key,j)!=0) { |
| 570 | | aux = fn2_sequence_key_scheduling[j]%24; |
| 571 | | aux2 = fn2_sequence_key_scheduling[j]/24; |
| 572 | | fn2_subkeys[aux2] ^= (1<<aux); |
| 568 | for (j = 0; j < 16; ++j) { |
| 569 | if (BIT(sequence_key, j) != 0) { |
| 570 | aux = fn2_sequence_key_scheduling[j] % 24; |
| 571 | aux2 = fn2_sequence_key_scheduling[j] / 24; |
| 572 | fn2_subkeys[aux2] ^= (1 << aux); |
| 573 | 573 | } |
| 574 | 574 | } |
| 575 | 575 | |
| 576 | 576 | // subkeys bits 10 & 41 |
| 577 | | fn2_subkeys[0] ^= (BIT(sequence_key,2)<<10); |
| 578 | | fn2_subkeys[1] ^= (BIT(sequence_key,4)<<17); |
| 577 | fn2_subkeys[0] ^= (BIT(sequence_key, 2) << 10); |
| 578 | fn2_subkeys[1] ^= (BIT(sequence_key, 4) << 17); |
| 579 | 579 | /**************************************************************/ |
| 580 | 580 | |
| 581 | 581 | // First Feistel Network |
| 582 | 582 | |
| 583 | | aux = BITSWAP16(counter,5,12,14,13,9,3,6,4, 8,1,15,11,0,7,10,2); |
| 583 | aux = BITSWAP16(counter, 5, 12, 14, 13, 9, 3, 6, 4, 8, 1, 15, 11, 0, 7, 10, 2); |
| 584 | 584 | |
| 585 | 585 | // 1st round |
| 586 | 586 | B = aux >> 8; |
| 587 | | A = (aux & 0xff) ^ feistel_function(B,fn1_sboxes[0],fn1_subkeys[0]); |
| 587 | A = (aux & 0xff) ^ feistel_function(B, fn1_sboxes[0], fn1_subkeys[0]); |
| 588 | 588 | |
| 589 | 589 | // 2nd round |
| 590 | | B = B ^ feistel_function(A,fn1_sboxes[1],fn1_subkeys[1]); |
| 590 | B = B ^ feistel_function(A, fn1_sboxes[1], fn1_subkeys[1]); |
| 591 | 591 | |
| 592 | 592 | // 3rd round |
| 593 | | A = A ^ feistel_function(B,fn1_sboxes[2],fn1_subkeys[2]); |
| 593 | A = A ^ feistel_function(B, fn1_sboxes[2], fn1_subkeys[2]); |
| 594 | 594 | |
| 595 | 595 | // 4th round |
| 596 | | B = B ^ feistel_function(A,fn1_sboxes[3],fn1_subkeys[3]); |
| 596 | B = B ^ feistel_function(A, fn1_sboxes[3], fn1_subkeys[3]); |
| 597 | 597 | |
| 598 | | middle_result = (B<<8)|A; |
| 598 | middle_result = (B << 8) | A; |
| 599 | 599 | |
| 600 | 600 | |
| 601 | 601 | /* Middle-result-key sheduling */ |
| 602 | | for (j=0; j<16; ++j) { |
| 603 | | if (BIT(middle_result,j)!=0) { |
| 604 | | aux = fn2_middle_result_scheduling[j]%24; |
| 605 | | aux2 = fn2_middle_result_scheduling[j]/24; |
| 606 | | fn2_subkeys[aux2] ^= (1<<aux); |
| 602 | for (j = 0; j < 16; ++j) { |
| 603 | if (BIT(middle_result, j) != 0) { |
| 604 | aux = fn2_middle_result_scheduling[j] % 24; |
| 605 | aux2 = fn2_middle_result_scheduling[j] / 24; |
| 606 | fn2_subkeys[aux2] ^= (1 << aux); |
| 607 | 607 | } |
| 608 | 608 | } |
| 609 | 609 | /*********************/ |
| 610 | 610 | |
| 611 | 611 | // Second Feistel Network |
| 612 | 612 | |
| 613 | | aux = BITSWAP16(data,14,3,8,12,13,7,15,4, 6,2,9,5,11,0,1,10); |
| 613 | aux = BITSWAP16(data, 14, 3, 8, 12, 13, 7, 15, 4, 6, 2, 9, 5, 11, 0, 1, 10); |
| 614 | 614 | |
| 615 | 615 | // 1st round |
| 616 | 616 | B = aux >> 8; |
| 617 | | A = (aux & 0xff) ^ feistel_function(B,fn2_sboxes[0],fn2_subkeys[0]); |
| 617 | A = (aux & 0xff) ^ feistel_function(B, fn2_sboxes[0], fn2_subkeys[0]); |
| 618 | 618 | |
| 619 | 619 | // 2nd round |
| 620 | | B = B ^ feistel_function(A,fn2_sboxes[1],fn2_subkeys[1]); |
| 620 | B = B ^ feistel_function(A, fn2_sboxes[1], fn2_subkeys[1]); |
| 621 | 621 | |
| 622 | 622 | // 3rd round |
| 623 | | A = A ^ feistel_function(B,fn2_sboxes[2],fn2_subkeys[2]); |
| 623 | A = A ^ feistel_function(B, fn2_sboxes[2], fn2_subkeys[2]); |
| 624 | 624 | |
| 625 | 625 | // 4th round |
| 626 | | B = B ^ feistel_function(A,fn2_sboxes[3],fn2_subkeys[3]); |
| 626 | B = B ^ feistel_function(A, fn2_sboxes[3], fn2_subkeys[3]); |
| 627 | 627 | |
| 628 | | aux = (B<<8)|A; |
| 628 | aux = (B << 8) | A; |
| 629 | 629 | |
| 630 | | aux = BITSWAP16(aux,15,7,6,14,13,12,5,4, 3,2,11,10,9,1,0,8); |
| 630 | aux = BITSWAP16(aux, 15, 7, 6, 14, 13, 12, 5, 4, 3, 2, 11, 10, 9, 1, 0, 8); |
| 631 | 631 | |
| 632 | 632 | return aux; |
| 633 | 633 | } |
| 634 | 634 | |
| 635 | |
| 635 | 636 | UINT16 sega_315_5881_crypt_device::get_decrypted_16() |
| 636 | 637 | { |
| 637 | 638 | UINT16 enc; |
| r243020 | r243021 | |
| 643 | 644 | dec_hist = dec; |
| 644 | 645 | |
| 645 | 646 | prot_cur_address ++; |
| 647 | |
| 646 | 648 | return res; |
| 647 | 649 | } |
| 648 | 650 | |
| 651 | |
| 649 | 652 | void sega_315_5881_crypt_device::enc_start() |
| 650 | 653 | { |
| 654 | dec_hist = 0; // seems to be needed by astrass at least otherwise any call after the first one will be influenced by the one before it. |
| 655 | block_pos = 0; |
| 651 | 656 | buffer_pos = BUFFER_SIZE; |
| 652 | 657 | dec_header = get_decrypted_16() << 16; |
| 653 | 658 | dec_header |= get_decrypted_16(); |
| 654 | 659 | |
| 660 | // the lower header bits are 2 values that multiply together to get the current stream length |
| 661 | // in astrass the first block is 0xffff (for a 0x10000 block) followed by 0x3f3f (for a 0x1000 block) |
| 662 | // etc. after each block a new header must be read, it looks like compressed and uncompressed blocks |
| 663 | // can be mixed like this, I don't know if the length is src length of decompressed length. |
| 664 | int blockx = ((dec_header & 0x00ff) >> 0) + 1; |
| 665 | int blocky = ((dec_header & 0xff00) >> 8) + 1; |
| 666 | block_size = blockx * blocky; |
| 667 | |
| 655 | 668 | if(dec_header & FLAG_COMPRESSED) { |
| 656 | 669 | line_buffer_size = dec_header & FLAG_LINE_SIZE_512 ? 512 : 256; |
| 657 | 670 | line_buffer_pos = line_buffer_size; |
| 658 | 671 | buffer_bit = 7; |
| 659 | 672 | } |
| 673 | |
| 674 | // printf("header %08x\n", dec_header); |
| 660 | 675 | enc_ready = true; |
| 661 | 676 | } |
| 662 | 677 | |
| r243020 | r243021 | |
| 667 | 682 | UINT16 val = get_decrypted_16(); |
| 668 | 683 | buffer[i] = val; |
| 669 | 684 | buffer[i+1] = val >> 8; |
| 685 | block_pos+=2; |
| 686 | if (block_pos == block_size) |
| 687 | { |
| 688 | // if we reach the size specified we need to read a new header |
| 689 | // todo: how should this work with compressed blocks?? |
| 690 | |
| 691 | enc_start(); |
| 692 | } |
| 670 | 693 | } |
| 671 | 694 | buffer_pos = 0; |
| 672 | 695 | } |