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.
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,
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.