1 /*****************************************************************************
2 * dvd_css.c: Functions for DVD authentification and unscrambling
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_css.c,v 1.4 2001/02/09 03:51:42 stef Exp $
7 * Author: Stéphane Borel <stef@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
29 #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
35 #include <netinet/in.h>
37 # include <sys/ioctl.h>
39 #ifdef HAVE_SYS_DVDIO_H
40 # include <sys/dvdio.h>
43 # include <linux/cdrom.h>
52 #include "input_dvd.h"
53 #include "css_table.h"
55 /*****************************************************************************
57 *****************************************************************************/
59 unsigned int pi_css_tab0[11]={ 5, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 };
61 unsigned char pi_css_tab1[256]=
62 { 0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76,
63 0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b,
64 0xd3, 0x93, 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96,
65 0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b,
66 0x57, 0x17, 0x5f, 0x82, 0xc7, 0x87, 0xcf, 0x12,
67 0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f,
68 0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, 0x41, 0x90,
69 0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91,
70 0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74,
71 0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75,
72 0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94,
73 0xdc, 0x9c, 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95,
74 0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10,
75 0x58, 0x18, 0x50, 0x81, 0xc8, 0x88, 0xc0, 0x11,
76 0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92,
77 0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, 0x42, 0x9f,
78 0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16,
79 0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b,
80 0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6,
81 0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb,
82 0x37, 0x77, 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72,
83 0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f,
84 0xb9, 0xf9, 0xb1, 0xa0, 0xe9, 0xa9, 0xe1, 0xf0,
85 0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1,
86 0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, 0xc5, 0x14,
87 0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15,
88 0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4,
89 0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5,
90 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70,
91 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71,
92 0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2,
93 0xba, 0xfa, 0xb2, 0xaf, 0xea, 0xaa, 0xe2, 0xff };
95 unsigned char pi_css_tab2[256]=
96 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
97 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
98 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
99 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
100 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
101 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
102 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
103 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
104 0x49, 0x48, 0x4b, 0x4a, 0x4d, 0x4c, 0x4f, 0x4e,
105 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
106 0x5b, 0x5a, 0x59, 0x58, 0x5f, 0x5e, 0x5d, 0x5c,
107 0x52, 0x53, 0x50, 0x51, 0x56, 0x57, 0x54, 0x55,
108 0x6d, 0x6c, 0x6f, 0x6e, 0x69, 0x68, 0x6b, 0x6a,
109 0x64, 0x65, 0x66, 0x67, 0x60, 0x61, 0x62, 0x63,
110 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
111 0x76, 0x77, 0x74, 0x75, 0x72, 0x73, 0x70, 0x71,
112 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
113 0x9b, 0x9a, 0x99, 0x98, 0x9f, 0x9e, 0x9d, 0x9c,
114 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
115 0x89, 0x88, 0x8b, 0x8a, 0x8d, 0x8c, 0x8f, 0x8e,
116 0xb6, 0xb7, 0xb4, 0xb5, 0xb2, 0xb3, 0xb0, 0xb1,
117 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
118 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3,
119 0xad, 0xac, 0xaf, 0xae, 0xa9, 0xa8, 0xab, 0xaa,
120 0xdb, 0xda, 0xd9, 0xd8, 0xdf, 0xde, 0xdd, 0xdc,
121 0xd2, 0xd3, 0xd0, 0xd1, 0xd6, 0xd7, 0xd4, 0xd5,
122 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,
123 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
124 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
125 0xf6, 0xf7, 0xf4, 0xf5, 0xf2, 0xf3, 0xf0, 0xf1,
126 0xed, 0xec, 0xef, 0xee, 0xe9, 0xe8, 0xeb, 0xea,
127 0xe4, 0xe5, 0xe6, 0xe7, 0xe0, 0xe1, 0xe2, 0xe3
130 unsigned char pi_css_tab3[512]=
131 { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
132 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
133 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
134 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
135 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
136 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
137 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
138 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
139 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
140 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
141 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
142 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
143 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
144 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
145 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
146 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
147 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
148 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
149 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
150 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
151 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
152 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
153 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
154 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
155 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
156 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
157 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
158 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
159 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
160 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
161 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
162 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
163 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
164 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
165 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
166 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
167 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
168 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
169 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
170 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
171 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
172 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
173 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
174 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
175 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
176 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
177 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
178 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
179 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
180 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
181 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
182 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
183 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
184 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
185 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
186 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
187 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
188 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
189 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
190 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
191 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
192 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
193 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
194 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff };
196 unsigned char pi_css_tab4[256]=
197 { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
198 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
199 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
200 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
201 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
202 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
203 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
204 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
205 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
206 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
207 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
208 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
209 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
210 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
211 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
212 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
213 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
214 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
215 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
216 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
217 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
218 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
219 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
220 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
221 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
222 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
223 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
224 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
225 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
226 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
227 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
228 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff };
230 unsigned char pi_css_tab5[256]=
231 { 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
232 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
233 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
234 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
235 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
236 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
237 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
238 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
239 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
240 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
241 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
242 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
243 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
244 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
245 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
246 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
247 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
248 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
249 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
250 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
251 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
252 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
253 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
254 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
255 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
256 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
257 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
258 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
259 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
260 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
261 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
262 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00 };
268 /*****************************************************************************
269 * CSSGetASF : Get Authentification success flag
270 *****************************************************************************/
271 int CSSGetASF( int i_fd )
275 ai.type = DVD_LU_SEND_ASF;
278 for( ai.lsasf.agid = 0 ; ai.lsasf.agid < 4 ; ai.lsasf.agid++ )
280 if( !( ioctl( i_fd, DVD_AUTH, &ai ) ) )
282 intf_Msg("CSS: %sAuthenticated\n", (ai.lsasf.asf) ? "" : "not");
286 intf_ErrMsg( "CSS Error: GetASF" );
290 /*****************************************************************************
291 * CSSCryptKey : shuffles bits and unencrypt keys.
293 * i_key_type : 0->key1, 1->key2, 2->buskey.
294 * i_varient : between 0 and 31.
295 *****************************************************************************/
296 static void CSSCryptKey( int i_key_type, int i_varient,
297 u8 const * pi_challenge, u8* pi_key )
299 /* Permutation table for challenge */
300 u8 ppi_perm_challenge[3][10] =
301 { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 },
302 { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 },
303 { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } };
304 /* Permutation table for varient table */
305 u8 ppi_perm_varient[2][32] =
306 { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d,
307 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d,
308 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05,
309 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 },
310 { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e,
311 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c,
312 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f,
313 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } };
314 u8 pi_css_secret[5] = { 0xE2, 0xA3, 0x45, 0x10, 0xF4 };
315 u8 pi_css_varients[32] =
316 { 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
317 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
318 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
319 0xA0, 0xA1, 0xA4, 0xA5, 0xB0, 0xB1, 0xB4, 0xB5 };
333 for( i=0 ; i<10 ; i++ )
335 pi_scratch[i] = pi_challenge[ppi_perm_challenge[i_key_type][i]];
337 i_css_varient = i_key_type == 0 ? i_varient
338 : ppi_perm_varient[i_key_type-1][i_varient];
340 for( i=0 ; i<5 ; i++ )
342 pi_tmp1[i] = pi_scratch[5+i] ^ pi_css_secret[i];
345 /* In order to ensure that the LFSR works we need to ensure that the
346 * initial values are non-zero. Thus when we initialise them from
347 * the seed, we ensure that a bit is set.
349 i_lfsr0 = ( pi_tmp1[0] << 17 ) | ( pi_tmp1[1] << 9 ) |
350 ( ( pi_tmp1[2] & ~7 ) << 1 ) | 8 | (pi_tmp1[2] & 7);
353 * reverse lfsr0/1 to simplify calculation in loop
355 i_lfsr0 = ( pi_reverse[i_lfsr0 & 0xff] << 17 ) |
356 ( pi_reverse[( i_lfsr0 >> 8 ) & 0xff] << 9 ) |
357 ( pi_reverse[( i_lfsr0 >> 16 ) & 0xff] << 1) |
360 i_lfsr1 = ( pi_reverse[pi_tmp1[4]] << 9 ) | 0x100 |
361 ( pi_reverse[pi_tmp1[3]] );
363 i_index = sizeof( pi_bits );
366 i_lfsr0_o = ( i_lfsr0 >> 12) ^ ( i_lfsr0 >> 4) ^
367 ( i_lfsr0 >> 3) ^ i_lfsr0;
369 i_lfsr1_o = ( ( i_lfsr1 >> 14 ) & 7) ^ i_lfsr1;
370 i_lfsr1_o ^= ( i_lfsr1_o << 3 ) ^ ( i_lfsr1_o << 6 );
372 i_lfsr1 = ( i_lfsr1 >> 8) ^ ( i_lfsr1_o << 9);
373 i_lfsr0 = ( i_lfsr0 >> 8 ) ^ ( i_lfsr0_o << 17);
375 i_lfsr0_o = ~i_lfsr0_o;
376 i_lfsr1_o = ~i_lfsr1_o;
378 i_val += i_lfsr0_o + i_lfsr1_o;
380 pi_bits[--i_index] = i_val & 0xFF;
383 } while( i_index > 0 );
385 i_css_varient = pi_css_varients[i_css_varient];
387 intf_WarnMsg( 3, "CSS varient: %d\n", i_css_varient );
392 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_scratch[i] )
394 i_index = pi_bits[25+i] ^ pi_scratch[i];
395 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
396 pi_tmp1[i] = pi_css_mangle2[i_index] ^ i_term;
398 pi_tmp1[4] ^= pi_tmp1[0];
399 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
401 i_index = pi_bits[20+i] ^ pi_tmp1[i];
402 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
403 pi_tmp2[i] = pi_css_mangle2[i_index] ^ i_term;
405 pi_tmp2[4] ^= pi_tmp2[0];
406 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
408 i_index = pi_bits[15+i] ^ pi_tmp2[i];
409 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
410 i_index = pi_css_mangle2[i_index] ^ i_term;
411 pi_tmp1[i] = pi_css_mangle0[i_index];
413 pi_tmp1[4] ^= pi_tmp1[0];
414 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
416 i_index = pi_bits[10+i] ^ pi_tmp1[i];
417 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
418 i_index = pi_css_mangle2[i_index] ^ i_term;
419 pi_tmp2[i] = pi_css_mangle0[i_index];
421 pi_tmp2[4] ^= pi_tmp2[0];
422 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
424 i_index = pi_bits[5+i] ^ pi_tmp2[i];
425 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
426 pi_tmp1[i] = pi_css_mangle2[i_index] ^ i_term;
428 pi_tmp1[4] ^= pi_tmp1[0];
430 for( i=5, i_term=0 ; --i>=0 ; i_term=pi_tmp1[i] )
432 i_index = pi_bits[i] ^ pi_tmp1[i];
433 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
434 pi_key[i] = pi_css_mangle2[i_index] ^ i_term;
440 static int CSSAuthHost( dvd_authinfo *ai, disc_t *disc )
446 /* Host data receive (host changes state) */
447 case DVD_LU_SEND_AGID:
449 ai->type = DVD_HOST_SEND_CHALLENGE;
452 case DVD_LU_SEND_KEY1:
454 for( i=0; i<KEY_SIZE; i++ )
456 disc->pi_key1[i] = ai->lsk.key[4-i];
459 for( i=0; i<32; ++i )
461 CSSCryptKey( 0, i, disc->pi_challenge,
462 disc->pi_key_check );
464 if( memcmp( disc->pi_key_check,
465 disc->pi_key1, KEY_SIZE ) == 0 )
467 intf_WarnMsg( 3, "CSS: Drive Authentic - using varient %d\n", i);
469 ai->type = DVD_LU_SEND_CHALLENGE;
473 // intf_ErrMsg( "Drive would not Authenticate" );
474 // ai->type = DVD_AUTH_FAILURE;
478 case DVD_LU_SEND_CHALLENGE:
479 for( i=0; i<10; ++i )
481 disc->pi_challenge[i] = ai->hsc.chal[9-i];
483 CSSCryptKey( 1, disc->i_varient, disc->pi_challenge,
485 ai->type = DVD_HOST_SEND_KEY2;
489 case DVD_HOST_SEND_CHALLENGE:
490 for( i=0; i<10; ++i )
492 ai->hsc.chal[9-i] = disc->pi_challenge[i];
494 /* Returning data, let LU change state */
497 case DVD_HOST_SEND_KEY2:
498 for( i=0; i<KEY_SIZE; ++i )
500 ai->hsk.key[4-i] = disc->pi_key2[i];
502 /* Returning data, let LU change state */
506 intf_ErrMsg( "CSS: Got invalid state %d", ai->type );
513 /*****************************************************************************
514 * CSSCracker : title key decryption by cracking
515 *****************************************************************************/
517 // FIXME : adapt to vlc
518 #define KEYSTREAMBYTES 10
520 static unsigned char invtab4[256];
522 static int CSScracker( int StartVal,
523 unsigned char* pCrypted,
524 unsigned char* pDecrypted,
525 DVD_key_t *StreamKey,
528 unsigned char MyBuf[10];
529 unsigned int t1,t2,t3,t4,t5,t6;
531 unsigned int vCandidate;
539 MyBuf[i] = pi_css_tab1[pCrypted[i]] ^ pDecrypted[i];
542 /* Test that CSStab4 is a permutation */
543 memset( invtab4, 0, 256 );
544 for( i = 0 ; i < 256 ; i++ )
546 invtab4[ pi_css_tab4[i] ] = 1;
549 for (i = 0 ; i < 256 ; i++)
551 if (invtab4[ i ] != 1)
553 intf_ErrMsg( "CSS: Permutation error" );
558 /* initialize the inverse of table4 */
559 for( i = 0 ; i < 256 ; i++ )
561 invtab4[ pi_css_tab4[i] ] = i;
564 for( nTry = StartVal ; nTry < 65536 ; nTry++ )
566 t1 = nTry >> 8 | 0x100;
568 t3 = 0; /* not needed */
571 /* iterate cipher 4 times to reconstruct LFSR2 */
572 for( i = 0 ; i < 4 ; i++ )
574 /* advance LFSR1 normaly */
575 t4=pi_css_tab2[t2]^pi_css_tab3[t1];
583 t6 = ( t6 + 0xff )&0x0ff;
592 /* feed / advance t3 / t5 */
599 /* iterate 6 more times to validate candidate key */
600 for( ; i < KEYSTREAMBYTES ; i++ )
602 t4=pi_css_tab2[t2]^pi_css_tab3[t1];
606 t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
610 if( (t5 & 0xff) != MyBuf[i] ) break;
614 if( i == KEYSTREAMBYTES )
616 /* Do 4 backwards steps of iterating t3 to deduce initial state */
618 for( i = 0 ; i < 4 ; i++ )
622 /* easy to code, and fast enough bruteforce
623 * search for byte shifted in */
624 for( j=0 ; j < 256 ; j++ )
626 t3 = (t3 & 0x1ffff) | ( j << 17 );
627 t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
628 if( t6 == t1 ) break;
631 // printf( "Candidate: t1=%03x t2=%02x t3=%08x\n", 0x100|(nTry>>8),nTry&0x0ff, t3 );
636 if ( ((t4+t5)*2 + 8 - ((t4+t5)&7))==t3 )
638 (*pkey)[0] = nTry>>8;
639 (*pkey)[1] = nTry & 0xFF;
640 (*pkey)[2] = ((t4+t5) >> 0) & 0xFF;
641 (*pkey)[3] = ((t4+t5) >> 8) & 0xFF;
642 (*pkey)[4] = ((t4+t5) >> 16) & 0xFF;
651 (*pkey)[0] ^= (*StreamKey)[0];
652 (*pkey)[1] ^= (*StreamKey)[1];
653 (*pkey)[2] ^= (*StreamKey)[2];
654 (*pkey)[3] ^= (*StreamKey)[3];
655 (*pkey)[4] ^= (*StreamKey)[4];
662 * Authentication and keys
665 /*****************************************************************************
666 * CSSTest : check if the disc is encrypted or not
667 *****************************************************************************/
668 int CSSTest( int i_fd )
672 dvd.type = DVD_STRUCT_COPYRIGHT;
673 dvd.copyright.layer_num = 0;
675 if( ioctl( i_fd, DVD_READ_STRUCT, &dvd ) < 0 )
677 intf_ErrMsg( "DVD ioctl error" );
681 return dvd.copyright.cpst;
684 /*****************************************************************************
685 * CSSInit : CSS Structure initialisation and DVD authentication.
686 *****************************************************************************/
688 css_t CSSInit( int i_fd )
698 memset( &ai, 0, sizeof(ai) );
700 // if (CSSGetASF (i_fd))
704 /* Init sequence, request AGID */
705 for( i=1; (i<4)&&(rv== -1) ; ++i )
707 intf_WarnMsg( 3, "CSS: Request AGID [%d]...", i );
708 ai.type = DVD_LU_SEND_AGID;
710 rv = ioctl (i_fd, DVD_AUTH, &ai);
713 intf_ErrMsg( "CSS: N/A, invalidating" );
714 ai.type = DVD_INVALIDATE_AGID;
716 ioctl( i_fd, DVD_AUTH, &ai );
721 intf_ErrMsg( "CSS: Cannot get AGID\n" );
724 for( i=0 ; i<10; ++i )
726 css.disc.pi_challenge[i] = i;
729 /* Send AGID to host */
730 if( CSSAuthHost(&ai, &(css.disc) )<0 )
732 intf_ErrMsg( "CSS Error: Send AGID to host failed" );
736 /* Get challenge from host */
737 if( CSSAuthHost( &ai, &(css.disc) )<0)
739 intf_ErrMsg( "CSS Error: Get challenge from host failed" );
742 css.i_agid = ai.lsa.agid;
744 /* Send challenge to LU */
745 if( ioctl( i_fd, DVD_AUTH, &ai )<0 )
747 intf_ErrMsg( "CSS Error: Send challenge to LU failed ");
751 /* Get key1 from LU */
752 if( ioctl( i_fd, DVD_AUTH, &ai )<0)
754 intf_ErrMsg( "CSS Error: Get key1 from LU failed ");
758 /* Send key1 to host */
759 // if (_CSSAuthHost(&ai, disc) < 0) {
760 if( CSSAuthHost( &ai, &(css.disc) )<0)
762 intf_ErrMsg( "CSS Error: Send key1 to host failed" );
766 /* Get challenge from LU */
767 if( ioctl( i_fd, DVD_AUTH, &ai)<0 )
769 intf_ErrMsg( "CSS Error: Get challenge from LU failed ");
773 /* Send challenge to host */
774 if( CSSAuthHost( &ai, &(css.disc) )<0 )
776 intf_ErrMsg( "CSS Error: Send challenge to host failed");
780 /* Get key2 from host */
781 if( CSSAuthHost( &ai, &(css.disc) )<0 )
783 intf_ErrMsg( "CSS Error: Get key2 from host failed" );
787 /* Send key2 to LU */
788 if( ioctl( i_fd, DVD_AUTH, &ai )<0 )
790 intf_ErrMsg( "CSS Error: Send key2 to LU failed (expected)" );
794 if( ai.type == DVD_AUTH_ESTABLISHED )
796 intf_WarnMsg( 3, "DVD is authenticated");
798 else if( ai.type == DVD_AUTH_FAILURE )
800 intf_ErrMsg("CSS Error: DVD authentication failed");
803 memcpy( css.disc.pi_challenge, css.disc.pi_key1, KEY_SIZE );
804 memcpy( css.disc.pi_challenge+KEY_SIZE, css.disc.pi_key2, KEY_SIZE );
805 CSSCryptKey( 2, css.disc.i_varient,
806 css.disc.pi_challenge,
807 css.disc.pi_key_check );
809 intf_WarnMsg( 3, "CSS: Received Session Key\n" );
816 // if (CSSGetASF (i_fd) < 0)
819 dvd.type = DVD_STRUCT_DISCKEY;
820 dvd.disckey.agid = css.i_agid;
821 memset( dvd.disckey.value, 0, 2048 );
823 if( ioctl( i_fd, DVD_READ_STRUCT, &dvd )<0 )
825 intf_ErrMsg( "CSS Error: Could not read Disc Key" );
830 for (i=0; i<sizeof dvd.disckey.value; i++)
832 dvd.disckey.value[i] ^= css.disc.pi_key_check[4 - (i % KEY_SIZE)];
834 memcpy( css.disc.pi_key_check, dvd.disckey.value, 2048 );
836 // if (CSSGetASF (i_fd) < 0)
845 /*****************************************************************************
846 * CSSGetKeys : get the disc key of the media en the dvd device, and then
848 * The DVD should have been opened before.
849 *****************************************************************************/
853 int CSSGetKeys( css_t * p_css )
858 * css_auth/libcss method from Derek Fawcus.
859 * Get encrypted keys with ioctls and decrypt them
860 * with cracked player keys
865 if( CSSGetASF( p_css->i_fd ) < 0 )
871 dvd.type = DVD_STRUCT_DISCKEY;
872 dvd.disckey.agid = p_css->i_agid;
873 memset( dvd.disckey.value, 0, 2048 );
875 if( ioctl( p_css->i_fd, DVD_READ_STRUCT, &dvd )<0 )
877 intf_ErrMsg( "DVD ioctl error in CSSGetKeys" );
882 for( i=0 ; i<sizeof(dvd.disckey.value) ; i++ )
884 dvd.disckey.value[i] ^=
885 p_css->keys.pi_key_check[4 - (i % KEY_SIZE )];
888 memcpy( p_css->pi_disc_key, dvd.disckey.value, 2048 );
890 if( CSSGetASF( p_css->i_fd ) < 0 )
896 auth.type = DVD_LU_SEND_TITLE_KEY;
897 auth.lstk.agid = p_css->i_agid;
899 for( j=0 ; j<p_css->i_title_nb ; j++ )
901 auth.lstk.lba = p_css->p_title_key[j].i_lba;
903 if( ioctl( p_css->i_fd, DVD_AUTH, &auth )<0 )
905 intf_ErrMsg( "DVD ioctl error in CSSGetKeys" );
910 for( i=0 ; i<KEY_SIZE ; ++i )
912 auth.lstk.title_key[i] ^=
913 p_css->keys.pi_key_check[4 - (i % KEY_SIZE)];
914 memcpy( p_css->p_title_key[j].key, auth.lstk.title_key, KEY_SIZE );
918 if( CSSGetASF( p_css->i_fd ) < 0 )
927 * Cracking method from Ethan Hawke.
928 * Does not use key tables and ioctls.
932 title_key_t title_key[MaxKeys] ;
939 int i_registered_keys = 0 ;
940 int i_total_keys_found = 0 ;
942 boolean_t b_encrypted = 0;
943 boolean_t b_stop_scanning = 0 ;
945 int i_fd = p_css->i_fd;
947 for( i_title=0 ; i_title<1/*p_css->i_title_nb*/ ; i_title++ )
949 i_pos = p_css->p_title_key[i_title].i;
952 i_pos = lseek( i_fd, i_pos, SEEK_SET );
953 i_bytes_read = read( i_fd, pi_buf, 0x800 );
954 if( pi_buf[0x14] & 0x30 ) // PES_scrambling_control
959 for( i=2 ; i<0x30 ; i++ )
961 for( j=i ; (j<0x80) &&
962 (pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j]) ; j++ );
963 if( (j>i_best_plen) && (j>i) )
969 if( (i_best_plen>20) && (i_best_plen / i_best_p >= 2) )
971 i = CSScracker( 0, &pi_buf[0x80],
972 &pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
973 (DVD_key_t*)&pi_buf[0x54],
978 for( j=0 ; j<i_registered_keys ; j++ )
980 if( memcmp( &(title_key[j].key),
981 &my_key, sizeof(DVD_key_t) ) == 0 )
984 i_total_keys_found++;
990 memcpy( &( title_key[i_registered_keys].key),
993 title_key[i_registered_keys++].i = 1;
994 i_total_keys_found++;
996 i = CSScracker( i, &pi_buf[0x80],
997 &pi_buf[0x80 -( i_best_plen / i_best_p) *i_best_p],
998 (DVD_key_t*)&pi_buf[0x54], &my_key);
1000 if( i_registered_keys == 1 && title_key[0].i >= REPEAT )
1002 b_stop_scanning = 1;
1006 i_pos += i_bytes_read;
1007 } while( i_bytes_read == 0x800 && !b_stop_scanning);
1009 if( b_stop_scanning)
1012 "CSS: Found enough occurancies of the same key." );
1016 intf_WarnMsg( 3, "CSS: This file was _NOT_ encrypted!");
1019 if( b_encrypted && i_registered_keys == 0 )
1021 intf_WarnMsg( 3 , "CSS: Unable to determine keys from file.");
1024 for( i=0 ; i<i_registered_keys-1 ; i++ )
1026 for( j=i+1 ; j<i_registered_keys ; j++ )
1028 if( title_key[j].i > title_key[i].i )
1030 memcpy( &my_key, &(title_key[j].key), sizeof(DVD_key_t) );
1032 memcpy( &(title_key[j].key),
1033 &(title_key[i].key), sizeof(DVD_key_t) );
1034 title_key[j].i = title_key[i].i;
1035 memcpy( &(title_key[i].key),&my_key, sizeof(DVD_key_t) );
1042 fprintf(stderr, " Key(s) & key probability\n---------------------\n");
1043 for( i=0 ; i<i_registered_keys ; i++ )
1045 fprintf(stderr, "%d) %02X %02X %02X %02X %02X - %3.2f%%\n", i,
1046 title_key[i].key[0], title_key[i].key[1],
1047 title_key[i].key[2], title_key[i].key[3],
1048 title_key[i].key[4],
1049 title_key[i].i * 100.0 / i_total_keys_found );
1050 if( title_key[i_highest].i * 100.0 / i_total_keys_found
1051 <= title_key[i].i*100.0 / i_total_keys_found )
1056 fprintf(stderr, "\n");
1059 /* The "find the key with the highest probability" code
1060 * is untested, as I haven't been able to find a VOB that
1061 * produces multiple keys (RT)
1063 intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X\n",
1065 title_key[i_highest].key[0],
1066 title_key[i_highest].key[1],
1067 title_key[i_highest].key[2],
1068 title_key[i_highest].key[3],
1069 title_key[i_highest].key[4] );
1071 memcpy( p_css->p_title_key[i_title].key,
1072 title_key[i_highest].key, KEY_SIZE );
1078 /*****************************************************************************
1079 * CSSDescrambleSector
1081 * sec : sector to descramble
1082 * key : title key for this sector
1083 *****************************************************************************/
1084 int CSSDescrambleSector( DVD_key_t key, u8* pi_sec )
1086 unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
1087 u8* pi_end = pi_sec + 0x800;
1089 if( pi_sec[0x14] & 0x30) // PES_scrambling_control
1091 i_t1 = ((key)[0] ^ pi_sec[0x54]) | 0x100;
1092 i_t2 = (key)[1] ^ pi_sec[0x55];
1093 i_t3 = (((key)[2]) | ((key)[3] << 8) |
1094 ((key)[4] << 16)) ^ ((pi_sec[0x56]) |
1095 (pi_sec[0x57] << 8) | (pi_sec[0x58] << 16));
1097 i_t3 = i_t3 * 2 + 8 - i_t4;
1101 while( pi_sec != pi_end )
1103 i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
1105 i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
1106 i_t4 = pi_css_tab5[i_t4];
1107 i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
1108 i_t3 ) >> 8 ) ^ i_t3 ) >> 5) & 0xff;
1109 i_t3 = (i_t3 << 8 ) | i_t6;
1110 i_t6 = pi_css_tab4[i_t6];
1111 i_t5 += i_t6 + i_t4;
1112 *pi_sec++ = pi_css_tab1[*pi_sec] ^( i_t5 & 0xff );