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.3 2001/02/08 17:44:12 massiot 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>
36 #include <sys/ioctl.h>
37 #ifdef HAVE_SYS_DVDIO_H
38 # include <sys/dvdio.h>
41 # include <linux/cdrom.h>
50 #include "input_dvd.h"
51 #include "css_table.h"
53 /*****************************************************************************
55 *****************************************************************************/
57 unsigned int pi_css_tab0[11]={ 5, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 };
59 unsigned char pi_css_tab1[256]=
60 { 0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76,
61 0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b,
62 0xd3, 0x93, 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96,
63 0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b,
64 0x57, 0x17, 0x5f, 0x82, 0xc7, 0x87, 0xcf, 0x12,
65 0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f,
66 0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, 0x41, 0x90,
67 0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91,
68 0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74,
69 0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75,
70 0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94,
71 0xdc, 0x9c, 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95,
72 0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10,
73 0x58, 0x18, 0x50, 0x81, 0xc8, 0x88, 0xc0, 0x11,
74 0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92,
75 0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, 0x42, 0x9f,
76 0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16,
77 0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b,
78 0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6,
79 0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb,
80 0x37, 0x77, 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72,
81 0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f,
82 0xb9, 0xf9, 0xb1, 0xa0, 0xe9, 0xa9, 0xe1, 0xf0,
83 0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1,
84 0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, 0xc5, 0x14,
85 0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15,
86 0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4,
87 0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5,
88 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70,
89 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71,
90 0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2,
91 0xba, 0xfa, 0xb2, 0xaf, 0xea, 0xaa, 0xe2, 0xff };
93 unsigned char pi_css_tab2[256]=
94 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
95 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
96 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
97 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
98 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
99 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
100 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
101 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
102 0x49, 0x48, 0x4b, 0x4a, 0x4d, 0x4c, 0x4f, 0x4e,
103 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
104 0x5b, 0x5a, 0x59, 0x58, 0x5f, 0x5e, 0x5d, 0x5c,
105 0x52, 0x53, 0x50, 0x51, 0x56, 0x57, 0x54, 0x55,
106 0x6d, 0x6c, 0x6f, 0x6e, 0x69, 0x68, 0x6b, 0x6a,
107 0x64, 0x65, 0x66, 0x67, 0x60, 0x61, 0x62, 0x63,
108 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
109 0x76, 0x77, 0x74, 0x75, 0x72, 0x73, 0x70, 0x71,
110 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
111 0x9b, 0x9a, 0x99, 0x98, 0x9f, 0x9e, 0x9d, 0x9c,
112 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
113 0x89, 0x88, 0x8b, 0x8a, 0x8d, 0x8c, 0x8f, 0x8e,
114 0xb6, 0xb7, 0xb4, 0xb5, 0xb2, 0xb3, 0xb0, 0xb1,
115 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
116 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3,
117 0xad, 0xac, 0xaf, 0xae, 0xa9, 0xa8, 0xab, 0xaa,
118 0xdb, 0xda, 0xd9, 0xd8, 0xdf, 0xde, 0xdd, 0xdc,
119 0xd2, 0xd3, 0xd0, 0xd1, 0xd6, 0xd7, 0xd4, 0xd5,
120 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,
121 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
122 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
123 0xf6, 0xf7, 0xf4, 0xf5, 0xf2, 0xf3, 0xf0, 0xf1,
124 0xed, 0xec, 0xef, 0xee, 0xe9, 0xe8, 0xeb, 0xea,
125 0xe4, 0xe5, 0xe6, 0xe7, 0xe0, 0xe1, 0xe2, 0xe3
128 unsigned char pi_css_tab3[512]=
129 { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff,
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 };
194 unsigned char pi_css_tab4[256]=
195 { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
196 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
197 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
198 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
199 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
200 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
201 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
202 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
203 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
204 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
205 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
206 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
207 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
208 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
209 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
210 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
211 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
212 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
213 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
214 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
215 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
216 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
217 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
218 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
219 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
220 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
221 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
222 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
223 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
224 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
225 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
226 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff };
228 unsigned char pi_css_tab5[256]=
229 { 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
230 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f,
231 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
232 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07,
233 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
234 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b,
235 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
236 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03,
237 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
238 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d,
239 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
240 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05,
241 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
242 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09,
243 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
244 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01,
245 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
246 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e,
247 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
248 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06,
249 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
250 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a,
251 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
252 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02,
253 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
254 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c,
255 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
256 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04,
257 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
258 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08,
259 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
260 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00 };
266 /*****************************************************************************
267 * CSSGetASF : Get Authentification success flag
268 *****************************************************************************/
269 int CSSGetASF( int i_fd )
273 ai.type = DVD_LU_SEND_ASF;
276 for( ai.lsasf.agid = 0 ; ai.lsasf.agid < 4 ; ai.lsasf.agid++ )
278 if( !( ioctl( i_fd, DVD_AUTH, &ai ) ) )
280 intf_Msg("CSS: %sAuthenticated\n", (ai.lsasf.asf) ? "" : "not");
284 intf_ErrMsg( "CSS Error: GetASF" );
288 /*****************************************************************************
289 * CSSCryptKey : shuffles bits and unencrypt keys.
291 * i_key_type : 0->key1, 1->key2, 2->buskey.
292 * i_varient : between 0 and 31.
293 *****************************************************************************/
294 static void CSSCryptKey( int i_key_type, int i_varient,
295 u8 const * pi_challenge, u8* pi_key )
297 /* Permutation table for challenge */
298 u8 ppi_perm_challenge[3][10] =
299 { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 },
300 { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 },
301 { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } };
302 /* Permutation table for varient table */
303 u8 ppi_perm_varient[2][32] =
304 { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d,
305 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d,
306 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05,
307 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 },
308 { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e,
309 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c,
310 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f,
311 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } };
312 u8 pi_css_secret[5] = { 0xE2, 0xA3, 0x45, 0x10, 0xF4 };
313 u8 pi_css_varients[32] =
314 { 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
315 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
316 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
317 0xA0, 0xA1, 0xA4, 0xA5, 0xB0, 0xB1, 0xB4, 0xB5 };
331 for( i=0 ; i<10 ; i++ )
333 pi_scratch[i] = pi_challenge[ppi_perm_challenge[i_key_type][i]];
335 i_css_varient = i_key_type == 0 ? i_varient
336 : ppi_perm_varient[i_key_type-1][i_varient];
338 for( i=0 ; i<5 ; i++ )
340 pi_tmp1[i] = pi_scratch[5+i] ^ pi_css_secret[i];
343 /* In order to ensure that the LFSR works we need to ensure that the
344 * initial values are non-zero. Thus when we initialise them from
345 * the seed, we ensure that a bit is set.
347 i_lfsr0 = ( pi_tmp1[0] << 17 ) | ( pi_tmp1[1] << 9 ) |
348 ( ( pi_tmp1[2] & ~7 ) << 1 ) | 8 | (pi_tmp1[2] & 7);
351 * reverse lfsr0/1 to simplify calculation in loop
353 i_lfsr0 = ( pi_reverse[i_lfsr0 & 0xff] << 17 ) |
354 ( pi_reverse[( i_lfsr0 >> 8 ) & 0xff] << 9 ) |
355 ( pi_reverse[( i_lfsr0 >> 16 ) & 0xff] << 1) |
358 i_lfsr1 = ( pi_reverse[pi_tmp1[4]] << 9 ) | 0x100 |
359 ( pi_reverse[pi_tmp1[3]] );
361 i_index = sizeof( pi_bits );
364 i_lfsr0_o = ( i_lfsr0 >> 12) ^ ( i_lfsr0 >> 4) ^
365 ( i_lfsr0 >> 3) ^ i_lfsr0;
367 i_lfsr1_o = ( ( i_lfsr1 >> 14 ) & 7) ^ i_lfsr1;
368 i_lfsr1_o ^= ( i_lfsr1_o << 3 ) ^ ( i_lfsr1_o << 6 );
370 i_lfsr1 = ( i_lfsr1 >> 8) ^ ( i_lfsr1_o << 9);
371 i_lfsr0 = ( i_lfsr0 >> 8 ) ^ ( i_lfsr0_o << 17);
373 i_lfsr0_o = ~i_lfsr0_o;
374 i_lfsr1_o = ~i_lfsr1_o;
376 i_val += i_lfsr0_o + i_lfsr1_o;
378 pi_bits[--i_index] = i_val & 0xFF;
381 } while( i_index > 0 );
383 i_css_varient = pi_css_varients[i_css_varient];
385 intf_WarnMsg( 3, "CSS varient: %d\n", i_css_varient );
390 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_scratch[i] )
392 i_index = pi_bits[25+i] ^ pi_scratch[i];
393 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
394 pi_tmp1[i] = pi_css_mangle2[i_index] ^ i_term;
396 pi_tmp1[4] ^= pi_tmp1[0];
397 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
399 i_index = pi_bits[20+i] ^ pi_tmp1[i];
400 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
401 pi_tmp2[i] = pi_css_mangle2[i_index] ^ i_term;
403 pi_tmp2[4] ^= pi_tmp2[0];
404 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
406 i_index = pi_bits[15+i] ^ pi_tmp2[i];
407 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
408 i_index = pi_css_mangle2[i_index] ^ i_term;
409 pi_tmp1[i] = pi_css_mangle0[i_index];
411 pi_tmp1[4] ^= pi_tmp1[0];
412 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
414 i_index = pi_bits[10+i] ^ pi_tmp1[i];
415 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
416 i_index = pi_css_mangle2[i_index] ^ i_term;
417 pi_tmp2[i] = pi_css_mangle0[i_index];
419 pi_tmp2[4] ^= pi_tmp2[0];
420 for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
422 i_index = pi_bits[5+i] ^ pi_tmp2[i];
423 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
424 pi_tmp1[i] = pi_css_mangle2[i_index] ^ i_term;
426 pi_tmp1[4] ^= pi_tmp1[0];
428 for( i=5, i_term=0 ; --i>=0 ; i_term=pi_tmp1[i] )
430 i_index = pi_bits[i] ^ pi_tmp1[i];
431 i_index = pi_css_mangle1[i_index] ^ i_css_varient;
432 pi_key[i] = pi_css_mangle2[i_index] ^ i_term;
438 static int CSSAuthHost( dvd_authinfo *ai, disc_t *disc )
444 /* Host data receive (host changes state) */
445 case DVD_LU_SEND_AGID:
447 ai->type = DVD_HOST_SEND_CHALLENGE;
450 case DVD_LU_SEND_KEY1:
452 for( i=0; i<KEY_SIZE; i++ )
454 disc->pi_key1[i] = ai->lsk.key[4-i];
457 for( i=0; i<32; ++i )
459 CSSCryptKey( 0, i, disc->pi_challenge,
460 disc->pi_key_check );
462 if( memcmp( disc->pi_key_check,
463 disc->pi_key1, KEY_SIZE ) == 0 )
465 intf_WarnMsg( 3, "CSS: Drive Authentic - using varient %d\n", i);
467 ai->type = DVD_LU_SEND_CHALLENGE;
471 // intf_ErrMsg( "Drive would not Authenticate" );
472 // ai->type = DVD_AUTH_FAILURE;
476 case DVD_LU_SEND_CHALLENGE:
477 for( i=0; i<10; ++i )
479 disc->pi_challenge[i] = ai->hsc.chal[9-i];
481 CSSCryptKey( 1, disc->i_varient, disc->pi_challenge,
483 ai->type = DVD_HOST_SEND_KEY2;
487 case DVD_HOST_SEND_CHALLENGE:
488 for( i=0; i<10; ++i )
490 ai->hsc.chal[9-i] = disc->pi_challenge[i];
492 /* Returning data, let LU change state */
495 case DVD_HOST_SEND_KEY2:
496 for( i=0; i<KEY_SIZE; ++i )
498 ai->hsk.key[4-i] = disc->pi_key2[i];
500 /* Returning data, let LU change state */
504 intf_ErrMsg( "CSS: Got invalid state %d", ai->type );
511 /*****************************************************************************
512 * CSSCracker : title key decryption by cracking
513 *****************************************************************************/
515 // FIXME : adapt to vlc
516 #define KEYSTREAMBYTES 10
518 static unsigned char invtab4[256];
520 static int CSScracker( int StartVal,
521 unsigned char* pCrypted,
522 unsigned char* pDecrypted,
523 DVD_key_t *StreamKey,
526 unsigned char MyBuf[10];
527 unsigned int t1,t2,t3,t4,t5,t6;
529 unsigned int vCandidate;
537 MyBuf[i] = pi_css_tab1[pCrypted[i]] ^ pDecrypted[i];
540 /* Test that CSStab4 is a permutation */
541 memset( invtab4, 0, 256 );
542 for( i = 0 ; i < 256 ; i++ )
544 invtab4[ pi_css_tab4[i] ] = 1;
547 for (i = 0 ; i < 256 ; i++)
549 if (invtab4[ i ] != 1)
551 intf_ErrMsg( "CSS: Permutation error" );
556 /* initialize the inverse of table4 */
557 for( i = 0 ; i < 256 ; i++ )
559 invtab4[ pi_css_tab4[i] ] = i;
562 for( nTry = StartVal ; nTry < 65536 ; nTry++ )
564 t1 = nTry >> 8 | 0x100;
566 t3 = 0; /* not needed */
569 /* iterate cipher 4 times to reconstruct LFSR2 */
570 for( i = 0 ; i < 4 ; i++ )
572 /* advance LFSR1 normaly */
573 t4=pi_css_tab2[t2]^pi_css_tab3[t1];
581 t6 = ( t6 + 0xff )&0x0ff;
590 /* feed / advance t3 / t5 */
597 /* iterate 6 more times to validate candidate key */
598 for( ; i < KEYSTREAMBYTES ; i++ )
600 t4=pi_css_tab2[t2]^pi_css_tab3[t1];
604 t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
608 if( (t5 & 0xff) != MyBuf[i] ) break;
612 if( i == KEYSTREAMBYTES )
614 /* Do 4 backwards steps of iterating t3 to deduce initial state */
616 for( i = 0 ; i < 4 ; i++ )
620 /* easy to code, and fast enough bruteforce
621 * search for byte shifted in */
622 for( j=0 ; j < 256 ; j++ )
624 t3 = (t3 & 0x1ffff) | ( j << 17 );
625 t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff;
626 if( t6 == t1 ) break;
629 // printf( "Candidate: t1=%03x t2=%02x t3=%08x\n", 0x100|(nTry>>8),nTry&0x0ff, t3 );
634 if ( ((t4+t5)*2 + 8 - ((t4+t5)&7))==t3 )
636 (*pkey)[0] = nTry>>8;
637 (*pkey)[1] = nTry & 0xFF;
638 (*pkey)[2] = ((t4+t5) >> 0) & 0xFF;
639 (*pkey)[3] = ((t4+t5) >> 8) & 0xFF;
640 (*pkey)[4] = ((t4+t5) >> 16) & 0xFF;
649 (*pkey)[0] ^= (*StreamKey)[0];
650 (*pkey)[1] ^= (*StreamKey)[1];
651 (*pkey)[2] ^= (*StreamKey)[2];
652 (*pkey)[3] ^= (*StreamKey)[3];
653 (*pkey)[4] ^= (*StreamKey)[4];
660 * Authentication and keys
663 /*****************************************************************************
664 * CSSTest : check if the disc is encrypted or not
665 *****************************************************************************/
666 int CSSTest( int i_fd )
670 dvd.type = DVD_STRUCT_COPYRIGHT;
671 dvd.copyright.layer_num = 0;
673 if( ioctl( i_fd, DVD_READ_STRUCT, &dvd ) < 0 )
675 intf_ErrMsg( "DVD ioctl error" );
679 return dvd.copyright.cpst;
682 /*****************************************************************************
683 * CSSInit : CSS Structure initialisation and DVD authentication.
684 *****************************************************************************/
686 css_t CSSInit( int i_fd )
696 memset( &ai, 0, sizeof(ai) );
698 // if (CSSGetASF (i_fd))
702 /* Init sequence, request AGID */
703 for( i=1; (i<4)&&(rv== -1) ; ++i )
705 intf_WarnMsg( 3, "CSS: Request AGID [%d]...", i );
706 ai.type = DVD_LU_SEND_AGID;
708 rv = ioctl (i_fd, DVD_AUTH, &ai);
711 intf_ErrMsg( "CSS: N/A, invalidating" );
712 ai.type = DVD_INVALIDATE_AGID;
714 ioctl( i_fd, DVD_AUTH, &ai );
719 intf_ErrMsg( "CSS: Cannot get AGID\n" );
722 for( i=0 ; i<10; ++i )
724 css.disc.pi_challenge[i] = i;
727 /* Send AGID to host */
728 if( CSSAuthHost(&ai, &(css.disc) )<0 )
730 intf_ErrMsg( "CSS Error: Send AGID to host failed" );
734 /* Get challenge from host */
735 if( CSSAuthHost( &ai, &(css.disc) )<0)
737 intf_ErrMsg( "CSS Error: Get challenge from host failed" );
740 css.i_agid = ai.lsa.agid;
742 /* Send challenge to LU */
743 if( ioctl( i_fd, DVD_AUTH, &ai )<0 )
745 intf_ErrMsg( "CSS Error: Send challenge to LU failed ");
749 /* Get key1 from LU */
750 if( ioctl( i_fd, DVD_AUTH, &ai )<0)
752 intf_ErrMsg( "CSS Error: Get key1 from LU failed ");
756 /* Send key1 to host */
757 // if (_CSSAuthHost(&ai, disc) < 0) {
758 if( CSSAuthHost( &ai, &(css.disc) )<0)
760 intf_ErrMsg( "CSS Error: Send key1 to host failed" );
764 /* Get challenge from LU */
765 if( ioctl( i_fd, DVD_AUTH, &ai)<0 )
767 intf_ErrMsg( "CSS Error: Get challenge from LU failed ");
771 /* Send challenge to host */
772 if( CSSAuthHost( &ai, &(css.disc) )<0 )
774 intf_ErrMsg( "CSS Error: Send challenge to host failed");
778 /* Get key2 from host */
779 if( CSSAuthHost( &ai, &(css.disc) )<0 )
781 intf_ErrMsg( "CSS Error: Get key2 from host failed" );
785 /* Send key2 to LU */
786 if( ioctl( i_fd, DVD_AUTH, &ai )<0 )
788 intf_ErrMsg( "CSS Error: Send key2 to LU failed (expected)" );
792 if( ai.type == DVD_AUTH_ESTABLISHED )
794 intf_WarnMsg( 3, "DVD is authenticated");
796 else if( ai.type == DVD_AUTH_FAILURE )
798 intf_ErrMsg("CSS Error: DVD authentication failed");
801 memcpy( css.disc.pi_challenge, css.disc.pi_key1, KEY_SIZE );
802 memcpy( css.disc.pi_challenge+KEY_SIZE, css.disc.pi_key2, KEY_SIZE );
803 CSSCryptKey( 2, css.disc.i_varient,
804 css.disc.pi_challenge,
805 css.disc.pi_key_check );
807 intf_WarnMsg( 3, "CSS: Received Session Key\n" );
814 // if (CSSGetASF (i_fd) < 0)
817 dvd.type = DVD_STRUCT_DISCKEY;
818 dvd.disckey.agid = css.i_agid;
819 memset( dvd.disckey.value, 0, 2048 );
821 if( ioctl( i_fd, DVD_READ_STRUCT, &dvd )<0 )
823 intf_ErrMsg( "CSS Error: Could not read Disc Key" );
828 for (i=0; i<sizeof dvd.disckey.value; i++)
830 dvd.disckey.value[i] ^= css.disc.pi_key_check[4 - (i % KEY_SIZE)];
832 memcpy( css.disc.pi_key_check, dvd.disckey.value, 2048 );
834 // if (CSSGetASF (i_fd) < 0)
843 /*****************************************************************************
844 * CSSGetKeys : get the disc key of the media en the dvd device, and then
846 * The DVD should have been opened before.
847 *****************************************************************************/
851 int CSSGetKeys( css_t * p_css )
856 * css_auth/libcss method from Derek Fawcus.
857 * Get encrypted keys with ioctls and decrypt them
858 * with cracked player keys
863 if( CSSGetASF( p_css->i_fd ) < 0 )
869 dvd.type = DVD_STRUCT_DISCKEY;
870 dvd.disckey.agid = p_css->i_agid;
871 memset( dvd.disckey.value, 0, 2048 );
873 if( ioctl( p_css->i_fd, DVD_READ_STRUCT, &dvd )<0 )
875 intf_ErrMsg( "DVD ioctl error in CSSGetKeys" );
880 for( i=0 ; i<sizeof(dvd.disckey.value) ; i++ )
882 dvd.disckey.value[i] ^=
883 p_css->keys.pi_key_check[4 - (i % KEY_SIZE )];
886 memcpy( p_css->pi_disc_key, dvd.disckey.value, 2048 );
888 if( CSSGetASF( p_css->i_fd ) < 0 )
894 auth.type = DVD_LU_SEND_TITLE_KEY;
895 auth.lstk.agid = p_css->i_agid;
897 for( j=0 ; j<p_css->i_title_nb ; j++ )
899 auth.lstk.lba = p_css->p_title_key[j].i_lba;
901 if( ioctl( p_css->i_fd, DVD_AUTH, &auth )<0 )
903 intf_ErrMsg( "DVD ioctl error in CSSGetKeys" );
908 for( i=0 ; i<KEY_SIZE ; ++i )
910 auth.lstk.title_key[i] ^=
911 p_css->keys.pi_key_check[4 - (i % KEY_SIZE)];
912 memcpy( p_css->p_title_key[j].key, auth.lstk.title_key, KEY_SIZE );
916 if( CSSGetASF( p_css->i_fd ) < 0 )
925 * Cracking method from Ethan Hawke.
926 * Does not use key tables and ioctls.
930 title_key_t title_key[MaxKeys] ;
937 int i_registered_keys = 0 ;
938 int i_total_keys_found = 0 ;
940 boolean_t b_encrypted = 0;
941 boolean_t b_stop_scanning = 0 ;
943 int i_fd = p_css->i_fd;
945 for( i_title=0 ; i_title<1/*p_css->i_title_nb*/ ; i_title++ )
947 i_pos = p_css->p_title_key[i_title].i;
950 i_pos = lseek( i_fd, i_pos, SEEK_SET );
951 i_bytes_read = read( i_fd, pi_buf, 0x800 );
952 if( pi_buf[0x14] & 0x30 ) // PES_scrambling_control
957 for( i=2 ; i<0x30 ; i++ )
959 for( j=i ; (j<0x80) &&
960 (pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j]) ; j++ );
961 if( (j>i_best_plen) && (j>i) )
967 if( (i_best_plen>20) && (i_best_plen / i_best_p >= 2) )
969 i = CSScracker( 0, &pi_buf[0x80],
970 &pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
971 (DVD_key_t*)&pi_buf[0x54],
976 for( j=0 ; j<i_registered_keys ; j++ )
978 if( memcmp( &(title_key[j].key),
979 &my_key, sizeof(DVD_key_t) ) == 0 )
982 i_total_keys_found++;
988 memcpy( &( title_key[i_registered_keys].key),
991 title_key[i_registered_keys++].i = 1;
992 i_total_keys_found++;
994 i = CSScracker( i, &pi_buf[0x80],
995 &pi_buf[0x80 -( i_best_plen / i_best_p) *i_best_p],
996 (DVD_key_t*)&pi_buf[0x54], &my_key);
998 if( i_registered_keys == 1 && title_key[0].i >= REPEAT )
1000 b_stop_scanning = 1;
1004 i_pos += i_bytes_read;
1005 } while( i_bytes_read == 0x800 && !b_stop_scanning);
1007 if( b_stop_scanning)
1010 "CSS: Found enough occurancies of the same key." );
1014 intf_WarnMsg( 3, "CSS: This file was _NOT_ encrypted!");
1017 if( b_encrypted && i_registered_keys == 0 )
1019 intf_WarnMsg( 3 , "CSS: Unable to determine keys from file.");
1022 for( i=0 ; i<i_registered_keys-1 ; i++ )
1024 for( j=i+1 ; j<i_registered_keys ; j++ )
1026 if( title_key[j].i > title_key[i].i )
1028 memcpy( &my_key, &(title_key[j].key), sizeof(DVD_key_t) );
1030 memcpy( &(title_key[j].key),
1031 &(title_key[i].key), sizeof(DVD_key_t) );
1032 title_key[j].i = title_key[i].i;
1033 memcpy( &(title_key[i].key),&my_key, sizeof(DVD_key_t) );
1040 fprintf(stderr, " Key(s) & key probability\n---------------------\n");
1041 for( i=0 ; i<i_registered_keys ; i++ )
1043 fprintf(stderr, "%d) %02X %02X %02X %02X %02X - %3.2f%%\n", i,
1044 title_key[i].key[0], title_key[i].key[1],
1045 title_key[i].key[2], title_key[i].key[3],
1046 title_key[i].key[4],
1047 title_key[i].i * 100.0 / i_total_keys_found );
1048 if( title_key[i_highest].i * 100.0 / i_total_keys_found
1049 <= title_key[i].i*100.0 / i_total_keys_found )
1054 fprintf(stderr, "\n");
1057 /* The "find the key with the highest probability" code
1058 * is untested, as I haven't been able to find a VOB that
1059 * produces multiple keys (RT)
1061 intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X\n",
1063 title_key[i_highest].key[0],
1064 title_key[i_highest].key[1],
1065 title_key[i_highest].key[2],
1066 title_key[i_highest].key[3],
1067 title_key[i_highest].key[4] );
1069 memcpy( p_css->p_title_key[i_title].key,
1070 title_key[i_highest].key, KEY_SIZE );
1076 /*****************************************************************************
1077 * CSSDescrambleSector
1079 * sec : sector to descramble
1080 * key : title key for this sector
1081 *****************************************************************************/
1082 int CSSDescrambleSector( DVD_key_t key, u8* pi_sec )
1084 unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
1085 u8* pi_end = pi_sec + 0x800;
1087 if( pi_sec[0x14] & 0x30) // PES_scrambling_control
1089 i_t1 = ((key)[0] ^ pi_sec[0x54]) | 0x100;
1090 i_t2 = (key)[1] ^ pi_sec[0x55];
1091 i_t3 = (((key)[2]) | ((key)[3] << 8) |
1092 ((key)[4] << 16)) ^ ((pi_sec[0x56]) |
1093 (pi_sec[0x57] << 8) | (pi_sec[0x58] << 16));
1095 i_t3 = i_t3 * 2 + 8 - i_t4;
1099 while( pi_sec != pi_end )
1101 i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
1103 i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
1104 i_t4 = pi_css_tab5[i_t4];
1105 i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
1106 i_t3 ) >> 8 ) ^ i_t3 ) >> 5) & 0xff;
1107 i_t3 = (i_t3 << 8 ) | i_t6;
1108 i_t6 = pi_css_tab4[i_t6];
1109 i_t5 += i_t6 + i_t4;
1110 *pi_sec++ = pi_css_tab1[*pi_sec] ^( i_t5 & 0xff );