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.
- s/x/pack+/g;eval
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.
- while(read+STDIN,$_,2048)
The main loop of qrpff reads 2Kb 'sectors' of video data into
memory.
- @a=unx"C*",$_
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.
- @b=map{xB8,unxb8,chr($_^$a[--$h+84])}@ARGV;
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.
- $e=256|(ord$b[4])<<9|ord$b[3];
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.
- for@a[128..$#a]}print+x"C*",@a}
The table lookup and LFSR step are performed for each byte of
data in the sector, and the result is printed.