Decrypting Stream Data (Mode 1)
A DVD sector contains 2048 bytes (the same as a CD-ROM sector). Each sector has an MPEG-2 PACK header
which is followed by either stream data (MPEG-2, AC-3, etc.) or other information (PCI and DSI). An
introduction to this top-level format can be found here, or
in Part 1 of the MPEG-2 specification (but note that DVD uses 2048-byte PACKs which is larger than the
official maximum).
If a sector contains stream data, the PACK header is followed by a stream header which contains 2 bits
for the encryption type. These bits are set to 00 for no encryption, and 01 for CSS encryption. (According
to the source for css-auth, 10 is an unknown/reserved code and 11 is CPRM encryption).
Note that it is incorrect to look at these bits if the PACK is not stream data - most (all?)
open-source CSS decryptors fail in this respect. Non-stream data can never be encrypted, since it lacks
the header which specifies the encryption type.
Once you have a sector which needs decrypting using CSS, and the correct title key, the procedure is as follows:
- XOR the title key with a "salt" sequence - this is the bytes at offset 0x54 to 0x58 in the sector
- Initialize LFSR #1, LFSR #2 and CC
- Decrypt bytes 0x080 to 0x7FF in the sector, in that order
The LFSRs are run in mode 1 (H1 = 0xFF, H2 = 0x00) and each byte is decrypted using the following algorithm:
P = TABLE[C] ^ LFSRBYTE
This decryption algorithm can be specified in C++ as follows:
unsigned char salted_key[5];
for (int ii = 0; ii < 5; ii++)
{
salted_key[ii] = key[ii] ^ sector[0x54 + ii];
}
InitLFSRs(salted_key);
for (int ii = 0x080; ii < 0x800; ii++)
{
sector[ii] = css_table[sector[ii]] ^ GetLFSRBYTE(0xFF, 0x00);
}
And the CSS table is this:
33 73 3B 26 63 23 6B 76 3E 7E 36 2B 6E 2E 66 7B
D3 93 DB 06 43 03 4B 96 DE 9E D6 0B 4E 0E 46 9B
57 17 5F 82 C7 87 CF 12 5A 1A 52 8F CA 8A C2 1F
D9 99 D1 00 49 09 41 90 D8 98 D0 01 48 08 40 91
3D 7D 35 24 6D 2D 65 74 3C 7C 34 25 6C 2C 64 75
DD 9D D5 04 4D 0D 45 94 DC 9C D4 05 4C 0C 44 95
59 19 51 80 C9 89 C1 10 58 18 50 81 C8 88 C0 11
D7 97 DF 02 47 07 4F 92 DA 9A D2 0F 4A 0A 42 9F
53 13 5B 86 C3 83 CB 16 5E 1E 56 8B CE 8E C6 1B
B3 F3 BB A6 E3 A3 EB F6 BE FE B6 AB EE AE E6 FB
37 77 3F 22 67 27 6F 72 3A 7A 32 2F 6A 2A 62 7F
B9 F9 B1 A0 E9 A9 E1 F0 B8 F8 B0 A1 E8 A8 E0 F1
5D 1D 55 84 CD 8D C5 14 5C 1C 54 85 CC 8C C4 15
BD FD B5 A4 ED AD E5 F4 BC FC B4 A5 EC AC E4 F5
39 79 31 20 69 29 61 70 38 78 30 21 68 28 60 71
B7 F7 BF A2 E7 A7 EF F2 BA FA B2 AF EA AA E2 FF
Calculating the Response to a Challenge (Mode 3)
The DVD challenge-response protocol is used by a DVD player to authenticate itself with a drive (in theory it also
works to authenticate the drive with the DVD player, although a player could easily not care).
The protocol uses three different key types and 32 different variants to calculate a 5-byte response
from a 10-byte challenge. The key types are called KEY1, KEY2 and BUSKEY. See Drive Authentication
for details of how these keys are used.
The calculation procedure works as follows:
- The challenge string is permuted (rearranged) depending on the key type
- A CSS key is created from the first 5 bytes of the permuted string
- The key is salted with the constant sequence F4 10 45 A3 E2 and the LFSRs are initialized
- The response is initialized from the last 5 bytes of the permuted string
- A mix byte is determined depending on the key type and the CSS variant
- The response is scrambled six times using the LFSRs running in mode 3 (H1 = H2 = 0xFF)
The scrambling function uses three primitives, which I call "mix", "xor" and "mess". These are easiest to describe directly in C++:
void mix(unsigned char RSP[5], unsigned char MIXBYTE)
{
unsigned char lastbyte = 0;
for (int ii = 0; ii < 5; ii++)
{
unsigned char temp = mix1[RSP[ii] ^ GetLFSRBYTE(0xFF, 0xFF)];
temp = mix2[temp ^ MIXBYTE] ^ lastbyte;
lastbyte = RSP[ii];
RSP[ii] = temp;
}
}
void xor(unsigned char RSP[5])
{
RSP[0] ^= RSP[4];
}
void mess(unsigned char RSP[5])
{
for (int ii = 0; ii < 5; ii++)
{
RSP[ii] = mess[RSP[ii]];
}
}
Once these functions are derived, the total response calculation is as follows:
// permute challenge string into key and initial response
for (int ii = 0; ii < 5; ii++)
{
key[ii] = challenge[challenge_permute[KEYTYPE][ii]] ^ salt[ii];
response[ii] = challenge[challenge_permute[KEYTYPE][ii + 5]];
}
InitLFSRs(key);
unsigned char MIXBYTE = variant[translate_variant[KEYTYPE][VARIANT]];
// step 1
mix(response, MIXBYTE);
xor(response);
// step 2
mix(response, MIXBYTE);
xor(response);
// step 3
mix(response, MIXBYTE);
mess(response)
xor(response);
// step 4
mix(response, MIXBYTE);
mess(response)
xor(response);
// step 5
mix(response, MIXBYTE);
xor(response);
// step 6
mix(response, MIXBYTE);
As you can see, the algorithm is complicated, and uses more tables. These tables are defined here:
salt
F4 10 45 A3 E2
mix1
C4 CD CE CB C8 C9 CA CF CC C5 C6 C3 C0 C1 C2 C7
14 1D 1E 1B 18 19 1A 1F 1C 15 16 13 10 11 12 17
24 2D 2E 2B 28 29 2A 2F 2C 25 26 23 20 21 22 27
34 3D 3E 3B 38 39 3A 3F 3C 35 36 33 30 31 32 37
04 0D 0E 0B 08 09 0A 0F 0C 05 06 03 00 01 02 07
D4 DD DE DB D8 D9 DA DF DC D5 D6 D3 D0 D1 D2 D7
E4 ED EE EB E8 E9 EA EF EC E5 E6 E3 E0 E1 E2 E7
F4 FD FE FB F8 F9 FA FF FC F5 F6 F3 F0 F1 F2 F7
44 4D 4E 4B 48 49 4A 4F 4C 45 46 43 40 41 42 47
94 9D 9E 9B 98 99 9A 9F 9C 95 96 93 90 91 92 97
A4 AD AE AB A8 A9 AA AF AC A5 A6 A3 A0 A1 A2 A7
B4 BD BE BB B8 B9 BA BF BC B5 B6 B3 B0 B1 B2 B7
84 8D 8E 8B 88 89 8A 8F 8C 85 86 83 80 81 82 87
54 5D 5E 5B 58 59 5A 5F 5C 55 56 53 50 51 52 57
64 6D 6E 6B 68 69 6A 6F 6C 65 66 63 60 61 62 67
74 7D 7E 7B 78 79 7A 7F 7C 75 76 73 70 71 72 77
mix2
C4 24 14 34 CE 2E 1E 3E CD 2D 1D 3D CB 2B 1B 3B
44 A4 94 B4 4E AE 9E BE 4D AD 9D BD 4B AB 9B BB
04 E4 D4 F4 0E EE DE FE 0D ED DD FD 0B EB DB FB
84 64 54 74 8E 6E 5E 7E 8D 6D 5D 7D 8B 6B 5B 7B
CC 2C 1C 3C C6 26 16 36 C5 25 15 35 C3 23 13 33
4C AC 9C BC 46 A6 96 B6 45 A5 95 B5 43 A3 93 B3
0C EC DC FC 06 E6 D6 F6 05 E5 D5 F5 03 E3 D3 F3
8C 6C 5C 7C 86 66 56 76 85 65 55 75 83 63 53 73
C8 28 18 38 CA 2A 1A 3A C9 29 19 39 CF 2F 1F 3F
48 A8 98 B8 4A AA 9A BA 49 A9 99 B9 4F AF 9F BF
08 E8 D8 F8 0A EA DA FA 09 E9 D9 F9 0F EF DF FF
88 68 58 78 8A 6A 5A 7A 89 69 59 79 8F 6F 5F 7F
C0 20 10 30 C2 22 12 32 C1 21 11 31 C7 27 17 37
40 A0 90 B0 42 A2 92 B2 41 A1 91 B1 47 A7 97 B7
00 E0 D0 F0 02 E2 D2 F2 01 E1 D1 F1 07 E7 D7 F7
80 60 50 70 82 62 52 72 81 61 51 71 87 67 57 77
mess
00 81 03 82 06 87 05 84 0C 8D 0F 8E 0A 8B 09 88
18 99 1B 9A 1E 9F 1D 9C 14 95 17 96 12 93 11 90
30 B1 33 B2 36 B7 35 B4 3C BD 3F BE 3A BB 39 B8
28 A9 2B AA 2E AF 2D AC 24 A5 27 A6 22 A3 21 A0
60 E1 63 E2 66 E7 65 E4 6C ED 6F EE 6A EB 69 E8
78 F9 7B FA 7E FF 7D FC 74 F5 77 F6 72 F3 71 F0
50 D1 53 D2 56 D7 55 D4 5C DD 5F DE 5A DB 59 D8
48 C9 4B CA 4E CF 4D CC 44 C5 47 C6 42 C3 41 C0
C0 41 C3 42 C6 47 C5 44 CC 4D CF 4E CA 4B C9 48
D8 59 DB 5A DE 5F DD 5C D4 55 D7 56 D2 53 D1 50
F0 71 F3 72 F6 77 F5 74 FC 7D FF 7E FA 7B F9 78
E8 69 EB 6A EE 6F ED 6C E4 65 E7 66 E2 63 E1 60
A0 21 A3 22 A6 27 A5 24 AC 2D AF 2E AA 2B A9 28
B8 39 BB 3A BE 3F BD 3C B4 35 B7 36 B2 33 B1 30
90 11 93 12 96 17 95 14 9C 1D 9F 1E 9A 1B 99 18
88 09 8B 0A 8E 0F 8D 0C 84 05 87 06 82 03 81 00
challenge_permute
KEY1 01 05 03 00 07 04 02 09 06 08
KEY2 07 09 05 02 04 01 06 00 08 03
BUSKEY 00 08 03 01 07 02 04 06 09 05
variant
00 01 04 05 10 11 14 15 20 21 24 25 30 31 34 35
80 81 84 85 90 91 94 95 A0 A1 A4 A5 B0 B1 B4 B5
translate_variant
KEY1 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
KEY2 0A 08 0E 0C 0B 09 0F 0D 1A 18 1E 1C 1B 19 1F 1D
02 00 06 04 03 01 07 05 12 10 16 14 13 11 17 15
BUSKEY 12 1A 16 1E 02 0A 06 0E 10 18 14 1C 00 08 04 0C
13 1B 17 1F 03 0B 07 0F 11 19 15 1D 01 09 05 0D
The large tables are made up of simple bit operations on the input byte, but this isn't very interesting and I won't go into details.