qrpff Explained

This program, called qrpff, decodes CSS, the DVD Content Scrambling System. To understand qrpff, we first need to understand CSS.

The heart of CSS is something called a linear feedback shift register (LFSR). An LFSR is a sequence of bits. At each step in the algorithm, certain of the bits are combined to make an output bit. The output bit is then appended to the sequence on the right, and the leftmost bit in the sequence is discarded to make room.

The output of an LFSR isn't random, but it has many of the properties of a random sequence.

CSS uses two LFSRs. One is 17 bits long and the other is 25 bits long. The video data is combined with the outputs of the two LFSRs to yield the encrypted data on the DVD. When the DVD player combines the encrypted data with the LFSR output, the LFSR part cancels out, yielding the original data.


qrpff itself is written in a deliberately obfuscated way. Most of the code is actually contained in a string. In the string, pack is abbreviated to x and unpack to unx. This part replaces all the xes with packs, and then compiles and executes the result.


The main loop of qrpff reads 2Kb 'sectors' of video data into memory.


Each sector contains a sector key which is used to initialize the LFSRs. This part extracts the sector key and stores the bits in the variable @a.


The sector key is encoded too---it must first be combined with a title key that is the same for every sector in the entire movie. This section does that. A DVD player would get the title key by combining its secret built-in 'player key' with an encrypted title key on the DVD itself. qrpff assumes that the decrypted title key was supplied as an argument when qrpff was run.

$_=unxb24,join"", and s/...$/1$&/;$d=unxV,xb25,$_;

This extracts 24 bits of the sector key to set up the larger LFSR, which is in $d.


This extracts 16 bits of the sector key to set up the smaller LFSR, stored in $e.

$d=$d>>8^($f=($t=255)&($d>>12^$d>>4^$d^$d/8))<<17, $e=$e>>8^($t&($g=($q=$e>>14&7^$e)^$q*8^$q<<6))<<9

This section operates the two LFSRs. The important parts are saved in variables $f and $g.

(map{$_%16or$t^=$c^=($m=(11,10,116,100,11,122,20,100)[$_/16%8])&110;$t ^=(72,@z=(64,72,$a^=12*($_%16-2?0:$m&17)),$b^=$_%64?12:0,@z)[$_%8]}(16..271))

The other part of the decryption process involves transforming the bytes by looking up the values in a table. This is just like the substitution ciphers you might have used when you were a kid, where a was replaced by z, b by y, and so on---except the rule is less straightforward. This part computes the lookup table.

$_= and [$_]^(($h>>=8)+=$f+(~$g&$t))

The transformed byte is combined with the LFSR output, which is in $f and $g.


The table lookup and LFSR step are performed for each byte of data in the sector, and the result is printed.