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 + -
显示快捷键?