structure ExCSS :>
sig
type bytevector = Word8.word Vector.vector
(* keys are 6 bytes *)
type key = bytevector
(* an example player key *)
val playerkey : key
(* takes encrypted disk key and player key,
returns decrypted disk key *)
val titlekey1 : key * key -> key
(* takes encrypted title key and disk key,
returns decrypted title key *)
val titlekey2 : key * key -> key
(* takes an encrypted title key and encrytped disk key,
returns a decrypted title key *)
val detitlekey : key * key -> key
(* takes a 2048-byte sector and decryption key,
returns decrypted sector *)
val descramble : bytevector * key -> bytevector
end =
struct
exception Unimplemented and Impossible
open Vector
(* functional vector modify *)
fun modify (v : 'a vector,
i : int,
a : 'a) : 'a vector =
mapi (fn (ii, aa) => if ii = i then a else aa) (v, 0, NONE)
structure W8 = Word8
structure W32 = Word32
type bytevector = W8.word Vector.vector
val w32 = W32.fromInt o W8.toInt
val w8 = W8.fromInt o W32.toIntX
type key = W8.word vector
val playerkey : bytevector =
fromList [0wx51, 0wx67, 0wx67, 0wxC5, 0wxE0, 0wx00]
local
val table1 = Vector.fromList [
0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b,
0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b,
0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f,
0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91,
0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75,
0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95,
0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11,
0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f,
0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b,
0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb,
0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f,
0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1,
0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15,
0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5,
0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71,
0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff]
val table2 = Vector.fromList [
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e,
0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c,
0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a,
0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,
0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55,
0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63,
0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71,
0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e,
0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,
0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa,
0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5,
0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1,
0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3]
in
fun tab0 0 = 5
| tab0 1 = 0
| tab0 2 = 1
| tab0 3 = 2
| tab0 4 = 3
| tab0 5 = 4
| tab0 6 = 0
| tab0 7 = 1
| tab0 8 = 2
| tab0 9 = 3
| tab0 10 = 4
| tab0 _ = raise Impossible
fun tab3 0 = 0wx00 : W32.word
| tab3 1 = 0wx24
| tab3 2 = 0wx49
| tab3 3 = 0wx6d
| tab3 4 = 0wx92
| tab3 5 = 0wxb6
| tab3 6 = 0wxdb
| tab3 7 = 0wxff
| tab3 n = tab3 (n mod 8)
(* substitutions above *)
fun tab1 n = W32.fromInt (Vector.sub (table1, n))
fun tab2 n = W32.fromInt (Vector.sub (table2, n))
(* reverse bits *)
fun tab4 n =
let
fun set i = W32.<<(0w1, Word.fromInt i)
fun b i = (if W32.andb(n, set i) > 0w0 then
set (7 - i) else 0w0)
in
b 0 + b 1 + b 2 + b 3 + b 4 + b 5 + b 6 + b 7
end
(* reverse bits, then not *)
fun tab5 n =
W32.xorb(tab4 n, 0wxFF)
val tab1w = tab1 o W32.toIntX
val tab2w = tab2 o W32.toIntX
val tab3w = tab3 o W32.toIntX
end
(* this functional takes a table as its
first parameter. It is used to generate
titlekey1 and titlekey2 *)
fun decode table (enc : key,
pk : key) : key =
let
fun im x = w32 (sub (pk, x))
val t1 = im 0 + 0w256
val t2 = im 1
val t3 = im 5 * (0w256*0w256*0w256) +
im 4 * (0w256*0w256) +
im 3 * (0w256) +
im 2
val t4 = im 2 mod 0w8
val t3 = (t3 + 0w4) * 0w2 - t4
fun l1 (_, 5, k) = Vector.fromList (rev k)
| l1 ((t1, t2, t3, t5), n, k) =
let
val t4 = W32.xorb (tab3w t1, tab2w t2)
val t2 = t1 div 0w2
val t1 = W32.xorb(W32.<< (W32.andb(t1, 0w1), 0w8), t4)
val t4 = tab4 t4
val t6 =
(W32.xorb(W32.xorb(W32.xorb (t3 div 0w8, t3) div 0w2, t3) div 0w256,
t3) div 0w32) mod 0w256
val t3 = W32.orb(t3 * 0w256, t6)
val t6 = table t6
val t5 = t5 + t6 + t4
val res = t5 mod 0w256
val t5 = t5 div 0w256
in
l1 ((t1, t2, t3, t5), n + 1, res :: k)
end
val k = l1 ((t1, t2, t3, 0w0), 0, nil)
fun l2 (~1, key) = key : W8.word vector
| l2 (n, key) =
l2 (n - 1,
modify (key, tab0 (n + 1),
W8.fromInt
(W32.toInt
(W32.xorb (sub (k, tab0 (n + 1)),
W32.xorb (tab1 (W8.toInt (sub (key,
tab0 (n + 1)))),
w32 (sub (key, tab0 n))))))))
in
(l2 (9, enc))
end
val titlekey1 = decode tab4
val titlekey2 = decode tab5
fun detitlekey (tkey : key, dkey : key) : key =
titlekey2 (tkey,
titlekey1 (playerkey,
dkey))
fun descramble (sector : W8.word vector,
dec_key : key) =
let
fun sec x = w32 (sub (sector, x))
fun key x = w32 (sub (dec_key, x))
val t1 = W32.orb(0wx100,W32.xorb(key 0, sec 0x54))
val t2 = W32.xorb(key 1, sec 0x55)
val t3 = W32.xorb
(key 5 * (0w256*0w256*0w256) +
key 4 * (0w256*0w256) +
key 3 * (0w256) +
key 2,
sec 0x59 * (0w256*0w256*0w256) +
sec 0x58 * (0w256*0w256) +
sec 0x57 * (0w256) +
sec 0x56)
val t4 = t3 mod 0w8
val t3 = (t3 + 0w4) * 0w2 - t4
fun foldme (_, b, ((t1, t2, t3, t5), l)) =
let
val t4 = W32.xorb(tab2w t2, tab3w t1)
val t2 = t1 div 0w2
val t1 = W32.xorb(W32.andb(t1, 0w1) * 0w256, t4)
val t4 = tab5 t4
val t6 =
(W32.xorb(W32.xorb(W32.xorb (t3 div 0w8, t3) div 0w2, t3) div 0w256,
t3) div 0w32) mod 0w256
val t3 = W32.orb(t3 * 0w256, t6)
val t6 = tab4 t6
val t5 = t4 + t5 + t6
in
( (t1, t2, t3, t5 div 0w256),
W8.xorb(w8 (tab1 (W8.toInt b)),
w8 t5) :: l )
end
in
Vector.concat [Vector.extract (sector, 0, SOME 0x80),
Vector.fromList (rev (#2
(Vector.foldli foldme
((t1, t2, t3, 0w0), nil)
(sector, 0x80, NONE))))]
end
end