comparison libmpdvdkit2/libdvdcss.c @ 9333:f0f0f176d298

sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...) patch by Andreas Hess <jaska@gmx.net>
author arpi
date Sat, 08 Feb 2003 00:22:39 +0000
parents ddf6a9f4cc6a
children cbc01dc4b773
comparison
equal deleted inserted replaced
9332:a604236b0dd6 9333:f0f0f176d298
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. 13 * (at your option) any later version.
14 * 14 *
15 * This program is distributed in the hope that it will be useful, 15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details. 18 * GNU General Public License for more details.
19 * 19 *
20 * You should have received a copy of the GNU General Public License 20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. 22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 */ 23 */
24 24
25 /** 25 /**
26 * \mainpage libdvdcss developer documentation 26 * \mainpage libdvdcss developer documentation
27 * 27 *
28 * \section intro Introduction 28 * \section intro Introduction
29 * 29 *
30 * \e libdvdcss is a simple library designed for accessing DVDs like a block 30 * \e libdvdcss is a simple library designed for accessing DVDs like a block
75 * because there is not enough encrypted data on the disc to perform 75 * because there is not enough encrypted data on the disc to perform
76 * a statistical attack, but in the other hand it is the only way to 76 * a statistical attack, but in the other hand it is the only way to
77 * decrypt a DVD stored on a hard disc, or a DVD with the wrong region 77 * decrypt a DVD stored on a hard disc, or a DVD with the wrong region
78 * on an RPC2 drive. 78 * on an RPC2 drive.
79 * 79 *
80 * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use. 80 * \li \b DVDCSS_RAW_DEVICE: specify the raw device to use. Exact usage will
81 * 81 * depend on your operating system, the Linux utility to set up raw devices
82 * is \c raw(8) for instance. Please note that on most operating systems,
83 * using a raw device requires highly aligned buffers: Linux requires a
84 * 2048 bytes alignment (which is the size of a DVD sector).
85 *
86 * \li \b DVDCSS_CACHE: specify a directory in which to store title key
87 * values. This will speed up descrambling of DVDs which are in the
88 * cache. The DVDCSS_CACHE directory is created if it does not exist,
89 * and a subdirectory is created named after the DVD's title or
90 * manufacturing date.
82 */ 91 */
83 92
84 /* 93 /*
85 * Preamble 94 * Preamble
86 */ 95 */
90 #include <stdlib.h> 99 #include <stdlib.h>
91 #include <string.h> 100 #include <string.h>
92 #include <sys/types.h> 101 #include <sys/types.h>
93 #include <sys/stat.h> 102 #include <sys/stat.h>
94 #include <fcntl.h> 103 #include <fcntl.h>
95 104 #include <errno.h>
96 #ifdef HAVE_UNISTD_H 105 #include <unistd.h>
97 # include <unistd.h> 106 #include <limits.h>
98 #endif
99 107
100 #include "dvdcss.h" 108 #include "dvdcss.h"
101 109
102 #include "common.h" 110 #include "common.h"
103 #include "css.h" 111 #include "css.h"
115 * The variable itself contains the exact version number of the library, 123 * The variable itself contains the exact version number of the library,
116 * which can be useful for specific feature needs. 124 * which can be useful for specific feature needs.
117 */ 125 */
118 char * dvdcss_interface_2 = VERSION; 126 char * dvdcss_interface_2 = VERSION;
119 127
120 char * dvdcss_cache_dir = NULL;
121
122 /** 128 /**
123 * \brief Open a DVD device or directory and return a dvdcss instance. 129 * \brief Open a DVD device or directory and return a dvdcss instance.
124 * 130 *
125 * \param psz_target a string containing the target name, for instance 131 * \param psz_target a string containing the target name, for instance
126 * "/dev/hdc" or "E:". 132 * "/dev/hdc" or "E:".
137 { 143 {
138 int i_ret; 144 int i_ret;
139 145
140 char *psz_method = getenv( "DVDCSS_METHOD" ); 146 char *psz_method = getenv( "DVDCSS_METHOD" );
141 char *psz_verbose = getenv( "DVDCSS_VERBOSE" ); 147 char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
148 char *psz_cache = getenv( "DVDCSS_CACHE" );
142 #ifndef WIN32 149 #ifndef WIN32
143 char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" ); 150 char *psz_raw_device = getenv( "DVDCSS_RAW_DEVICE" );
144 #endif 151 #endif
145 152
146 dvdcss_t dvdcss; 153 dvdcss_t dvdcss;
162 #endif 169 #endif
163 dvdcss->p_titles = NULL; 170 dvdcss->p_titles = NULL;
164 dvdcss->psz_device = (char *)strdup( psz_target ); 171 dvdcss->psz_device = (char *)strdup( psz_target );
165 dvdcss->psz_error = "no error"; 172 dvdcss->psz_error = "no error";
166 dvdcss->i_method = DVDCSS_METHOD_KEY; 173 dvdcss->i_method = DVDCSS_METHOD_KEY;
174 dvdcss->psz_cachefile[0] = '\0';
167 dvdcss->b_debug = 0; 175 dvdcss->b_debug = 0;
168 dvdcss->b_errors = 0; 176 dvdcss->b_errors = 0;
169 dvdcss->psz_cache = NULL;
170 177
171 /* 178 /*
172 * Find verbosity from DVDCSS_VERBOSE environment variable 179 * Find verbosity from DVDCSS_VERBOSE environment variable
173 */ 180 */
174 if( psz_verbose != NULL ) 181 if( psz_verbose != NULL )
209 free( dvdcss ); 216 free( dvdcss );
210 return NULL; 217 return NULL;
211 } 218 }
212 } 219 }
213 220
214 if(!dvdcss_cache_dir) dvdcss_cache_dir = getenv( "DVDCSS_CACHE" ); 221 /*
222 * Find cache dir from the DVDCSS_CACHE environment variable
223 */
224 if( psz_cache != NULL )
225 {
226 if( psz_cache[0] == '\0' )
227 {
228 psz_cache = NULL;
229 }
230 /* Check that we can add the ID directory and the block filename */
231 else if( strlen( psz_cache ) + 1 + 32 + 1 + 10 + 1 > PATH_MAX )
232 {
233 _dvdcss_error( dvdcss, "cache directory name is too long" );
234 psz_cache = NULL;
235 }
236 }
237 else psz_cache = get_path( "DVDKeys" );
215 238
216 /* 239 /*
217 * Open device 240 * Open device
218 */ 241 */
219 i_ret = _dvdcss_open( dvdcss ); 242 i_ret = _dvdcss_open( dvdcss );
221 { 244 {
222 free( dvdcss->psz_device ); 245 free( dvdcss->psz_device );
223 free( dvdcss ); 246 free( dvdcss );
224 return NULL; 247 return NULL;
225 } 248 }
226 249
227 dvdcss->b_scrambled = 1; /* Assume the worst */ 250 dvdcss->b_scrambled = 1; /* Assume the worst */
228 dvdcss->b_ioctls = _dvdcss_use_ioctls( dvdcss ); 251 dvdcss->b_ioctls = _dvdcss_use_ioctls( dvdcss );
229 252
230 if( dvdcss->b_ioctls ) 253 if( dvdcss->b_ioctls )
231 { 254 {
232 i_ret = _dvdcss_test( dvdcss ); 255 i_ret = _dvdcss_test( dvdcss );
233 if( i_ret < 0 ) 256 if( i_ret < 0 )
234 { 257 {
235 /* Disable the CSS ioctls and hope that it works? */ 258 /* Disable the CSS ioctls and hope that it works? */
236 _dvdcss_debug( dvdcss, 259 _dvdcss_debug( dvdcss,
237 "could not check whether the disc was scrambled" ); 260 "could not check whether the disc was scrambled" );
238 dvdcss->b_ioctls = 0; 261 dvdcss->b_ioctls = 0;
239 } 262 }
240 else 263 else
241 { 264 {
242 _dvdcss_debug( dvdcss, i_ret ? "disc is scrambled" 265 _dvdcss_debug( dvdcss, i_ret ? "disc is scrambled"
243 : "disc is unscrambled" ); 266 : "disc is unscrambled" );
244 dvdcss->b_scrambled = i_ret; 267 dvdcss->b_scrambled = i_ret;
245 } 268 }
246 } 269 }
247 270
248 /* If disc is CSS protected and the ioctls work, authenticate the drive */ 271 /* If disc is CSS protected and the ioctls work, authenticate the drive */
249 if( dvdcss->b_scrambled && dvdcss->b_ioctls ) 272 if( dvdcss->b_scrambled && dvdcss->b_ioctls )
250 { 273 {
264 { 287 {
265 _dvdcss_raw_open( dvdcss, psz_raw_device ); 288 _dvdcss_raw_open( dvdcss, psz_raw_device );
266 } 289 }
267 #endif 290 #endif
268 291
269 /* if the CACHE is enabled, extract some unique disc ID */ 292 /* If the cache is enabled, extract a unique disc ID */
270 if(dvdcss_cache_dir){ 293 if( psz_cache )
271 char* disc_id=NULL; 294 {
272 /*char title_name[64];*/ 295 uint8_t p_sector[DVDCSS_BLOCK_SIZE];
273 char sector[DVDCSS_BLOCK_SIZE]; 296 unsigned char psz_debug[PATH_MAX+30];
274 // 32768+40 -> disc title (32 uppercase chars) 297 unsigned char * psz_data;
275 // 32768+813 -> disc manufacturing date + serial no (16 digit number) 298 int i;
276 int ret=dvdcss->pf_seek( dvdcss, 32768/DVDCSS_BLOCK_SIZE); 299
277 //printf("disc_id seek: %d -> %d, i_fd=%d i_read_fd=%d\n",32768/DVDCSS_BLOCK_SIZE,ret,dvdcss->i_fd,dvdcss->i_read_fd); 300 /* We read sector 0. If it starts with 0x000001ba (BE), we are
278 if(dvdcss->pf_read( dvdcss, sector, 1) == 1){ 301 * reading a VOB file, and we should not cache anything. */
279 // check disc title first: 302
280 char* title_name=&sector[40]; 303 i_ret = dvdcss->pf_seek( dvdcss, 0 );
281 int i=0; 304 if( i_ret != 0 )
282 while(i<32 && title_name[i]>='0' && title_name[i]<='z') i++; 305 {
283 title_name[i]=0; 306 goto nocache;
284 if(i>5){ 307 }
285 disc_id=strdup(title_name); 308
286 } else { 309 i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
287 // use disc date+serial: 310 if( i_ret != 1 )
288 title_name=&sector[813]; 311 {
289 title_name[16]=0; 312 goto nocache;
290 for ( i=0;i<16;i++ ) 313 }
291 if ( ( title_name[i] < '0' )||( title_name[i] > '9' ) ){ 314
292 disc_id=malloc(16+4); 315 if( p_sector[0] == 0x00 && p_sector[1] == 0x00
293 snprintf( disc_id,17,"%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X",title_name[0],title_name[1],title_name[2],title_name[3],title_name[4],title_name[5],title_name[6],title_name[7] ); 316 && p_sector[2] == 0x01 && p_sector[3] == 0xba )
294 break; 317 {
295 } 318 goto nocache;
296 if(!disc_id) disc_id=strdup(title_name); 319 }
297 } 320
298 if(disc_id){ 321 /* The data we are looking for is at sector 16 (32768 bytes):
299 // yeah, we have a disc name/id, let's set up cache path: 322 * - offset 40: disc title (32 uppercase chars)
300 /*char* dir;*/ 323 * - offset 813: manufacturing date + serial no (16 digits) */
301 dvdcss->psz_cache = malloc(strlen(dvdcss_cache_dir)+strlen(disc_id)+4); 324
302 sprintf(dvdcss->psz_cache,"%s/%s",dvdcss_cache_dir,disc_id); 325 i_ret = dvdcss->pf_seek( dvdcss, 16 );
303 mkdir( dvdcss->psz_cache,493 ); 326 if( i_ret != 16 )
304 free(disc_id); 327 {
305 fprintf(stderr,"Using CSS Key-cache dir: %s\n",dvdcss->psz_cache); 328 goto nocache;
306 } 329 }
307 } 330
308 } 331 i_ret = dvdcss->pf_read( dvdcss, p_sector, 1 );
332 if( i_ret != 1 )
333 {
334 goto nocache;
335 }
336
337 /* Get the disc title */
338 psz_data = p_sector + 40;
339 psz_data[32] = '\0';
340
341 for( i = 0 ; i < 32 ; i++ )
342 {
343 if( psz_data[i] <= ' ' )
344 {
345 psz_data[i] = '\0';
346 break;
347 }
348 else if( psz_data[i] == '/' || psz_data[i] == '\\' )
349 {
350 psz_data[i] = '-';
351 }
352 }
353
354 /* If it's not long enough, try the date + serial */
355 if( strlen( psz_data ) < 6 )
356 {
357 psz_data = p_sector + 813;
358 psz_data[16] = '\0';
359
360 /* Check that all characters are digits, otherwise convert. */
361 for( i = 0 ; i < 16 ; i++ )
362 {
363 if( psz_data[i] < '0' || psz_data[i] > '9' )
364 {
365 sprintf( psz_data,
366 "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X",
367 psz_data[0], psz_data[1], psz_data[2],
368 psz_data[3], psz_data[4], psz_data[5],
369 psz_data[6], psz_data[7] );
370 break;
371 }
372 }
373 }
374
375 /* We have a disc name or ID, we can create the cache dir */
376 i = sprintf( dvdcss->psz_cachefile, "%s", psz_cache );
377 #if !defined( WIN32 ) || defined( SYS_CYGWIN )
378 i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
379 #else
380 i_ret = mkdir( dvdcss->psz_cachefile );
381 #endif
382 if( i_ret < 0 && errno != EEXIST )
383 {
384 _dvdcss_error( dvdcss, "failed creating cache directory" );
385 dvdcss->psz_cachefile[0] = '\0';
386 goto nocache;
387 }
388
389 i += sprintf( dvdcss->psz_cachefile + i, "/%s/", psz_data );
390 #if !defined( WIN32 ) || defined( SYS_CYGWIN )
391 i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
392 #else
393 i_ret = mkdir( dvdcss->psz_cachefile );
394 #endif
395 if( i_ret < 0 && errno != EEXIST )
396 {
397 _dvdcss_error( dvdcss, "failed creating cache subdirectory" );
398 dvdcss->psz_cachefile[0] = '\0';
399 goto nocache;
400 }
401
402 /* Pointer to the filename we will use. */
403 dvdcss->psz_block = dvdcss->psz_cachefile + i;
404
405 sprintf( psz_debug, "using CSS key cache dir: %s",
406 dvdcss->psz_cachefile );
407 _dvdcss_debug( dvdcss, psz_debug );
408 }
409 nocache:
410
411 /* Seek at the beginning, just for safety. */
412 dvdcss->pf_seek( dvdcss, 0 );
309 413
310 return dvdcss; 414 return dvdcss;
311 } 415 }
312 416
313 /** 417 /**
352 */ 456 */
353 extern int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags ) 457 extern int dvdcss_seek ( dvdcss_t dvdcss, int i_blocks, int i_flags )
354 { 458 {
355 /* title cracking method is too slow to be used at each seek */ 459 /* title cracking method is too slow to be used at each seek */
356 if( ( ( i_flags & DVDCSS_SEEK_MPEG ) 460 if( ( ( i_flags & DVDCSS_SEEK_MPEG )
357 && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) ) 461 && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) )
358 || ( i_flags & DVDCSS_SEEK_KEY ) ) 462 || ( i_flags & DVDCSS_SEEK_KEY ) )
359 { 463 {
360 /* check the title key */ 464 /* check the title key */
361 if( _dvdcss_title( dvdcss, i_blocks ) ) 465 if( _dvdcss_title( dvdcss, i_blocks ) )
362 { 466 {
363 return -1; 467 return -1;
364 } 468 }
365 } 469 }
366 470
405 return i_ret; 509 return i_ret;
406 } 510 }
407 511
408 if( ! memcmp( dvdcss->css.p_title_key, "\0\0\0\0\0", 5 ) ) 512 if( ! memcmp( dvdcss->css.p_title_key, "\0\0\0\0\0", 5 ) )
409 { 513 {
410 /* For what we believe is an unencrypted title, 514 /* For what we believe is an unencrypted title,
411 * check that there are no encrypted blocks */ 515 * check that there are no encrypted blocks */
412 for( i_index = i_ret; i_index; i_index-- ) 516 for( i_index = i_ret; i_index; i_index-- )
413 { 517 {
414 if( ((u8*)p_buffer)[0x14] & 0x30 ) 518 if( ((uint8_t*)p_buffer)[0x14] & 0x30 )
415 { 519 {
416 _dvdcss_error( dvdcss, "no key but found encrypted block" ); 520 _dvdcss_error( dvdcss, "no key but found encrypted block" );
417 /* Only return the initial range of unscrambled blocks? */ 521 /* Only return the initial range of unscrambled blocks? */
418 /* or fail completely? return 0; */ 522 /* or fail completely? return 0; */
419 break; 523 break;
420 } 524 }
421 p_buffer = (void *) ((u8 *)p_buffer + DVDCSS_BLOCK_SIZE); 525 p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE);
422 } 526 }
423 } 527 }
424 else 528 else
425 { 529 {
426 /* Decrypt the blocks we managed to read */ 530 /* Decrypt the blocks we managed to read */
427 for( i_index = i_ret; i_index; i_index-- ) 531 for( i_index = i_ret; i_index; i_index-- )
428 { 532 {
429 _dvdcss_unscramble( dvdcss->css.p_title_key, p_buffer ); 533 _dvdcss_unscramble( dvdcss->css.p_title_key, p_buffer );
430 ((u8*)p_buffer)[0x14] &= 0x8f; 534 ((uint8_t*)p_buffer)[0x14] &= 0x8f;
431 p_buffer = (void *) ((u8 *)p_buffer + DVDCSS_BLOCK_SIZE); 535 p_buffer = (void *) ((uint8_t *)p_buffer + DVDCSS_BLOCK_SIZE);
432 } 536 }
433 } 537 }
434 538
435 return i_ret; 539 return i_ret;
436 } 540 }
437 541
438 /** 542 /**
439 * \brief Read from the disc into multiple buffers and decrypt data if 543 * \brief Read from the disc into multiple buffers and decrypt data if
500 iov_base = _p_iovec->iov_base; 604 iov_base = _p_iovec->iov_base;
501 iov_len = _p_iovec->iov_len; 605 iov_len = _p_iovec->iov_len;
502 } 606 }
503 607
504 _dvdcss_unscramble( dvdcss->css.p_title_key, iov_base ); 608 _dvdcss_unscramble( dvdcss->css.p_title_key, iov_base );
505 ((u8*)iov_base)[0x14] &= 0x8f; 609 ((uint8_t*)iov_base)[0x14] &= 0x8f;
506 610
507 iov_base = (void *) ((u8*)iov_base + DVDCSS_BLOCK_SIZE); 611 iov_base = (void *) ((uint8_t*)iov_base + DVDCSS_BLOCK_SIZE);
508 iov_len -= DVDCSS_BLOCK_SIZE; 612 iov_len -= DVDCSS_BLOCK_SIZE;
509 } 613 }
510 614
511 return i_ret; 615 return i_ret;
512 } 616 }