The Content Scrambling System (CSS)

The Basic Algorithm

The CSS State Machine

CSS uses a 42-bit state machine, which is initialized from a 40-bit [5-byte] key. The state machine uses two Linear Feedback Shift Registers - one of 17 bits, and one of 25 bits, plus a single carry bit. In this description I will use the symbols a through q for the bits of LFSR #1, the symbols A through Y for the bits of LFSR #2, and the symbol CC for the carry bit. The bits q and Y form the most-significant bits (MSBs) of the LFSRs.

 ``` LFSR #1 = q ponmlkji hgfedcba LFSR #2 = Y XWVUTSRQ PONMLKJI HGFEDCBA CARRY = CC```

The state machine also produces an 8-bit output every time it is run, which is fed to a data decryptor. This decryptor combines this output with a ciphertext byte to product an output byte. So one byte is decrypted every time the state machine is stepped.

Initializing the State Machine

The state machine is initialized from a 40-bit key. All bits are specified from this key, except for bits i and V, which are set to 1, and CC, which is set to zero.

 ``` KEY = jklmnopq abcdefgh QRSTUWXY IJKLMNOP ABCDEFGH```

Here, the bytes are specified left-to-right. Note that the bits are reversed in order compared to the LFSR bits. The initialization can be coded in C++ as follows:

 ``` u8 KEY; // input key LFSR1 = (reverse[KEY] << 9) // bits qponmlkj | 0x100 // bit i | reverse[KEY]; // bits hgfedcba LFSR2 = (reverse[KEY & 0x07] << 17) // bits YXW | 0x200000 // bit V | (reverse[KEY & 0xF8] << 16) // bits UTSRQ | (reverse[KEY] << 8) // bits PONMLKJI | reverse[KEY]; // bits HGFEDCBA CC = 0;```

Here, reverse is a table containing 256 entries, each the bit reversal of its index. So reverse[0x01] = 0x80, for instance.

Stepping the State Machine

The state machine steps forwards independently of the data input. This happens in one of four modes.

First, LFSR #1 and LFSR #2 roll forwards. This happens independently of the mode. Secondly, bits from the LFSRs are combined to form the input to the data decryptor and the new carry. This process does vary according to the mode.

In hardware, the first operation is done one bit at a time, and must be done 8 times for every input byte. Each LFSR is rotated right, and the bit coming in on the left is XORed with the values taken from a number of taps. LFSR #1 has one tap, and LFSR #2 has three:

 ``` new LFSR #1 = a qponmlkj ihgfedcb ^ o 00000000 00000000 new LFSR #2 = A YXWVUTSR QPONMLKJ IHGFEDCB ^ D 00000000 00000000 00000000 ^ E 00000000 00000000 00000000 ^ M 00000000 00000000 00000000```

When coding this in software, the 8 steps can be done in one. Now, each bit of the new LFSR value is calculated as the XOR of 4 bits of the old LFSR value:

 ``` new LFSR #1 = h gfedcbaq ponmlkji ^ e dcbaqpo0 00000000 ^ b aqpo0000 00000000 ^ p o0000000 00000000 new LFSR #2 = H GFEDCBAY XWVUTSRQ PONMLKJI ^ K JIHGFED0 00000000 00000000 ^ L KJIHGFE0 00000000 00000000 ^ T SRQPONM0 00000000 00000000```

This can be coded in C++ as follows:

 ``` // LFSR #1 // rotate LFSR #1 right 8 bits (4th term) LFSR1 = (LFSR1 << 9) | (LFSR1 >> 8); // isolate bits edcbaqpo in LFSR #1 unsigned long bits = LFSR1 & 0x03FC0; // form product (first 3 terms plus junk) unsigned long product = (bits << 3) ^ (bits << 6) ^ (bits << 9); // XOR in the product LFSR1 ^= product; // remove junk bits LFSR1 &= 0x1FFFF; // LFSR #2 // form left 8 bits of result unsigned long left8 = LFSR2 ^ (LFSR2 >> 3) ^ (LFSR2 >> 4) ^ (LFSR2 >> 12); // rotate LFSR #2 right 8 bits and combine with left 8 bits LFSR2 = (left8 << 17) | (LFSR2 >> 8) // remove junk bits LFSR2 &= 0x1FFFFFF;```

The new CC and the input to the data decryptor (LFSRBYTE) are calculated using an arithmetic sum operation with the operands being the top 8 bits of the new LFSRs. Each operand can be inverted, or not, giving rise to the four modes. The 8 bit output of this sum is fed to the data decryptor, and the carry of this sum becomes the new CC. The equations for this are as follows:

 ``` sum = qponmlkj ^ H1 + YXWVUTSR ^ H2 + CC new CC = sum LFSRBYTE = sum[7:0]```

Here, the value of H1 and H2 are either 0x00 or 0xFF depending on the mode. When decrypting data from a DVD file, H1 is 0xFF and H2 is 0x00 - this is mode 1. When using CSS to encrypt a challenge key, H1 and H2 are both 0xFF, which is mode 3.

This process can be performed in C++ code as follows:

 ``` unsigned char H1 = (mode & 1) ? 0xFF : 0x00; unsigned char H2 = (mode & 2) ? 0xFF : 0x00; unsigned long sum = ((LFSR1 >> 9) ^ H1) + ((LFSR2 >> 17) ^ H2) + CC; CC = sum >> 8; LFSRBYTE = sum & 0xFF;```

LFSRBYTE is then used in the various decryptors/encryptors to actually decrypt/encrypt the data.

[Back] [Home] [TinyTed]