css.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 1,697 行 · 第 1/4 页
C
1,697 行
/***************************************************************************** * css.c: Functions for DVD authentication and descrambling ***************************************************************************** * Copyright (C) 1999-2003 VideoLAN * $Id: css.c,v 1.3 2008/04/12 07:14:44 dsqiu Exp $ * * Authors: St閜hane Borel <stef@via.ecp.fr> * H錵an Hjort <d95hjort@dtek.chalmers.se> * * based on: * - css-auth by Derek Fawcus <derek@spider.com> * - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net> * - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com> * (see http://www-2.cs.cmu.edu/~dst/DeCSS/FrankStevenson/index.html) * - DeCSSPlus by Ethan Hawke * - DecVOB * see http://www.lemuria.org/DeCSS/ by Tom Vogt for more information. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include "config.h"#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <sys/types.h>#include <sys/stat.h>#ifdef HAVE_SYS_PARAM_H# include <sys/param.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#ifdef HAVE_LIMITS_H# include <limits.h>#endif#include "dvdcss/dvdcss.h"#include "common.h"#include "css.h"#include "libdvdcss.h"#include "csstables.h"#include "ioctl.h"#include "device.h"#undef memcpy#define memcpy uc_memcpy/***************************************************************************** * Local prototypes *****************************************************************************/static void PrintKey ( dvdcss_t, char *, uint8_t const * );static int GetBusKey ( dvdcss_t );static int GetASF ( dvdcss_t );static void CryptKey ( int, int, uint8_t const *, uint8_t * );static void DecryptKey ( uint8_t, uint8_t const *, uint8_t const *, uint8_t * );static int DecryptDiscKey ( dvdcss_t, uint8_t const *, dvd_key_t );static int CrackDiscKey ( dvdcss_t, uint8_t * );static void DecryptTitleKey ( dvd_key_t, dvd_key_t );static int RecoverTitleKey ( int, uint8_t const *, uint8_t const *, uint8_t const *, uint8_t * );static int CrackTitleKey ( dvdcss_t, int, int, dvd_key_t );static int AttackPattern ( uint8_t const[], int, uint8_t * );#if 0static int AttackPadding ( uint8_t const[], int, uint8_t * );#endif/***************************************************************************** * _dvdcss_test: check if the disc is encrypted or not *****************************************************************************/int _dvdcss_test( dvdcss_t dvdcss ){ int i_ret, i_copyright; i_ret = ioctl_ReadCopyright( dvdcss->i_fd, 0 /* i_layer */, &i_copyright );#ifdef WIN32 if( i_ret < 0 ) { /* Maybe we didn't have enough privileges to read the copyright * (see ioctl_ReadCopyright comments). * Apparently, on unencrypted DVDs _dvdcss_disckey() always fails, so * we can check this as a workaround. */ i_ret = 0; i_copyright = 1; if( _dvdcss_disckey( dvdcss ) < 0 ) { i_copyright = 0; } }#endif if( i_ret < 0 ) { /* Since it's the first ioctl we try to issue, we add a notice */ print_error( dvdcss, "css error: ioctl_ReadCopyright failed, " "make sure there is a DVD in the drive, and that " "you have used the correct device node." ); return i_ret; } return i_copyright;}/***************************************************************************** * _dvdcss_title: crack or decrypt the current title key if needed ***************************************************************************** * This function should only be called by dvdcss->pf_seek and should eventually * not be external if possible. *****************************************************************************/int _dvdcss_title ( dvdcss_t dvdcss, int i_block ){ dvd_title_t *p_title; dvd_title_t *p_newtitle; dvd_key_t p_title_key; int i_fd, i_ret = -1, b_cache = 0; if( ! dvdcss->b_scrambled ) { return 0; } /* Check if we've already cracked this key */ p_title = dvdcss->p_titles; while( p_title != NULL && p_title->p_next != NULL && p_title->p_next->i_startlb <= i_block ) { p_title = p_title->p_next; } if( p_title != NULL && p_title->i_startlb == i_block ) { /* We've already cracked this key, nothing to do */ memcpy( dvdcss->css.p_title_key, p_title->p_key, sizeof(dvd_key_t) ); return 0; } /* Check whether the key is in our disk cache */ if( dvdcss->psz_cachefile[0] ) { /* XXX: be careful, we use sprintf and not snprintf */ sprintf( dvdcss->psz_block, "%.10x", i_block ); i_fd = open( dvdcss->psz_cachefile, O_RDONLY ); b_cache = 1; if( i_fd >= 0 ) { char psz_key[KEY_SIZE * 3]; unsigned int k0, k1, k2, k3, k4; psz_key[KEY_SIZE * 3 - 1] = '\0'; if( read( i_fd, psz_key, KEY_SIZE * 3 - 1 ) == KEY_SIZE * 3 - 1 && sscanf( psz_key, "%x:%x:%x:%x:%x", &k0, &k1, &k2, &k3, &k4 ) == 5 ) { p_title_key[0] = k0; p_title_key[1] = k1; p_title_key[2] = k2; p_title_key[3] = k3; p_title_key[4] = k4; PrintKey( dvdcss, "title key found in cache ", p_title_key ); /* Don't try to save it again */ b_cache = 0; i_ret = 1; } close( i_fd ); } } /* Crack or decrypt CSS title key for current VTS */ if( i_ret < 0 ) { i_ret = _dvdcss_titlekey( dvdcss, i_block, p_title_key ); if( i_ret < 0 ) { print_error( dvdcss, "fatal error in vts css key" ); return i_ret; } if( i_ret == 0 ) { print_debug( dvdcss, "unencrypted title" ); /* We cache this anyway, so we don't need to check again. */ } } /* Key is valid, we store it on disk. */ if( dvdcss->psz_cachefile[0] && b_cache ) { i_fd = open( dvdcss->psz_cachefile, O_RDWR|O_CREAT, 0644 ); if( i_fd >= 0 ) { char psz_key[KEY_SIZE * 3 + 2]; sprintf( psz_key, "%02x:%02x:%02x:%02x:%02x\r\n", p_title_key[0], p_title_key[1], p_title_key[2], p_title_key[3], p_title_key[4] ); write( i_fd, psz_key, KEY_SIZE * 3 + 1 ); close( i_fd ); } } /* Find our spot in the list */ p_newtitle = NULL; p_title = dvdcss->p_titles; while( ( p_title != NULL ) && ( p_title->i_startlb < i_block ) ) { p_newtitle = p_title; p_title = p_title->p_next; } /* Save the found title */ p_title = p_newtitle; /* Write in the new title and its key */ p_newtitle = malloc( sizeof( dvd_title_t ) ); p_newtitle->i_startlb = i_block; memcpy( p_newtitle->p_key, p_title_key, KEY_SIZE ); /* Link it at the head of the (possibly empty) list */ if( p_title == NULL ) { p_newtitle->p_next = dvdcss->p_titles; dvdcss->p_titles = p_newtitle; } /* Link the new title inside the list */ else { p_newtitle->p_next = p_title->p_next; p_title->p_next = p_newtitle; } memcpy( dvdcss->css.p_title_key, p_title_key, KEY_SIZE ); return 0;}/***************************************************************************** * _dvdcss_disckey: get disc key. ***************************************************************************** * This function should only be called if DVD ioctls are present. * It will set dvdcss->i_method = DVDCSS_METHOD_TITLE if it fails to find * a valid disc key. * Two decryption methods are offered: * -disc key hash crack, * -decryption with player keys if they are available. *****************************************************************************/int _dvdcss_disckey( dvdcss_t dvdcss ){ unsigned char p_buffer[ DVD_DISCKEY_SIZE ]; dvd_key_t p_disc_key; int i; if( GetBusKey( dvdcss ) < 0 ) { return -1; } /* Get encrypted disc key */ if( ioctl_ReadDiscKey( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0 ) { print_error( dvdcss, "ioctl ReadDiscKey failed" ); return -1; } /* This should have invaidated the AGID and got us ASF=1. */ if( GetASF( dvdcss ) != 1 ) { /* Region mismatch (or region not set) is the most likely source. */ print_error( dvdcss, "ASF not 1 after reading disc key (region mismatch?)" ); ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); return -1; } /* Shuffle disc key using bus key */ for( i = 0 ; i < DVD_DISCKEY_SIZE ; i++ ) { p_buffer[ i ] ^= dvdcss->css.p_bus_key[ 4 - (i % KEY_SIZE) ]; } /* Decrypt disc key */ switch( dvdcss->i_method ) { case DVDCSS_METHOD_KEY: /* Decrypt disc key with player key. */ PrintKey( dvdcss, "decrypting disc key ", p_buffer ); if( ! DecryptDiscKey( dvdcss, p_buffer, p_disc_key ) ) { PrintKey( dvdcss, "decrypted disc key is ", p_disc_key ); break; } print_debug( dvdcss, "failed to decrypt the disc key, " "faulty drive/kernel? " "cracking title keys instead" ); /* Fallback, but not to DISC as the disc key might be faulty */ dvdcss->i_method = DVDCSS_METHOD_TITLE; break; case DVDCSS_METHOD_DISC: /* Crack Disc key to be able to use it */ memcpy( p_disc_key, p_buffer, KEY_SIZE ); PrintKey( dvdcss, "cracking disc key ", p_disc_key ); if( ! CrackDiscKey( dvdcss, p_disc_key ) ) { PrintKey( dvdcss, "cracked disc key is ", p_disc_key ); break; } print_debug( dvdcss, "failed to crack the disc key" ); memset( p_disc_key, 0, KEY_SIZE ); dvdcss->i_method = DVDCSS_METHOD_TITLE; break; default: print_debug( dvdcss, "disc key needs not be decrypted" ); memset( p_disc_key, 0, KEY_SIZE ); break; } memcpy( dvdcss->css.p_disc_key, p_disc_key, KEY_SIZE ); return 0;}/***************************************************************************** * _dvdcss_titlekey: get title key. *****************************************************************************/int _dvdcss_titlekey( dvdcss_t dvdcss, int i_pos, dvd_key_t p_title_key ){ static uint8_t p_garbage[ DVDCSS_BLOCK_SIZE ]; /* we never read it back */ uint8_t p_key[ KEY_SIZE ]; int i, i_ret = 0; if( dvdcss->b_ioctls && ( dvdcss->i_method == DVDCSS_METHOD_KEY || dvdcss->i_method == DVDCSS_METHOD_DISC ) ) { /* We have a decrypted Disc key and the ioctls are available, * read the title key and decrypt it. */ print_debug( dvdcss, "getting title key at block %i the classic way", i_pos ); /* We need to authenticate again every time to get a new session key */ if( GetBusKey( dvdcss ) < 0 ) { return -1; } /* Get encrypted title key */ if( ioctl_ReadTitleKey( dvdcss->i_fd, &dvdcss->css.i_agid, i_pos, p_key ) < 0 ) { print_debug( dvdcss, "ioctl ReadTitleKey failed (region mismatch?)" ); i_ret = -1; } /* Test ASF, it will be reset to 0 if we got a Region error */ switch( GetASF( dvdcss ) ) { case -1: /* An error getting the ASF status, something must be wrong. */ print_debug( dvdcss, "lost ASF requesting title key" ); ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); i_ret = -1; break; case 0: /* This might either be a title that has no key, * or we encountered a region error. */ print_debug( dvdcss, "lost ASF requesting title key" ); break; case 1: /* Drive status is ok. */ /* If the title key request failed, but we did not loose ASF, * we might stil have the AGID. Other code assume that we * will not after this so invalidate it(?). */ if( i_ret < 0 ) { ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); } break; } if( !( i_ret < 0 ) ) { /* Decrypt title key using the bus key */ for( i = 0 ; i < KEY_SIZE ; i++ )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?