Docstoc

Cryptanalysis of Contents Scrambling System

Document Sample
Cryptanalysis of Contents Scrambling System Powered By Docstoc
					 Cryptanalysis of Contents Scrambling System
                                  Frank A. Stevenson ( frank@funcom.com )

                                      8th November 1999 (updated 13th Nov.)

Abstract: CSS is a scrambling system used in the distribution for movies on DVD ( Digital Versatile Disc )
a high capacity CD like storage system. Its main purpose is to prevent the unauthorized duplication of disc
contents. This is achieved through encrypting the files, and storing keys in hardware. Here we will describe
the system, and show that even if the keys can be securely stored in hardware, the data will not be protected
from unauthorized copying. Severe weaknesses in the ciphers effectively voids the need for the hardware
keys when decrypting the content.



0 General disclaimer.
    This information is provided as is, with no warranties on its accuracy or usability. It is based on a
    piece of source code claiming to be the css algorithms, and which have since been confirmed to
    interoperate with the CSS system. The author has not read any official CSS documentation, and
    any errors in the terminology is a result of this. This information has not to the knowledge of the
    author been made available through breaches of the DVD consortium Non Disclosure Agreement.



1 System overview.
    Every DVD player is equipped with a small set of player keys. When presented with a new disc,
    the player will attempt to decrypt the contents with the set of keys it possesses. Every disk has a
    disk key data block that is organized as follows:

              5 bytes hash of decrypted disk key ( hash )

              disk key encrypted with player key 1 (dk1 )

              disk key encrypted with player key 2 (dk2 )

              ...

              disk key encrypted with player key 409 (dk409)

    Suppose the player has a valid key for slot 213, it will calculate

     (1)        Kd = DA( dk213 , Kp213 )

    To verify that Kd is correct, the following check is done, if the check fails, it will try the next
    player key.

    (2)        Kd = DA( hash , Kd )

    An obvious weakness stems from this check, by trying all 240 possible Kd, disk key can be deduced
    without knowing any valid player key. As will be shown later, this attack can be carried out with a
    complexity of 225, making such an attack feasible in runtime applications. Another obvious
    attack is that by having 1 working player key, other player keys can be derived through a similar
    search. This can be done offline, also keys obtained from the former attack can be used as a
    starting point.

    To decrypt the contents an additional key tk - the title key is decrypted with the now decrypted and
    verified disk key.
                                                        1
  (3)       Kt = DB( tk, Kd)

  Each sector of the data files is the optionally encrypted by a key that is derived from Kt by
  exclusive or of specified bytes from the unencrypted first 128 bytes of the 2048 bytes sector. The
  decryption is done with the CSS stream cipher primitive described in section II.



2 CSS streamcipher primitive:
  The CSS streamcipher is a very simplistic one, based on 2 LFSRs being added together to produce
  output bytes. There is no truncation, both LFSR are clocked 8 times for every byte output, and
  there are 4 ways of combining the output of the LFSRs to an output byte. These four modes are
  just settings on 2 inverter switches, and the modes operation are used for the following purposes.

        1. Authentication to DVD drive ( not discussed )

        2. Decryption of Disk key (DA)

        3. Decryption of Title key (DB)

        4. Decryption of data blocks.

  LFSR1: 17 bits ? taps, and is initialized by the 2 first bytes of key, and setting the most significant
  bit to 1 to prevent null cycling.

  LFSR2: 25 bits 4 taps, is initialized with byte 3,4,5 of the key shifting all but the 3 least significant
  bits up 1 position, and setting bit 4 to prevent null cycling.

  As new bits are clocked into the LFSRs, the same bits are clocked in with reversed order to the two
  LFSRs output bytes. ( With optional inversion of bits. )

  The output of LFSR1 is O1(1), O1(2), O1(3) ...
  Likewise LFSR2 produces O2(1), O2(2), O2(3) ...

  These two streams are combined through 8 bits addition with carry carried over to the next output.
  The carry bit is zero at start of stream.

  (4)       O(i) = O1(i) + O2(i) + c    where c is carry bit from O(i-1)

  This streamcipher is very weak, a trivial 216 attack is possible with output bytes known for i =
  {1,2,3,4,5,6}. Guess the initial state of LFSR1, and clock out 4 bytes. O2(1), O2(2), O2(3), O2(4)
  can then be uniquely determined, and from them the state at i=4 is fully known. The guess on
  LFSR1 can then be verified by clocking out 2 or more bytes of the cipher and comparing the result.

  Another important attack is the case when only O(i) for i = {1,2,3,4,5} is known. Guess the initial
  state of LFSR1, and clock out 3 bytes. Now O2(1), O2(2) and O2(3) can be found as in the above
  attack. This will reveal all but the most significant bit of LFSR2s state at i=3. If both possible
  settings for MSB is tried, and LFSR2 is clocked backwards 24 steps, a state where bit 4 is set at
  i=1 can always be found. ( This is stated without proof ). Select the setting of the most significant
  bit for LFSR2 such that LFSR2 is in a legal state at i=1, and clock out two more bytes to verify the
  guess of LFSR1. For some values of O( i = {1,2,3,4,5} ) multiple start states can be found, and for
  others none. Selecting the correct start state is not a problem, as this attack is used in situations
  where only the first five output bytes are of significance ( encryption of keys ).



3 CSS mangling step:
  When the CSS streamcipher is used to encrypt keys such as in DA(data,key) and DB(data,key), an
  additional mangling step is performed on the data. This cipher is best illustrated with the following

                                                     2
block diagram:

       A(1,2,3,4,5) are the input bytes (data)

       C(1,2,3,4,5) are the output bytes (data)

       ki = O(i) where O(i={1,2,3,4,5}) is streamcipher output from key

       B(1,2,3,4,5) are temporary stages

The cipher is evaluated top down, with exceptions indicated by an arrow.




Examples of evaluating cipher:

       B(j) = xor( F( A(j) ) , A(j-1) , kj ) for j = {2,3,4,5}

       B(1) = xor ( F( A(1)) , B(5), k1 )

       C(j) = xor( F( B(j) ) , B(j-1) , kj ) for j = {2,3,4,5}

       C(1) = xor ( F( B(1)) , k1 )

F is a function, defined by a byte permutation table. With known cipher and plaintext, the whole
cipher unravels with a minimal amount of work. Here is how:

       Make a guess on k5

       B(5) = xor( F( A(5) ) , A(4) , k5 )

       B(4) = xor( F( B(5) ) , C(5), k5 )

       k4 = xor( F( A(4) ) , A(3) , B(4) )

       B(3) = xor( F( B(4) ) , C(4), k4 )

                                                     3
          k3 = xor( F( A(3) ) , A(2) , B(3) )

          B(2) = xor( F( B(3) ) , C(3), k3 )

          k2 = xor( F( A(2) ) , A(1) , B(2) )

          B(1) = xor( F( B(2) ) , C(2), k2 )

          k1 = xor( F( A(1) ) , B(5) , B(1) )

          verify by checking C(1) = xor ( F( B(1) , k1 )

   Thus by trying 256 possibilities, we can recover 5 output bytes from the CSS streamcipher, and so
   recover the key by using the five known output bytes. This attack can be put to immediate use for
   recovering other player keys as in the notes to eqn. 2,3. Even if the player key is not recovered
   through the reversal of the stream cipher, the output of the streamcipher is known, and will still be
   usefull for decrypting disks that employ other player keys.



4 Attacking the hash of the disk key.
   Reversing the hash at the start of the disc key block is somewhat more complicated. From (2) we
   see that only the hash value is known, the problem is finding a disk key such that the decrypted
   hash equals the disk key itself. An attack of complexity 225 proceeds as follows.

   First some aspects on the value of k2 will have to be considered. A(1) and A(2) is known, and a
   table can be build by running through every possible combination of k2 and B(1) and calculate the
   resulting C(2). When trying to build a table of possible values k2 of indexed by C(2) and B(1) there
   will be many values that map to the same set of indices, so a the table must be able to hold several
   values of k2 in each location.

   Guess the start state of LFSR1, calculate O1( i = {1,2,3,4,5} ) . Next guess B(1) and complete the
   following calculations:

          k1 = xor( F( B( 1 ) ) , C(1) )        C(1,2) is known, they are the start state of LFSR1

          B(5) = xor( F( A(1) ) , B(1), k1)

          k5 = xor( F( A(5) ) , A(4), B(5) )

          Through the table indexed by C(2) and B(1) all permissible k2 can be found, there can be
           from 0-8 , on average 1. For all permissible k2 calculate:

                   O2(1) , O2(2), and 2 possible O2(5). This is possible since k1,2,5 are found.

                   For every legal initial state of LFSR2 there exists a one to one mapping to
                    O2(1,2,5) , by generating a table with 224 entries the start state of LFSR2 can be
                    found. Thus C(1,2,3,4,5) is potentially known.

                   B(4) = xor( F( B(5) ) , C(5), k5 )

                   k4 = xor( F( A(4) ) , A(3) , B(4) )

                   B(3) = xor( F( B(4) ) , C(4), k4 )

                   k3 = xor( F( A(3) ) , A(2) , B(3) )

                   B(2) = xor( F( B(3) ) , C(3), k3 )

                   verify k2 = xor( F( A(2) ) , A(1) , B(2) ) , this holds for 1 / 256 tries ( 217
                                                        4
                     altogether ) and if the test holds, the key C(1,2,3,4,5) can be tested by eqn. (2). If
                     eqn (2) holds, then a key has been found that will satisfy the hash. From
                     experience it is possible to find from zero to a few such keys to any given hash
                     value. When multiple disc keys are found trial decryption of the files will
                     eliminate the false keys.

    This attack when implemented on a Pentium III running 450 MHz, will recover a disk key from
    the hash alone in less than 18 seconds. This is clearly much less than what is to be expected of a 40
    bits cipher.



5 Conclusion
    The author has through email correspondence learned that attacks as described at (2) have indeed
    been carried out by brute force prior to this analysis. CSS was designed with a 40 bit keylength to
    comply with US government export regulation, and as such it easily compromised through brute
    force attacks ( such are the intentions of export control ). Moreover the 40 bits have not been put to
    good use, as the ciphers succumb to attacks with much lower computational work than which is
    permitted in the export control rules. Whether CSS is a serious cryptographic cipher is debatable. It
    has been clearly been demonstrated that its strength does not match the keylength. If the cipher
    was intended to get security by remaining secret, this is yet another testament to the fact that
    security through obscurity is an unworkable principle.



6 Further information
    I have collected some copies that were posted to the Livid project mailing list. These include the
    original anonymous posting of the CSS algorithm, as well as full C source code for the attacks I
    outline here.


Anonymous post of CSS C source ( Date Mon, 25 Oct 1999 )

unsigned int CSStab0[11]={5,0,1,2,3,4,0,1,2,3,4};




unsigned char CSStab1[256]=

{

    0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b,
    0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b,
    0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f,
    0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91,
    0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75,
    0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95,
    0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11,
    0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f,
    0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b,
    0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb,
    0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f,
    0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1,
    0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15,

                                                      5
     0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5,
     0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71,
     0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff
};

unsigned char CSStab2[256]=
{
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,
    0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,
    0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,
    0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,
    0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
    0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55,
    0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63,
    0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71,
    0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e,
    0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,
    0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa,
    0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5,
    0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
    0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1,
    0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3
};

unsigned char CSStab3[512]=
{
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
                                           6
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff
};

unsigned char CSStab4[256]=
{
    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
};

unsigned char CSStab5[256]=
{
    0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f,
    0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07,
    0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b,
    0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03,
    0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d,
    0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05,
    0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09,
    0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01,
    0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e,
    0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06,
    0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a,
    0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02,
    0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c,
    0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04,
    0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08,
    0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00
};

void CSSdescramble(unsigned char *sec,unsigned char *key)
                                           7
{
    unsigned int t1,t2,t3,t4,t5,t6;
    unsigned char *end=sec+0x800;

    t1=key[0]^sec[0x54]|0x100;
    t2=key[1]^sec[0x55];
    t3=(*((unsigned int *)(key+2)))^(*((unsigned int *)(sec+0x56)));
    t4=t3&7;
    t3=t3*2+8-t4;
    sec+=0x80;
    t5=0;
    while(sec!=end)
    {
        t4=CSStab2[t2]^CSStab3[t1];
        t2=t1>>1;
        t1=((t1&1)<<8)^t4;
        t4=CSStab5[t4];
        t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
        t3=(t3<<8)|t6;
        t6=CSStab4[t6];
        t5+=t6+t4;
        *sec++=CSStab1[*sec]^(t5&0xff);
        t5>>=8;
    }
}

void CSStitlekey1(unsigned char *key,unsigned char *im)
{
    unsigned int t1,t2,t3,t4,t5,t6;
    unsigned char k[5];
    int i;

    t1=im[0]|0x100;
    t2=im[1];
    t3=*((unsigned int *)(im+2));
    t4=t3&7;
    t3=t3*2+8-t4;
    t5=0;
    for(i=0;i<5;i++)
    {
        t4=CSStab2[t2]^CSStab3[t1];
        t2=t1>>1;
        t1=((t1&1)<<8)^t4;
        t4=CSStab4[t4];
        t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
        t3=(t3<<8)|t6;
        t6=CSStab4[t6];
        t5+=t6+t4;
        k[i]=t5&0xff;
        t5>>=8;
    }
                                          8
    for(i=9;i>=0;i--)
        key[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[key[CSStab0[i+1]]]^key[CSStab0[i]];
}

void CSStitlekey2(unsigned char *key,unsigned char *im)
{
    unsigned int t1,t2,t3,t4,t5,t6;
    unsigned char k[5];
    int i;

    t1=im[0]|0x100;
    t2=im[1];
    t3=*((unsigned int *)(im+2));
    t4=t3&7;
    t3=t3*2+8-t4;
    t5=0;
    for(i=0;i<5;i++)
    {
        t4=CSStab2[t2]^CSStab3[t1];
        t2=t1>>1;
        t1=((t1&1)<<8)^t4;
        t4=CSStab4[t4];
        t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
        t3=(t3<<8)|t6;
        t6=CSStab5[t6];
        t5+=t6+t4;
        k[i]=t5&0xff;
        t5>>=8;
    }
    for(i=9;i>=0;i--)
        key[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[key[CSStab0[i+1]]]^key[CSStab0[i]];
}

void CSSdecrypttitlekey(unsigned char *tkey,unsigned char *dkey)
{
    int i;
    unsigned char im1[6];
    unsigned char im2[6]={0x51,0x67,0x67,0xc5,0xe0,0x00};

    for(i=0;i<6;i++)
        im1[i]=dkey[i];

    CSStitlekey1(im1,im2);
    CSStitlekey2(tkey,im1);
}


Post & source describing 216 attack on streamcipher (Date: Wed, 27 Oct 1999).

From Frank Andrew Stevenson <frank@funcom.com> Tue Nov 9 13:22:51 1999


                                                9
Date: Wed, 27 Oct 1999 08:55:01 +0200 (CEST)

To: livid-dev@livid.on.openprojects.net
Subject: [Livid-dev] Successfull attack on CSS algorithm

Hi, I am a new member to this list, in fact I subscribed just today, in order to send this
message, and answer to followups.

My main interest in this is purely cryptographical, so I have little or no knowledge of
the problems associated with CSS. What I have done is device an attack that will recover
a CSS key with a complexity of 2^16 and as little as 6 known output bytes. This should reduce
the keyrecovery time from ~17 hours to a fraction of a second.

The CSS algorith is fataly flawed. A divide and conquer attack is possible by guessing the
16 unknown bits of LFSR1. LFSR1 is then clocked 4 times, and the known keystream bytes are
then used to reconstruct the state of LFSR2. The whole cipher is then clocked another 2-6
times to validate the key. If the key is correct LFSR2 is clocked backwards 4 times to
retrieve the initial state. The fine details can be found in the source code below.

I hope this mail isn't too long, but I have included source for a complete cracker which
works as follows:

hippopotamus:~/pc/temp> scramble 3e 4c 13 2e 9c
Doing encryption
Keystate at start: 13e 4c 01385c2b
output: 80 18 e2 cc c1 21 85 0d 9f 8c

This produces the 10 first bytes of the keystream for the given key, and also dumps the
initial keystate.

hippopotamus:~/pc/temp> time scramble 80 18 e2 cc c1 21 85 0d 9f 8c
Attempting crack
Candidate: 13e 4c 01385c2b
0.090u 0.000s 0:00.10 90.0%     0+0k 0+0io 87pf+0w

With 10 bytes as input, the initial state is here recovered in 1/10th of a second on a PPro200.

 frank

---------- The following is C code for the attack --------

/********************************************************
 *
 * The Divide and conquer attack
 *
 * Deviced and written by Frank A. Stevenson 26 Oct 1999
 *
 * ( frank@funcom.com )
 * Released under the GPL license
 *
 ********************************************************/
                                              10
#define KEYSTREAMBYTES 10

static unsigned char invtab4[256];

void CSScracker( unsigned char* pStream ) {
  unsigned int t1,t2,t3,t4,t5,t6;
  unsigned int nTry;
  unsigned int vCandidate;
  int i;
  unsigned int j;

  /* Test that CSStab4 is a permutation */
  memset( invtab4, 0, 256 );
  for( i = 0 ; i < 256 ; i++ ) invtab4[ CSStab4[i] ] = 1;
  for( i = 0 ; i < 256 ; i++ ) if( invtab4[ i ] != 1 ) {
    printf( "Permutation error\n" );
    exit( -1 );
  }

  /* initialize the inverse of table4 */
  for( i = 0 ; i < 256 ; i++ ) invtab4[ CSStab4[i] ] = i;

  for(   nTry =   0 ; nTry < 65536 ; nTry++ ) {
    t1   = nTry   >> 8 | 0x100;
    t2   = nTry   & 0xff;
    t3   = 0;     /* not needed */
    t5   = 0;

    /* iterate cipher 4 times to reconstruct LFSR2 */
    for( i = 0 ; i < 4 ; i++ ) {
      /* advance LFSR1 normaly */
      t4=CSStab2[t2]^CSStab3[t1];
      t2=t1>>1;
      t1=((t1&1)<<8)^t4;
      t4=CSStab5[t4];
      /* deduce t6 & t5 */
      t6 = pStream[ i ];
      if( t5 ) t6 = ( t6 + 0xff )&0x0ff;
      if( t6 < t4 ) t6 += 0x100;
      t6 -= t4;
      t5 += t6 + t4;
      t6 = invtab4[ t6 ];
      /* printf( "%02x/%02x ", t4, t6 ); */
      /* feed / advance t3 / t5 */
      t3 = (t3 << 8) | t6;
      t5 >>= 8;
    }

    vCandidate = t3;


                                              11
        /* iterate 6 more times to validate candidate key */
        for( ; i < KEYSTREAMBYTES ; i++ ) {
          t4=CSStab2[t2]^CSStab3[t1];
          t2=t1>>1;
          t1=((t1&1)<<8)^t4;
          t4=CSStab5[t4];
          t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
          t3=(t3<<8)|t6;
          t6=CSStab4[t6];
          t5+=t6+t4;
          if( (t5 & 0xff) != pStream[i] ) break;
          t5>>=8;
        }

        if( i == KEYSTREAMBYTES ) {
          /* Do 4 backwards steps of iterating t3 to deduce initial state */
          t3 = vCandidate;
          for( i = 0 ; i < 4 ; i++ ) {
            t1 = t3 & 0xff;
            t3 = ( t3 >> 8 );
            /* easy to code, and fast enough bruteforce search for byte shifted in */
            for( j=0 ; j < 256 ; j++ ) {
              t3 = (t3 & 0x1ffff) | ( j << 17 );
              t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
              if( t6 == t1 ) break;
            }
          }
          printf( "Candidate: %03x %02x %08x\n", 0x100|(nTry>>8),nTry&0x0ff,t3 );
        }
    }
}


------ Following is a complete cracker --- scramble.c ---------
------- compiles with VC++ / gcc linux, runs on x86 ----------

#include <stdio.h>

#include <string.h>

#include <ctype.h>

#include <stdlib.h>




unsigned int CSStab0[11]={5,0,1,2,3,4,0,1,2,3,4};




unsigned char CSStab1[256]=
                                              12
{

     0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b,
     0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b,
     0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f,
     0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91,
     0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75,
     0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95,
     0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11,
     0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f,
     0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b,
     0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb,
     0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f,
     0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1,
     0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15,
     0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5,
     0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71,
     0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff
};

unsigned char CSStab2[256]=
{
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,
    0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,
    0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,
    0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,
    0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
    0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55,
    0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63,
    0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71,
    0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e,
    0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,
    0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa,
    0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5,
    0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
    0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1,
    0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3
};

unsigned char CSStab3[512]=
{
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
                                           13
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff
};

unsigned char CSStab4[256]=
{
    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
};

unsigned char CSStab5[256]=
{
    0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f,
    0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07,
    0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b,
                                           14
     0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03,
     0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d,
     0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05,
     0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09,
     0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01,
     0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e,
     0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06,
     0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a,
     0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02,
     0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c,
     0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04,
     0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08,
     0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00
};

/***********************************************
 *
 * The basic CSS cipher code
 *
 *
 * With reduced mangling in the key setup
 *
 *
 ***********************************************/

void CSSdescramble( unsigned char *key )
{
    unsigned int t1,t2,t3,t4,t5,t6;
    unsigned int i;

     t1= key[0] ^ 0x100;
     t2= key[1];
     t3=(*((unsigned int *)(key+2)));
     t4=t3&7;
     t3=t3*2+8-t4;
     t5=0;

  printf( "Keystate at start: %03x %02x %08x\n", t1, t2, t3 );
    printf( "output: " );
    for( i=0 ; i < 10 ; i++ )
    {
        t4=CSStab2[t2]^CSStab3[t1];
        t2=t1>>1;
        t1=((t1&1)<<8)^t4;
        t4=CSStab5[t4];
        t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
        t3=(t3<<8)|t6;
        t6=CSStab4[t6];
        t5+=t6+t4;
        printf( "%02x ",t5&0xff);
        t5>>=8;
                                           15
      }
      printf( "\n" );
}

/********************************************************
 *
 * The Divide and conquer attack
 *
 * Deviced and written by Frank A. Stevenson 26 Oct 1999
 *
 * ( frank@funcom.com )
 * Released under the GPL license
 *
 ********************************************************/

#define KEYSTREAMBYTES 10

static unsigned char invtab4[256];

void CSScracker( unsigned char* pStream ) {
  unsigned int t1,t2,t3,t4,t5,t6;
  unsigned int nTry;
  unsigned int vCandidate;
  int i;
  unsigned int j;

    /* Test that CSStab4 is a permutation */
    memset( invtab4, 0, 256 );
    for( i = 0 ; i < 256 ; i++ ) invtab4[ CSStab4[i] ] = 1;
    for( i = 0 ; i < 256 ; i++ ) if( invtab4[ i ] != 1 ) {
      printf( "Permutation error\n" );
      exit( -1 );
    }

    /* initialize the inverse of table4 */
    for( i = 0 ; i < 256 ; i++ ) invtab4[ CSStab4[i] ] = i;

    for(   nTry =   0 ; nTry < 65536 ; nTry++ ) {
      t1   = nTry   >> 8 | 0x100;
      t2   = nTry   & 0xff;
      t3   = 0;     /* not needed */
      t5   = 0;

      /* iterate cipher 4 times to reconstruct LFSR2 */
      for( i = 0 ; i < 4 ; i++ ) {
        /* advance LFSR1 normaly */
        t4=CSStab2[t2]^CSStab3[t1];
        t2=t1>>1;
        t1=((t1&1)<<8)^t4;
        t4=CSStab5[t4];
        /* deduce t6 & t5 */
                                                16
            t6 = pStream[ i ];
            if( t5 ) t6 = ( t6 + 0xff )&0x0ff;
            if( t6 < t4 ) t6 += 0x100;
            t6 -= t4;
            t5 += t6 + t4;
            t6 = invtab4[ t6 ];
            /* printf( "%02x/%02x ", t4, t6 ); */
            /* feed / advance t3 / t5 */
            t3 = (t3 << 8) | t6;
            t5 >>= 8;
        }

        vCandidate = t3;

        /* iterate 6 more times to validate candidate key */
        for( ; i < KEYSTREAMBYTES ; i++ ) {
          t4=CSStab2[t2]^CSStab3[t1];
          t2=t1>>1;
          t1=((t1&1)<<8)^t4;
          t4=CSStab5[t4];
          t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
          t3=(t3<<8)|t6;
          t6=CSStab4[t6];
          t5+=t6+t4;
          if( (t5 & 0xff) != pStream[i] ) break;
          t5>>=8;
        }

        if( i == KEYSTREAMBYTES ) {
          /* Do 4 backwards steps of iterating t3 to deduce initial state */
          t3 = vCandidate;
          for( i = 0 ; i < 4 ; i++ ) {
            t1 = t3 & 0xff;
            t3 = ( t3 >> 8 );
            /* easy to code, and fast enough bruteforce search for byte shifted in */
            for( j=0 ; j < 256 ; j++ ) {
              t3 = (t3 & 0x1ffff) | ( j << 17 );
              t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
              if( t6 == t1 ) break;
        }
          }
          printf( "Candidate: %03x %02x %08x\n", 0x100|(nTry>>8),nTry&0x0ff, t3 );
        }
    }
}

/* simple function to convert hex bytes to int */
/* note: will give random results if nonhex digits are input */

static char hexdigits[17] = "0123456789abcdef\0";


                                                17
static int HexByteToInt( const char *pNumber ) {
  char ch;
  int r;

    ch = tolower( pNumber[0] );
    r = 16 * (int)( strchr( hexdigits, ch ) - hexdigits );
    ch = tolower( pNumber[1] );
    r+= (int)( strchr( hexdigits, ch ) - hexdigits );

    return r & 0x0ff;   /* invalid input will have produce garbage */
}

/* Main function */
int main( int argc, char* argv[] ) {
  int i;
  unsigned char data[ KEYSTREAMBYTES ];


    memset( data, 0, KEYSTREAMBYTES );

    if( argc > KEYSTREAMBYTES + 1 ) {
      printf( "To many arguments\n" );
      return -1;
    }

    if( argc < 6 ) {
      printf( "Usage: %s xx xx ... ( 5 / %i hex bytes )\n", argv[0], KEYSTREAMBYTES );
      return -1;
    }

    for( i = 1; i < argc ; i++ ) {
      data[i-1] = HexByteToInt( argv[i] );
    }

    if( argc == KEYSTREAMBYTES + 1 ) {
      /* search for key */
      printf( "Attempting crack\n" );
      CSScracker( data );
    } else {
      /* Produce sample keystream */
      printf( "Doing encryption\n" );
      CSSdescramble( data );
    }

    return( 0 );
}


Post & source describing attack on playerkeys (Date: Thu, 28 Oct 1999).

From Frank Andrew Stevenson <frank@funcom.com> Tue Nov 9 13:23:29 1999

                                                18
Date: Thu, 28 Oct 1999 12:57:37 +0200 (CEST)
To: livid-dev@livid.on.openprojects.net
Subject: [Livid-dev] Working PlayerKey cracker


In response to feedback from yesterdays post I have now refined my attack in the following
ways:

The CSSdecrypt key can now be recoverd with only 5 bytes of known output. Sometimes multiple
keys will be found to a single output, due to colissions in the mixing stage. But this is
not a problem when recovering KEKs ( Key encryption Keys ), as all keys found will be
equivalent / interchangable.

There has been some debate around the 'hash function'. I choose to view it as a very simple
encryption function. With 5 byte input, 5 byte output and 5 byte key. When searching for
a player key, the input / output is known. The cipher can then be attacked with a complexity
of 2^8. Code for the key recovery is given below. This cipher has many colissions, and some
input outup pairs have no keys, while others have multiple. The latter is a concern when
searching for Player keys, as they have to be eliminted by checking agains other discs.

I have attached a program that works as follows:

hippopotamus:~/tmp> time ./keyrec 22 e1 67 83 72 0f c1 7a 96 98
Recovering Key
Possible mangling key: af c9 07 42 1f
  Possible Player key 51 67 67 c5 e0
  Possible Player key 69 d2 e3 92 ae
5.000u 0.010s 0:05.44 92.0%     0+0k 0+0io 87pf+0w

Here 2 equivalent player keys are recovered from the
input: 22 e1 67 83 72 - Disc key
output: 0f c1 7a 96 98 - intermediate key, common for all player keys

The process takes 5.5 seconds on a PPro200, somewhat slower now that only 5 bytes are known
in the keystream.

If this works, as I hope it will, I will leave it as an exersice to the reader to recover
all player keys :-)

frank


-------------- This is how to recover the 'hashing key' --------

static int   unmangle ( unsigned char* in , unsigned char *out ) {
  unsigned   char A[5];
  unsigned   char B[5];
  unsigned   char C[5];
  unsigned   char k[6];
  int i,j;


                                             19
  /* Recover mangling key */
  memcpy( A, in, 5 );
  memcpy( C, out, 5 );
  k[5] = 0;

  for( i=0 ; i < 256 ; i++ ) {
    k[4] = i;
    for( j = 4 ; j >= 2 ; j-- ) {
      B[j] = k[j] ^ CSStab1[ A[j] ] ^ A[j-1];
      B[j-1] = CSStab1[ B[j] ] ^ k[j] ^ C[j];
      k[j-1] = A[j-2] ^ CSStab1[ A[j-1] ] ^ B[j-1];
    }
    B[0] = CSStab1[ B[1] ] ^ k[1] ^ C[1];
    k[0] = B[0] ^ CSStab1[ A[0] ] ^ B[4];

    if( ( CSStab1[ B[0] ] ^ k[0] )== C[0] ) {
      printf( "Possible mangling key: %02x %02x %02x %02x %02x\n", k[0],
k[1], k[2], k[3], k[4] );
    }
  }
  return 0;
}

--------- The following is the complete sourec for --------
-------------- player key cracker --- keyrec.c -------------


#include   <stdio.h>
#include   <string.h>
#include   <ctype.h>
#include   <stdlib.h>

static unsigned int CSStab0[11]={5,0,1,2,3,4,0,1,2,3,4};

static unsigned char CSStab1[256]=
{
    0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b,
    0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b,
    0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f,
    0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91,
    0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75,
    0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95,
    0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11,
    0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f,
    0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b,
    0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb,
    0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f,
    0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1,
    0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15,
    0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5,
    0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71,
                                          20
     0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff
};

static unsigned char CSStab2[256]=
{
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,
    0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,
    0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,
    0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,
    0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
    0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55,
    0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63,
    0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71,
    0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e,
    0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,
    0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa,
    0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5,
    0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
    0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1,
    0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3
};

static unsigned char CSStab3[512]=
{
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
                                           21
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff
};

static unsigned char CSStab4[256]=
{
    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
};

static unsigned char CSStab5[256]=
{
    0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f,
    0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07,
    0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b,
    0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03,
    0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d,
    0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05,
    0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09,
    0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01,
    0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e,
    0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06,
    0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a,
    0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02,
    0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c,
    0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04,
    0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08,
    0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00
};

static void CSSdescramble( unsigned char *key )
{
    unsigned int t1,t2,t3,t4,t5,t6;
                                           22
      unsigned int i;

      t1= key[0] ^ 0x100;
      t2= key[1];
      t3=(*((unsigned int *)(key+2)));
      t4=t3&7;
      t3=t3*2+8-t4;
      t5=0;
          printf( "Keystate at start: %03x %02x %08x\n", t1, t2, t3 );
      printf( "output: " );
      for( i=0 ; i < 10 ; i++ )
      {
          t4=CSStab2[t2]^CSStab3[t1];
          t2=t1>>1;
          t1=((t1&1)<<8)^t4;
          t4=CSStab5[t4];
          t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
          t3=(t3<<8)|t6;
          t6=CSStab4[t6];
          t5+=t6+t4;
          printf( "%02x ",t5&0xff);
          t5>>=8;
      }
      printf( "\n" );
}

/********************************************************
 *
 * The Divide and conquer attack
 *
 * Deviced and written by Frank A. Stevenson
 *
 * ( frank@funcom.com )
 * Released on a GPL license
 *
 ********************************************************/

static int RunLfsr2Backwards( int vStartState, int nSteps ) {
  unsigned int t1,t3,t6;
  int i,j;

    t3 = vStartState;
    for( i = 0 ; i < nSteps ; i++ ) {
      t1 = t3 & 0xff;
      t3 = ( t3 >> 8 );
      /* easy to code, and fast enough bruteforce search for byte shifted in */
      for( j=0 ; j < 256 ; j++ ) {
        t3 = (t3 & 0x1ffff) | ( j << 17 );
        t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
        if( t6 == t1 ) break;
      }
                                            23
    }
    return t3;
}

static unsigned char invtab4[256];

static void CSScracker( unsigned char* pStream, unsigned char *pTableA, unsigned char
*pTableB ) {
  unsigned int t1,t2,t3,t4,t5,t6;
  unsigned int nTry;
  unsigned int vCandidate;
  int i;

    /* Test that pTableA is a permutation */
    memset( invtab4, 0, 256 );
    for( i = 0 ; i < 256 ; i++ ) invtab4[ pTableA[i] ] = 1;
    for( i = 0 ; i < 256 ; i++ ) if( invtab4[ i ] != 1 ) {
      printf( "Permutation error\n" );
      exit( -1 );
    }

    /* initialize the inverse of table4 */
    for( i = 0 ; i < 256 ; i++ ) invtab4[ pTableA[i] ] = i;

    for(   nTry = 0 ; nTry < 65536 ; nTry++ ) {
      t1   = nTry >> 8 | 0x100;
      t2   = nTry & 0xff;
      t3   = 0;
      t5   = 0;

      /* iterate cipher 3 times to reconstruct LFSR2 16/17 bits */
      for( i = 0 ; i < 3 ; i++ ) {
        /* advance LFSR1 normaly */
        t4=CSStab2[t2]^CSStab3[t1];
        t2=t1>>1;
        t1=((t1&1)<<8)^t4;
        t4=pTableB[t4];
        /* deduce t6 & t5 */
        t6 = pStream[ i ];
        if( t5 ) t6 = ( t6 + 0xff )&0x0ff;
        if( t6 < t4 ) t6 += 0x100;
        t6 -= t4;
        t5 += t6 + t4;
        t6 = invtab4[ t6 ];
        /* printf( "%02x/%02x ", t4, t6 ); */
        /* feed / advance t3 / t5 */
        t3 = (t3 << 8) | t6;
        t5 >>= 8;
      }

      /* Guess the most significant bit of LFSR2 */
                                              24
     vCandidate = RunLfsr2Backwards( t3 , 3 );
     if( ( vCandidate & 0x08 ) == 0 ) {
       t3 |= 0x01000000;
       vCandidate = RunLfsr2Backwards( t3 , 3 );
     }
     if( ( vCandidate & 0x08 ) == 0 ) {
       printf( "Failed to guess bit - exiting\n" );
       exit( -1 );
     }

     /* iterate 2 more times to validate candidate key */
     for( ; i < 5 ; i++ ) {
       t4=CSStab2[t2]^CSStab3[t1];
       t2=t1>>1;
       t1=((t1&1)<<8)^t4;
       t4=pTableB[t4];
       t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
       t3=(t3<<8)|t6;
       t6=pTableA[t6];
       t5+=t6+t4;
       if( (t5 & 0xff) != pStream[i] ) break;
       t5>>=8;
     }

     if( i == 5 ) {
       /* Key was found - print out result */
       t4 = ( vCandidate / 2 ) & 0xfffff8;
       t4 |= vCandidate & 0x7;
       /* printf( "Candidate: %03x %02x %08x\n", 0x100|(nTry>>8),nTry&0x0ff, vCandidate );
*/
      printf( " Possible Player key %02x %02x %02x %02x %02x\n", nTry>>8, nTry&0x0ff,
t4&0xff , (t4 >>8) &0xff, t4 >> 16 );
    }
  }
}


/* simple function to convert hex bytes to int */
/* note: will give random results if nonhex digits are input */

static char hexdigits[17] = "0123456789abcdef\0";

static int HexByteToInt( const char *pNumber ) {
  char ch;
  int r;

  ch = tolower( pNumber[0] );
  r = 16 * (int)( strchr( hexdigits, ch ) - hexdigits );
  ch = tolower( pNumber[1] );
  r+= (int)( strchr( hexdigits, ch ) - hexdigits );


                                            25
    return r & 0x0ff;   /* invalid input will have produce garbage */
}


/* Revert mangling function - and crack keys*/
static int unmangle ( unsigned char* in , unsigned char *out ) {
  unsigned char A[5];
  unsigned char B[5];
  unsigned char C[5];
  unsigned char k[6];
  int i,j;

    /* Recover mangling key */
    memcpy( A, in, 5 );
    memcpy( C, out, 5 );
    k[5] = 0;

    for( i=0 ; i < 256 ; i++ ) {
      k[4] = i;
      for( j = 4 ; j >= 2 ; j-- ) {
        B[j] = k[j] ^ CSStab1[ A[j] ] ^ A[j-1];
        B[j-1] = CSStab1[ B[j] ] ^ k[j] ^ C[j];
        k[j-1] = A[j-2] ^ CSStab1[ A[j-1] ] ^ B[j-1];
      }
      B[0] = CSStab1[ B[1] ] ^ k[1] ^ C[1];
      k[0] = B[0] ^ CSStab1[ A[0] ] ^ B[4];

    if( ( CSStab1[ B[0] ] ^ k[0] )== C[0] ) {
      printf( "Possible mangling key: %02x %02x %02x %02x %02x\n", k[0], k[1], k[2], k[3],
k[4] );
      CSScracker( k, CSStab4, CSStab4 );

        }
    }

    return 0;
}


/* Main function */
int main( int argc, char* argv[] ) {
  int i;
  unsigned char in[5] = { 0,0,0,0,0 };
  unsigned char out[5] = { 0,0,0,0,0 };

  if( argc != 11 ) {
    printf( "Usage: %s xx xx xx xx xx yy yy yy yy yy ( Disc key / Encrypted Disk key )\n",
argv[0] );
    return -1;
  }


                                             26
    for( i = 0; i < 5 ; i++ ) {
      in[ i ] = HexByteToInt( argv[i+1] );
      out[ i ] = HexByteToInt( argv[i+6] );
    }

    /* search for key */
    printf( "Recovering Key\n" );
    unmangle( in, out );

    return( 0 );
}




Post & source describing attack on Disk key hash (Date: Sat, 30 Oct 1999).

From Frank Andrew Stevenson <frank@funcom.com> Tue Nov 9 13:24:21 1999
Date: Sat, 30 Oct 1999 20:40:25 +0200 (CEST)
To: livid-dev@livid.on.openprojects.net
Subject: [Livid-dev] Working attack on DiskKey Hash

Through private communication with list readers, I was more or less challenged... ( Or so
it felt to me ) To find an attack whereby the encrypted (temporary) diskkey can be retrieved
from the hash found at the start of the Disk key data block.

At first it seemed to me that it required a workload of 2^40. And there didn't seem much
in the way for speeding up such an attack. But througe careful study of the structure in
the mangling cipher and the CSS I have now come up with the following attack.

Guess the initals state of LFSR1, and B[0] - the first byte of the second stage of the mangling
cipher. From this starting point k[0] and B[4] , first byte of mangling key, and fifth byte
of second stage can be found. Now k[4] can be found, that is the fifth byte in the mangling
key. Through a table all permissible k[1] second mangling keys can be found.

Since the mangling key is the output of the ordinary CSS cipher, LFSR1s output is completely
known. We have also just found byte 1,2,5 of the CSS cipher output. This gives us 2
possibilities of 1,2,5 byte output from LFSR2. Luckily there is a 1 <-> 1 mapping of these
bytes and the initial state.

So through a table with 2^24 entries the initial state of LSFR2 can be found. By now
completing the mangle cipher 1 out 256 LFSR2 startstates will emerge as a candidate, and
can be checked the usual (slow) way. There will 'only' be 2^17 such checks so performance
is not a concern.

The whole attack has a complexity of 2^24 (mayby 25), with a memory requirnement of 64MB.
On a PIII/450 it will recover a set of possible keys in less than in 20 seconds.

Sample run on 200MHz R4000 (?)

odin:~> time ./unhash fb 81 26 01 fe

                                                 27
CSS hash finder - gobbles memory ( 64 MB RAM ) Good luck

Searching for hash: fb 81 26 01 fe
Initializing k[1] lookup table
Initializing and clearing 64MB of RAM
Calculating big table. Wait, this takes time
--------------------------------
################################
Table init completed, now reversing hash

 Possible tmp key 21 5b   31 89   82
 Possible tmp key 3f 9d   fa de   f3
 Possible tmp key 53 4d   fe 99   1e
114.602u 1.595s 1:59.12   97.5%   0+0k 0+0io 0pf+0w

This recovers 3 possible keys for the given hash. I believe the wrong ones are easy to
eliminate by trying to decode the datastreams. ( It takes almost 2 minutes on this CPU,
but at least it runs on bigendians as well )

frank


--------- The following is the complete sourec for --------
---- Fully functional DiskKey Hash cracker --- unhash.c ----


#include <stdio.h>

#include <string.h>

#include <ctype.h>

#include <stdlib.h>




static unsigned int CSStab0[11]={5,0,1,2,3,4,0,1,2,3,4};




static unsigned char CSStab1[256]=
{
    0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b,
    0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b,
    0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f,
    0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91,
    0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75,
    0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95,
    0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11,
    0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f,
    0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b,
                                              28
     0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb,
     0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f,
     0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1,
     0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15,
     0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5,
     0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71,
     0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff
};

static unsigned char CSStab2[256]=
{
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,
    0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,
    0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,
    0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,
    0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
    0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55,
    0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63,
    0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71,
    0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c,
    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e,
    0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,
    0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa,
    0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5,
    0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
    0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1,
    0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3
};

static unsigned char CSStab3[512]=
{
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
    0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
                                           29
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,
     0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff
};

static unsigned char CSStab4[256]=
{
    0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
    0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
    0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
    0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
    0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
    0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
    0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
    0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
    0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
    0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
    0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
    0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
    0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
    0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
    0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
    0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
};

void CSStitlekey1(unsigned char *key,unsigned char *im)
{
    unsigned int t1,t2,t3,t4,t5,t6;
    unsigned char k[5];
    int i;

     t1=im[0]|0x100;
     t2=im[1];
     t3=im[2] | (im[3]<<8) | (im[4]<<16);
     t4=t3&7;
     t3=t3*2+8-t4;
     t5=0;
     for(i=0;i<5;i++)
     {
         t4=CSStab2[t2]^CSStab3[t1];
         t2=t1>>1;
         t1=((t1&1)<<8)^t4;
                                            30
          t4=CSStab4[t4];
          t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
          t3=(t3<<8)|t6;
          t6=CSStab4[t6];
          t5+=t6+t4;
          k[i]=t5&0xff;
          t5>>=8;
      }
      for(i=9;i>=0;i--)
          key[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[key[CSStab0[i+1]]]^key[CSStab0[i]];
}

/********************************************************
 *
 * The CSS Hash reversal
 *
 * Devised and written by Frank A. Stevenson
 *
 * ( frank@funcom.com )
 * Released on a GPL license
 *
 ********************************************************/

#define K1TABLEWIDTH 10

/* simple function to convert hex bytes to int */
/* note: will give random results if nonhex digits are input */

static char hexdigits[17] = "0123456789abcdef\0";

static int HexByteToInt( const char *pNumber ) {
  char ch;
  int r;

    ch = tolower( pNumber[0] );
    r = 16 * (int)( strchr( hexdigits, ch ) - hexdigits );
    ch = tolower( pNumber[1] );
    r+= (int)( strchr( hexdigits, ch ) - hexdigits );

    return r & 0x0ff;   /* invalid input will have produce garbage */
}

/*
 * Simple function to test if a candidate key produces the given hash
 */

void investigate( unsigned char* hash, unsigned char *k ) {
  unsigned char im2[6];
  unsigned char pkey[6];

    memcpy( im2, hash, 5 );
                                             31
    im2[5] = 0;
    memcpy( pkey, k, 5 );
    pkey[5] = 0;
      CSStitlekey1( im2, pkey );

    if( memcmp( im2, pkey, 5 ) == 0 ) {
       printf( " Possible tmp key %02x %02x %02x %02x %02x\n", k[0], k[1], k[2], k[3], k[4] );
    }
}

/* Main function */
int main( int argc, char* argv[] ) {
  unsigned char A[5] = { 0,0,0,0,0 }; /* hashed disk key - unput to mangle cipher */
  unsigned char B[5] = { 0,0,0,0,0 }; /* Second Stage of mangle cipher */
  unsigned char C[5] = { 0,0,0,0,0 }; /* Output Stage of mangle cipher-IntermediateKey */
  unsigned char k[5] = { 0,0,0,0,0 }; /* Mangling cipher key - Also output from CSS(C) */
  unsigned char out1[5];               /* five first output bytes of LFSR1 */
  unsigned char out2[5];               /* five first output bytes of LFSR2 */
  unsigned int lfsr1a;                 /* upper 9 bits of LFSR1 */
  unsigned int lfsr1b;                 /* lower 8 bits of LFSR1 */
  unsigned int tmp, tmp2, tmp3, tmp4,tmp5;
  int i,j;
  unsigned int nStepA;         /* iterator for LFSR1 start state */
  unsigned int nStepB;         /* iterator for possible B[0]      */
  unsigned int nTry;           /* iterator for K[1] possibilities */
  unsigned int nPossibleK1; /* #of possible K[1] values */
  unsigned char* K1table;      /* Lookup table for possible K[1] */
  unsigned int* BigTable;      /* LFSR2 startstate indexed by 1,2,5 output byte */

    /* Greeting */
    printf( "CSS hash finder - gobbles memory ( 64 MB RAM ) Good luck\n\n" );

    /* Check arguments */
    if( argc != 6 ) {
      printf( "Usage: %s xx xx xx xx xx ( Hashed Disk key )\n", argv[0] );
      return -1;
    }

    /* Convert input arguments to hash */
    for( i = 0; i < 5 ; i++ ) {
      A[ i ] = HexByteToInt( argv[i+1] );
    }
    printf( "Searching for hash: %02x %02x %02x %02x %02x\n", A[0], A[1], A[2], A[3], A[4] );

    /*
     * Prepare tables for hash reversal
     */

    /* initialize lookup tables for k[1] */
    printf( "Initializing k[1] lookup table\n");
    K1table = malloc( 65536 * K1TABLEWIDTH );
                                              32
memset( K1table, 0 , 65536 * K1TABLEWIDTH );
if( K1table == NULL ) {
  printf( "Out of memory error, damn you should see what I will malloc next :-)\n" );
  exit( -1 );
}
tmp = A[0] ^ CSStab1[ A[1] ];
for( i = 0 ; i < 256 ; i++ ) /* k[1] */ {
  tmp2 = CSStab1[ tmp ^ i ]; /* CSStab1[ B[1] ]*/
  for( j = 0 ; j < 256 ; j++ ) /* B[0] */ {
    tmp3 = j ^ tmp2 ^ i; /* C[1] */
    tmp4 = K1table[ K1TABLEWIDTH * ( 256 * j + tmp3 ) ]; /* count of entries here */
    tmp4++;
    if( tmp4 == K1TABLEWIDTH ) {
      printf( "Table disaster %d\n", tmp4 );
    }
    if( tmp4 < K1TABLEWIDTH ) K1table[ K1TABLEWIDTH * ( 256 * j + tmp3 ) + tmp4 ] = i;
    K1table[ K1TABLEWIDTH * ( 256 * j + tmp3 ) ] = tmp4;
  }
}

/* Initing our Really big table */
printf( "Initializing and clearing 64MB of RAM\n");
BigTable = malloc( 16777216 * sizeof(int) );
memset( BigTable, 0 , 16777216 * sizeof(int) );
if( K1table == NULL ) {
  printf( "Out of memory error. As if this wouldn't hurt\n" );
  exit( -1 );
}
tmp3 = 0;
printf( "Calculating big table. Wait, this takes time\n");
printf( "--------------------------------\n" );
for( i = 0 ; i < 16777216 ; i++ ) {
  if( (i & 0x07ffff) == 0 ) {
    printf( "#" );
    fflush( stdout );
  }
  tmp = (( i + i ) & 0x1fffff0 ) | 0x8 | ( i & 0x7 );
  for( j = 0 ; j < 5 ; j++ ) {
        tmp2=((((((( tmp>>3 )^tmp)>>1)^tmp)>>8)^tmp)>>5)&0xff;
        tmp =(tmp<<8)|tmp2;
        out2[j] = CSStab4[ tmp2 ];
  }
  j = ( out2[0] << 16 ) | ( out2[1] << 8 ) | out2[4];
  BigTable[j] = i;
}
printf( "\n" );

/*
 * We are done initing, now reverse hash
 */
printf( "Table init completed, now reversing hash\n\n" );
                                         33
tmp5 = A[0] ^ CSStab1[ A[1] ];
for( nStepA = 0 ; nStepA < 65536 ; nStepA ++ ) {
  lfsr1a = 0x100 | ( nStepA >> 8 );
  lfsr1b = nStepA & 0xff;

  /* Generate 5 first output bytes from lfsr1 */
  for( i = 0 ; i < 5 ; i++ ) {
    tmp = CSStab2[ lfsr1b ] ^ CSStab3[ lfsr1a ];
    lfsr1b = lfsr1a >> 1;
    lfsr1a = ((lfsr1a&1)<<8) ^ tmp;
    out1[ i ] = CSStab4[ tmp ];
  }

  /* cumpute and cache some variables */
  C[0] = nStepA >> 8;
  C[1] = nStepA & 0xff;
  tmp = A[3] ^ CSStab1[ A[4] ];
  tmp2 = CSStab1[ A[0] ];

  /* Search through all possible B[0] */
  for( nStepB = 0 ; nStepB < 256 ; nStepB++ ) {
    /* reverse parts of the mangling cipher */
    B[0] = nStepB;
    k[0] = CSStab1[ B[0] ] ^ C[0];
    B[4] = B[0] ^ k[0] ^ tmp2;
    k[4] = B[4] ^ tmp;
    nPossibleK1 = K1table[ K1TABLEWIDTH * (256 * B[0] + C[1]) ];

   /* Try out all possible values for k[1] */
   for( nTry = 0 ; nTry < nPossibleK1 ; nTry++ ) {
     k[1] = K1table[ K1TABLEWIDTH * (256 * B[0] + C[1]) + nTry + 1 ];
     B[1] = tmp5 ^ k[1];

      /* reconstruct output from LFSR2 */
      tmp3 = ( 0x100 + k[0] - out1[0] );
      out2[0] = tmp3 & 0xff;
      tmp3 = tmp3 & 0x100 ? 0x100 : 0xff;
      tmp3 = ( tmp3 + k[1] - out1[1] );
      out2[1] = tmp3 & 0xff;
      tmp3 = ( 0x100 + k[4] - out1[4] );
      out2[4] = tmp3 & 0xff; /* Can be 1 off */

      /* test first possible out2[4] */
      tmp4 = ( out2[0] << 16 ) | ( out2[1] << 8 ) | out2[4];
      tmp4 = BigTable[ tmp4 ];
      C[2] = tmp4 & 0xff;
      C[3] = ( tmp4 >> 8 ) & 0xff;
      C[4] = ( tmp4 >> 16 ) & 0xff;
      B[3] = CSStab1[ B[4] ] ^ k[4] ^ C[4];
      k[3] = A[2] ^ CSStab1[ A[3] ] ^ B[3];
      B[2] = CSStab1[ B[3] ] ^ k[3] ^ C[3];
                                           34
                k[2] = A[1] ^ CSStab1[ A[2] ] ^ B[2];
                if( ( B[1] ^ CSStab1[ B[2] ] ^ k[ 2 ] ) == C[ 2 ] ) investigate( &A[0] , &C[0] );

                /* Test second possible out2[4] */
                out2[4] = ( out2[4] + 0xff ) & 0xff;
                tmp4 = ( out2[0] << 16 ) | ( out2[1] << 8 ) | out2[4];
                tmp4 = BigTable[ tmp4 ];
                C[2] = tmp4 & 0xff;
                C[3] = ( tmp4 >> 8 ) & 0xff;
                C[4] = ( tmp4 >> 16 ) & 0xff;
                B[3] = CSStab1[ B[4] ] ^ k[4] ^ C[4];
                k[3] = A[2] ^ CSStab1[ A[3] ] ^ B[3];
                B[2] = CSStab1[ B[3] ] ^ k[3] ^ C[3];
                k[2] = A[1] ^ CSStab1[ A[2] ] ^ B[2];
                if( ( B[1] ^ CSStab1[ B[2] ] ^ k[ 2 ] ) == C[ 2 ] ) investigate( &A[0] , &C[0] );
            }

        }

    }

    free( K1table );
    free( BigTable );
    return( 0 );
}




                                                   35

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:19
posted:5/4/2011
language:English
pages:35