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.2 2001/02/08 06:41:56 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 )
36 #include <netinet/in.h>
37 #include <sys/ioctl.h>
38 #ifdef HAVE_SYS_DVDIO_H
39 # include <sys/dvdio.h>
42 # include <linux/cdrom.h>
51 #include "input_dvd.h"
52 #include "css_table.h"
54 /*****************************************************************************
56 *****************************************************************************/
58 unsigned int pi_css_tab0[11]={ 5, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 };
60 unsigned char pi_css_tab1[256]=
61 { 0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76,
62 0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b,
63 0xd3, 0x93, 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96,
64 0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b,
65 0x57, 0x17, 0x5f, 0x82, 0xc7, 0x87, 0xcf, 0x12,
66 0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f,
67 0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, 0x41, 0x90,
68 0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91,
69 0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74,
70 0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75,
71 0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94,
72 0xdc, 0x9c, 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95,
73 0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10,
74 0x58, 0x18, 0x50, 0x81, 0xc8, 0x88, 0xc0, 0x11,
75 0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92,
76 0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, 0x42, 0x9f,
77 0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16,
78 0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b,
79 0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6,
80 0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb,
81 0x37, 0x77, 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72,
82 0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f,
83 0xb9, 0xf9, 0xb1, 0xa0, 0xe9, 0xa9, 0xe1, 0xf0,
84 0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1,
85 0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, 0xc5, 0x14,
86 0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15,
87 0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4,
88 0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5,
89 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70,
90 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71,
91 0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2,
92 0xba, 0xfa, 0xb2, 0xaf, 0xea, 0xaa, 0xe2, 0xff };
94 unsigned char pi_css_tab2[256]=
95 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
96 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
97 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
98 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
99 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
100 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
101 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
102 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
103 0x49, 0x48, 0x4b, 0x4a, 0x4d, 0x4c, 0x4f, 0x4e,
104 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
105 0x5b, 0x5a, 0x59, 0x58, 0x5f, 0x5e, 0x5d, 0x5c,
106 0x52, 0x53, 0x50, 0x51, 0x56, 0x57, 0x54, 0x55,
107 0x6d, 0x6c, 0x6f, 0x6e, 0x69, 0x68, 0x6b, 0x6a,
108 0x64, 0x65, 0x66, 0x67, 0x60, 0x61, 0x62, 0x63,
109 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
110 0x76, 0x77, 0x74, 0x75, 0x72, 0x73, 0x70, 0x71,
111 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
112 0x9b, 0x9a, 0x99, 0x98, 0x9f, 0x9e, 0x9d, 0x9c,
113 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
114 0x89, 0x88, 0x8b, 0x8a, 0x8d, 0x8c, 0x8f, 0x8e,
115 0xb6, 0xb7, 0xb4, 0xb5, 0xb2, 0xb3, 0xb0, 0xb1,
116 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
117 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3,
118 0xad, 0xac, 0xaf, 0xae, 0xa9, 0xa8, 0xab, 0xaa,
119 0xdb, 0xda, 0xd9, 0xd8, 0xdf, 0xde, 0xdd, 0xdc,
120 0xd2, 0xd3, 0xd0, 0xd1, 0xd6, 0xd7, 0xd4, 0xd5,
121 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,
122 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
123 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
124 0xf6, 0xf7, 0xf4, 0xf5, 0xf2, 0xf3, 0xf0, 0xf1,
125 0xed, 0xec, 0xef, 0xee, 0xe9, 0xe8, 0xeb, 0xea,
126 0xe4, 0xe5, 0xe6, 0xe7, 0xe0, 0xe1, 0xe2, 0xe3
129 unsigned char pi_css_tab3[512]=
130 { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
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 };
195 unsigned char pi_css_tab4[256]=
196 { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
197 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
198 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
199 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
200 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
201 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
202 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
203 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
204 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
205 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
206 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
207 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
208 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
209 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
210 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
211 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
212 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
213 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
214 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
215 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
216 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
217 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
218 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
219 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
220 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
221 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
222 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
223 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
224 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
225 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
226 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
227 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff };
229 unsigned char pi_css_tab5[256]=
230 { 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
231 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
232 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
233 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
234 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
235 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
236 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
237 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
238 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
239 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
240 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
241 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
242 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
243 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
244 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
245 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
246 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
247 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
248 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
249 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
250 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
251 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
252 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
253 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
254 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
255 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
256 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
257 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
258 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
259 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
260 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
261 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00 };
267 /*****************************************************************************
268 * CSSGetASF : Get Authentification success flag
269 *****************************************************************************/
270 int CSSGetASF( int i_fd )
274 ai.type = DVD_LU_SEND_ASF;
277 for( ai.lsasf.agid = 0 ; ai.lsasf.agid < 4 ; ai.lsasf.agid++ )
279 if( !( ioctl( i_fd, DVD_AUTH, &ai ) ) )
281 intf_Msg("CSS: %sAuthenticated\n", (ai.lsasf.asf) ? "" : "not");
285 intf_ErrMsg( "CSS Error: GetASF" );
289 /*****************************************************************************
290 * CSSCryptKey : shuffles bits and unencrypt keys.
292 * i_key_type : 0->key1, 1->key2, 2->buskey.
293 * i_varient : between 0 and 31.
294 *****************************************************************************/
295 static void CSSCryptKey( int i_key_type, int i_varient,
296 u8 const * pi_challenge, u8* pi_key )
298 /* Permutation table for challenge */
299 u8 ppi_perm_challenge[3][10] =
300 { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 },
301 { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 },
302 { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } };
303 /* Permutation table for varient table */
304 u8 ppi_perm_varient[2][32] =
305 { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d,
306 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d,
307 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05,
308 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 },
309 { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e,
310 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c,
311 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f,
312 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } };
313 u8 pi_css_secret[5] = { 0xE2, 0xA3, 0x45, 0x10, 0xF4 };
314 u8 pi_css_varients[32] =
315 { 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
316 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
317 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
318 0xA0, 0xA1, 0xA4, 0xA5, 0xB0, 0xB1, 0xB4, 0xB5 };
332 for( i=0 ; i<10 ; i++ )
334 pi_scratch[i] = pi_challenge[ppi_perm_challenge[i_key_type][i]];
336 i_css_varient = i_key_type == 0 ? i_varient
337 : ppi_perm_varient[i_key_type-1][i_varient];
339 for( i=0 ; i<5 ; i++ )
341 pi_tmp1[i] = pi_scratch[5+i] ^ pi_css_secret[i];
344 /* In order to ensure that the LFSR works we need to ensure that the
345 * initial values are non-zero. Thus when we initialise them from
346 * the seed, we ensure that a bit is set.
348 i_lfsr0 = ( pi_tmp1[0] << 17 ) | ( pi_tmp1[1] << 9 ) |
349 ( ( pi_tmp1[2] & ~7 ) << 1 ) | 8 | (pi_tmp1[2] & 7);
352 * reverse lfsr0/1 to simplify calculation in loop
354 i_lfsr0 = ( pi_reverse[i_lfsr0 & 0xff] << 17 ) |
355 ( pi_reverse[( i_lfsr0 >> 8 ) & 0xff] << 9 ) |
356 ( pi_reverse[( i_lfsr0 >> 16 ) & 0xff] << 1) |
359 i_lfsr1 = ( pi_reverse[pi_tmp1[4]] << 9 ) | 0x100 |
360 ( pi_reverse[pi_tmp1[3]] );
362 i_index = sizeof( pi_bits );
365 i_lfsr0_o = ( i_lfsr0 >> 12) ^ ( i_lfsr0 >> 4) ^
366 ( i_lfsr0 >> 3) ^ i_lfsr0;
368 i_lfsr1_o = ( ( i_lfsr1 >> 14 ) & 7) ^ i_lfsr1;
369 i_lfsr1_o ^= ( i_lfsr1_o << 3 ) ^ ( i_lfsr1_o << 6 );
371 i_lfsr1 = ( i_lfsr1 >> 8) ^ ( i_lfsr1_o << 9);
372 i_lfsr0 = ( i_lfsr0 >> 8 ) ^ ( i_lfsr0_o << 17);
374 i_lfsr0_o = ~i_lfsr0_o;
375 i_lfsr1_o = ~i_lfsr1_o;
377 i_val += i_lfsr0_o + i_lfsr1_o;
379 pi_bits[--i_index] = i_val & 0xFF;
382 } while( i_index > 0 );
384 i_css_varient = pi_css_varients[i_css_varient];
386 intf_WarnMsg( 3, "CSS varient: %d\n", i_css_varient );
391 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_scratch[i] )
393 i_index = pi_bits[25+i] ^ pi_scratch[i];
394 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
395 pi_tmp1[i] = pi_css_mangle2[i_index] ^ i_term;
397 pi_tmp1[4] ^= pi_tmp1[0];
398 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
400 i_index = pi_bits[20+i] ^ pi_tmp1[i];
401 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
402 pi_tmp2[i] = pi_css_mangle2[i_index] ^ i_term;
404 pi_tmp2[4] ^= pi_tmp2[0];
405 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
407 i_index = pi_bits[15+i] ^ pi_tmp2[i];
408 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
409 i_index = pi_css_mangle2[i_index] ^ i_term;
410 pi_tmp1[i] = pi_css_mangle0[i_index];
412 pi_tmp1[4] ^= pi_tmp1[0];
413 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
415 i_index = pi_bits[10+i] ^ pi_tmp1[i];
416 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
417 i_index = pi_css_mangle2[i_index] ^ i_term;
418 pi_tmp2[i] = pi_css_mangle0[i_index];
420 pi_tmp2[4] ^= pi_tmp2[0];
421 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
423 i_index = pi_bits[5+i] ^ pi_tmp2[i];
424 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
425 pi_tmp1[i] = pi_css_mangle2[i_index] ^ i_term;
427 pi_tmp1[4] ^= pi_tmp1[0];
429 for( i=5, i_term=0 ; --i>=0 ; i_term=pi_tmp1[i] )
431 i_index = pi_bits[i] ^ pi_tmp1[i];
432 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
433 pi_key[i] = pi_css_mangle2[i_index] ^ i_term;
439 static int CSSAuthHost( dvd_authinfo *ai, disc_t *disc )
445 /* Host data receive (host changes state) */
446 case DVD_LU_SEND_AGID:
448 ai->type = DVD_HOST_SEND_CHALLENGE;
451 case DVD_LU_SEND_KEY1:
453 for( i=0; i<KEY_SIZE; i++ )
455 disc->pi_key1[i] = ai->lsk.key[4-i];
458 for( i=0; i<32; ++i )
460 CSSCryptKey( 0, i, disc->pi_challenge,
461 disc->pi_key_check );
463 if( memcmp( disc->pi_key_check,
464 disc->pi_key1, KEY_SIZE ) == 0 )
466 intf_WarnMsg( 3, "CSS: Drive Authentic - using varient %d\n", i);
468 ai->type = DVD_LU_SEND_CHALLENGE;
472 // intf_ErrMsg( "Drive would not Authenticate" );
473 // ai->type = DVD_AUTH_FAILURE;
477 case DVD_LU_SEND_CHALLENGE:
478 for( i=0; i<10; ++i )
480 disc->pi_challenge[i] = ai->hsc.chal[9-i];
482 CSSCryptKey( 1, disc->i_varient, disc->pi_challenge,
484 ai->type = DVD_HOST_SEND_KEY2;
488 case DVD_HOST_SEND_CHALLENGE:
489 for( i=0; i<10; ++i )
491 ai->hsc.chal[9-i] = disc->pi_challenge[i];
493 /* Returning data, let LU change state */
496 case DVD_HOST_SEND_KEY2:
497 for( i=0; i<KEY_SIZE; ++i )
499 ai->hsk.key[4-i] = disc->pi_key2[i];
501 /* Returning data, let LU change state */
505 intf_ErrMsg( "CSS: Got invalid state %d", ai->type );
512 /*****************************************************************************
513 * CSSCracker : title key decryption by cracking
514 *****************************************************************************/
516 // FIXME : adapt to vlc
517 #define KEYSTREAMBYTES 10
519 static unsigned char invtab4[256];
521 static int CSScracker( int StartVal,
522 unsigned char* pCrypted,
523 unsigned char* pDecrypted,
524 DVD_key_t *StreamKey,
527 unsigned char MyBuf[10];
528 unsigned int t1,t2,t3,t4,t5,t6;
530 unsigned int vCandidate;
538 MyBuf[i] = pi_css_tab1[pCrypted[i]] ^ pDecrypted[i];
541 /* Test that CSStab4 is a permutation */
542 memset( invtab4, 0, 256 );
543 for( i = 0 ; i < 256 ; i++ )
545 invtab4[ pi_css_tab4[i] ] = 1;
548 for (i = 0 ; i < 256 ; i++)
550 if (invtab4[ i ] != 1)
552 intf_ErrMsg( "CSS: Permutation error" );
557 /* initialize the inverse of table4 */
558 for( i = 0 ; i < 256 ; i++ )
560 invtab4[ pi_css_tab4[i] ] = i;
563 for( nTry = StartVal ; nTry < 65536 ; nTry++ )
565 t1 = nTry >> 8 | 0x100;
567 t3 = 0; /* not needed */
570 /* iterate cipher 4 times to reconstruct LFSR2 */
571 for( i = 0 ; i < 4 ; i++ )
573 /* advance LFSR1 normaly */
574 t4=pi_css_tab2[t2]^pi_css_tab3[t1];
582 t6 = ( t6 + 0xff )&0x0ff;
591 /* feed / advance t3 / t5 */
598 /* iterate 6 more times to validate candidate key */
599 for( ; i < KEYSTREAMBYTES ; i++ )
601 t4=pi_css_tab2[t2]^pi_css_tab3[t1];
605 t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
609 if( (t5 & 0xff) != MyBuf[i] ) break;
613 if( i == KEYSTREAMBYTES )
615 /* Do 4 backwards steps of iterating t3 to deduce initial state */
617 for( i = 0 ; i < 4 ; i++ )
621 /* easy to code, and fast enough bruteforce
622 * search for byte shifted in */
623 for( j=0 ; j < 256 ; j++ )
625 t3 = (t3 & 0x1ffff) | ( j << 17 );
626 t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
627 if( t6 == t1 ) break;
630 // printf( "Candidate: t1=%03x t2=%02x t3=%08x\n", 0x100|(nTry>>8),nTry&0x0ff, t3 );
635 if ( ((t4+t5)*2 + 8 - ((t4+t5)&7))==t3 )
637 (*pkey)[0] = nTry>>8;
638 (*pkey)[1] = nTry & 0xFF;
639 (*pkey)[2] = ((t4+t5) >> 0) & 0xFF;
640 (*pkey)[3] = ((t4+t5) >> 8) & 0xFF;
641 (*pkey)[4] = ((t4+t5) >> 16) & 0xFF;
650 (*pkey)[0] ^= (*StreamKey)[0];
651 (*pkey)[1] ^= (*StreamKey)[1];
652 (*pkey)[2] ^= (*StreamKey)[2];
653 (*pkey)[3] ^= (*StreamKey)[3];
654 (*pkey)[4] ^= (*StreamKey)[4];
661 * Authentication and keys
664 /*****************************************************************************
665 * CSSTest : check if the disc is encrypted or not
666 *****************************************************************************/
667 int CSSTest( int i_fd )
671 dvd.type = DVD_STRUCT_COPYRIGHT;
672 dvd.copyright.layer_num = 0;
674 if( ioctl( i_fd, DVD_READ_STRUCT, &dvd ) < 0 )
676 intf_ErrMsg( "DVD ioctl error" );
680 return dvd.copyright.cpst;
683 /*****************************************************************************
684 * CSSInit : CSS Structure initialisation and DVD authentication.
685 *****************************************************************************/
687 css_t CSSInit( int i_fd )
697 memset( &ai, 0, sizeof(ai) );
699 // if (CSSGetASF (i_fd))
703 /* Init sequence, request AGID */
704 for( i=1; (i<4)&&(rv== -1) ; ++i )
706 intf_WarnMsg( 3, "CSS: Request AGID [%d]...", i );
707 ai.type = DVD_LU_SEND_AGID;
709 rv = ioctl (i_fd, DVD_AUTH, &ai);
712 intf_ErrMsg( "CSS: N/A, invalidating" );
713 ai.type = DVD_INVALIDATE_AGID;
715 ioctl( i_fd, DVD_AUTH, &ai );
720 intf_ErrMsg( "CSS: Cannot get AGID\n" );
723 for( i=0 ; i<10; ++i )
725 css.disc.pi_challenge[i] = i;
728 /* Send AGID to host */
729 if( CSSAuthHost(&ai, &(css.disc) )<0 )
731 intf_ErrMsg( "CSS Error: Send AGID to host failed" );
735 /* Get challenge from host */
736 if( CSSAuthHost( &ai, &(css.disc) )<0)
738 intf_ErrMsg( "CSS Error: Get challenge from host failed" );
741 css.i_agid = ai.lsa.agid;
743 /* Send challenge to LU */
744 if( ioctl( i_fd, DVD_AUTH, &ai )<0 )
746 intf_ErrMsg( "CSS Error: Send challenge to LU failed ");
750 /* Get key1 from LU */
751 if( ioctl( i_fd, DVD_AUTH, &ai )<0)
753 intf_ErrMsg( "CSS Error: Get key1 from LU failed ");
757 /* Send key1 to host */
758 // if (_CSSAuthHost(&ai, disc) < 0) {
759 if( CSSAuthHost( &ai, &(css.disc) )<0)
761 intf_ErrMsg( "CSS Error: Send key1 to host failed" );
765 /* Get challenge from LU */
766 if( ioctl( i_fd, DVD_AUTH, &ai)<0 )
768 intf_ErrMsg( "CSS Error: Get challenge from LU failed ");
772 /* Send challenge to host */
773 if( CSSAuthHost( &ai, &(css.disc) )<0 )
775 intf_ErrMsg( "CSS Error: Send challenge to host failed");
779 /* Get key2 from host */
780 if( CSSAuthHost( &ai, &(css.disc) )<0 )
782 intf_ErrMsg( "CSS Error: Get key2 from host failed" );
786 /* Send key2 to LU */
787 if( ioctl( i_fd, DVD_AUTH, &ai )<0 )
789 intf_ErrMsg( "CSS Error: Send key2 to LU failed (expected)" );
793 if( ai.type == DVD_AUTH_ESTABLISHED )
795 intf_WarnMsg( 3, "DVD is authenticated");
797 else if( ai.type == DVD_AUTH_FAILURE )
799 intf_ErrMsg("CSS Error: DVD authentication failed");
802 memcpy( css.disc.pi_challenge, css.disc.pi_key1, KEY_SIZE );
803 memcpy( css.disc.pi_challenge+KEY_SIZE, css.disc.pi_key2, KEY_SIZE );
804 CSSCryptKey( 2, css.disc.i_varient,
805 css.disc.pi_challenge,
806 css.disc.pi_key_check );
808 intf_WarnMsg( 3, "CSS: Received Session Key\n" );
815 // if (CSSGetASF (i_fd) < 0)
818 dvd.type = DVD_STRUCT_DISCKEY;
819 dvd.disckey.agid = css.i_agid;
820 memset( dvd.disckey.value, 0, 2048 );
822 if( ioctl( i_fd, DVD_READ_STRUCT, &dvd )<0 )
824 intf_ErrMsg( "CSS Error: Could not read Disc Key" );
829 for (i=0; i<sizeof dvd.disckey.value; i++)
831 dvd.disckey.value[i] ^= css.disc.pi_key_check[4 - (i % KEY_SIZE)];
833 memcpy( css.disc.pi_key_check, dvd.disckey.value, 2048 );
835 // if (CSSGetASF (i_fd) < 0)
844 /*****************************************************************************
845 * CSSGetKeys : get the disc key of the media en the dvd device, and then
847 * The DVD should have been opened before.
848 *****************************************************************************/
852 int CSSGetKeys( css_t * p_css )
857 * css_auth/libcss method from Derek Fawcus.
858 * Get encrypted keys with ioctls and decrypt them
859 * with cracked player keys
864 if( CSSGetASF( p_css->i_fd ) < 0 )
870 dvd.type = DVD_STRUCT_DISCKEY;
871 dvd.disckey.agid = p_css->i_agid;
872 memset( dvd.disckey.value, 0, 2048 );
874 if( ioctl( p_css->i_fd, DVD_READ_STRUCT, &dvd )<0 )
876 intf_ErrMsg( "DVD ioctl error in CSSGetKeys" );
881 for( i=0 ; i<sizeof(dvd.disckey.value) ; i++ )
883 dvd.disckey.value[i] ^=
884 p_css->keys.pi_key_check[4 - (i % KEY_SIZE )];
887 memcpy( p_css->pi_disc_key, dvd.disckey.value, 2048 );
889 if( CSSGetASF( p_css->i_fd ) < 0 )
895 auth.type = DVD_LU_SEND_TITLE_KEY;
896 auth.lstk.agid = p_css->i_agid;
898 for( j=0 ; j<p_css->i_title_nb ; j++ )
900 auth.lstk.lba = p_css->p_title_key[j].i_lba;
902 if( ioctl( p_css->i_fd, DVD_AUTH, &auth )<0 )
904 intf_ErrMsg( "DVD ioctl error in CSSGetKeys" );
909 for( i=0 ; i<KEY_SIZE ; ++i )
911 auth.lstk.title_key[i] ^=
912 p_css->keys.pi_key_check[4 - (i % KEY_SIZE)];
913 memcpy( p_css->p_title_key[j].key, auth.lstk.title_key, KEY_SIZE );
917 if( CSSGetASF( p_css->i_fd ) < 0 )
926 * Cracking method from Ethan Hawke.
927 * Does not use key tables and ioctls.
931 title_key_t title_key[MaxKeys] ;
938 int i_registered_keys = 0 ;
939 int i_total_keys_found = 0 ;
941 boolean_t b_encrypted = 0;
942 boolean_t b_stop_scanning = 0 ;
944 int i_fd = p_css->i_fd;
946 for( i_title=0 ; i_title<1/*p_css->i_title_nb*/ ; i_title++ )
948 i_pos = p_css->p_title_key[i_title].i;
951 i_pos = lseek64( i_fd, i_pos, SEEK_SET );
952 i_bytes_read = read( i_fd, pi_buf, 0x800 );
953 if( pi_buf[0x14] & 0x30 ) // PES_scrambling_control
958 for( i=2 ; i<0x30 ; i++ )
960 for( j=i ; (j<0x80) &&
961 (pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j]) ; j++ );
962 if( (j>i_best_plen) && (j>i) )
968 if( (i_best_plen>20) && (i_best_plen / i_best_p >= 2) )
970 i = CSScracker( 0, &pi_buf[0x80],
971 &pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
972 (DVD_key_t*)&pi_buf[0x54],
977 for( j=0 ; j<i_registered_keys ; j++ )
979 if( memcmp( &(title_key[j].key),
980 &my_key, sizeof(DVD_key_t) ) == 0 )
983 i_total_keys_found++;
989 memcpy( &( title_key[i_registered_keys].key),
992 title_key[i_registered_keys++].i = 1;
993 i_total_keys_found++;
995 i = CSScracker( i, &pi_buf[0x80],
996 &pi_buf[0x80 -( i_best_plen / i_best_p) *i_best_p],
997 (DVD_key_t*)&pi_buf[0x54], &my_key);
999 if( i_registered_keys == 1 && title_key[0].i >= REPEAT )
1001 b_stop_scanning = 1;
1005 i_pos += i_bytes_read;
1006 } while( i_bytes_read == 0x800 && !b_stop_scanning);
1008 if( b_stop_scanning)
1011 "CSS: Found enough occurancies of the same key." );
1015 intf_WarnMsg( 3, "CSS: This file was _NOT_ encrypted!");
1018 if( b_encrypted && i_registered_keys == 0 )
1020 intf_WarnMsg( 3 , "CSS: Unable to determine keys from file.");
1023 for( i=0 ; i<i_registered_keys-1 ; i++ )
1025 for( j=i+1 ; j<i_registered_keys ; j++ )
1027 if( title_key[j].i > title_key[i].i )
1029 memcpy( &my_key, &(title_key[j].key), sizeof(DVD_key_t) );
1031 memcpy( &(title_key[j].key),
1032 &(title_key[i].key), sizeof(DVD_key_t) );
1033 title_key[j].i = title_key[i].i;
1034 memcpy( &(title_key[i].key),&my_key, sizeof(DVD_key_t) );
1041 fprintf(stderr, " Key(s) & key probability\n---------------------\n");
1042 for( i=0 ; i<i_registered_keys ; i++ )
1044 fprintf(stderr, "%d) %02X %02X %02X %02X %02X - %3.2f%%\n", i,
1045 title_key[i].key[0], title_key[i].key[1],
1046 title_key[i].key[2], title_key[i].key[3],
1047 title_key[i].key[4],
1048 title_key[i].i * 100.0 / i_total_keys_found );
1049 if( title_key[i_highest].i * 100.0 / i_total_keys_found
1050 <= title_key[i].i*100.0 / i_total_keys_found )
1055 fprintf(stderr, "\n");
1058 /* The "find the key with the highest probability" code
1059 * is untested, as I haven't been able to find a VOB that
1060 * produces multiple keys (RT)
1062 intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X\n",
1064 title_key[i_highest].key[0],
1065 title_key[i_highest].key[1],
1066 title_key[i_highest].key[2],
1067 title_key[i_highest].key[3],
1068 title_key[i_highest].key[4] );
1070 memcpy( p_css->p_title_key[i_title].key,
1071 title_key[i_highest].key, KEY_SIZE );
1077 /*****************************************************************************
1078 * CSSDescrambleSector
1080 * sec : sector to descramble
1081 * key : title key for this sector
1082 *****************************************************************************/
1083 int CSSDescrambleSector( DVD_key_t key, u8* pi_sec )
1085 unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
1086 u8* pi_end = pi_sec + 0x800;
1088 if( pi_sec[0x14] & 0x30) // PES_scrambling_control
1090 i_t1 = ((key)[0] ^ pi_sec[0x54]) | 0x100;
1091 i_t2 = (key)[1] ^ pi_sec[0x55];
1092 i_t3 = (((key)[2]) | ((key)[3] << 8) |
1093 ((key)[4] << 16)) ^ ((pi_sec[0x56]) |
1094 (pi_sec[0x57] << 8) | (pi_sec[0x58] << 16));
1096 i_t3 = i_t3 * 2 + 8 - i_t4;
1100 while( pi_sec != pi_end )
1102 i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
1104 i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
1105 i_t4 = pi_css_tab5[i_t4];
1106 i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
1107 i_t3 ) >> 8 ) ^ i_t3 ) >> 5) & 0xff;
1108 i_t3 = (i_t3 << 8 ) | i_t6;
1109 i_t6 = pi_css_tab4[i_t6];
1110 i_t5 += i_t6 + i_t4;
1111 *pi_sec++ = pi_css_tab1[*pi_sec] ^( i_t5 & 0xff );