⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 css.c

📁 python的多媒体包,可以实现很多漂亮的功能哦
💻 C
📖 第 1 页 / 共 4 页
字号:
/*****************************************************************************
 * css.c: Functions for DVD authentication and descrambling
 *****************************************************************************
 * Copyright (C) 1999-2001 VideoLAN
 * $Id: css.c,v 1.2 2004/11/20 20:19:30 jbors Exp $
 *
 * Author: 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>
 *  - 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_PARAM_H
#   include <sys/param.h>
#endif
#if !defined( WIN32 )
#   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"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
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  ( 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 0
static 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 priviledges to read the copyright
         * (see ioctl_ReadCopyright comments).
         * Apparently, on unencrypted DVDs _dvdcss_disckey() always fails, so
         * we can check this as a work-around. */
        i_ret = 0;
        if( _dvdcss_disckey( dvdcss ) < 0 )
            i_copyright = 0;
        else
            i_copyright = 1;
    }
#endif

    if( i_ret < 0 )
    {
        /* Since it's the first ioctl we try to issue, we add a notice */
        _dvdcss_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;
}

/*****************************************************************************
 * GetBusKey : Go through the CSS Authentication process
 *****************************************************************************
 * It simulates the mutual authentication between logical unit and host,
 * and stops when a session key (called bus key) has been established.
 * Always do the full auth sequence. Some drives seem to lie and always
 * respond with ASF=1.  For instance the old DVD roms on Compaq Armada says
 * that ASF=1 from the start and then later fail with a 'read of scrambled
 * block without authentication' error.
 *****************************************************************************/
static int GetBusKey( dvdcss_t dvdcss )
{
    uint8_t   p_buffer[10];
    uint8_t   p_challenge[2*KEY_SIZE];
    dvd_key_t p_key1;
    dvd_key_t p_key2;
    dvd_key_t p_key_check;
    uint8_t   i_variant = 0;
    char      psz_warning[80];
    int       i_ret = -1;
    int       i;

    _dvdcss_debug( dvdcss, "requesting AGID" );
    i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );

    /* We might have to reset hung authentication processes in the drive
       by invalidating the corresponding AGID'.  As long as we haven't got
       an AGID, invalidate one (in sequence) and try again. */
    for( i = 0; i_ret == -1 && i < 4 ; ++i )
    {
        sprintf( psz_warning,
                 "ioctl ReportAgid failed, invalidating AGID %d", i );
        _dvdcss_debug( dvdcss, psz_warning );

        /* This is really _not good_, should be handled by the OS.
           Invalidating an AGID could make another process fail some
           where in it's authentication process. */
        dvdcss->css.i_agid = i;
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );

        _dvdcss_debug( dvdcss, "requesting AGID" );
        i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
    }

    /* Unable to authenticate without AGID */
    if( i_ret == -1 )
    {
        _dvdcss_error( dvdcss, "ioctl ReportAgid failed, fatal" );
        return -1;
    }

    /* Setup a challenge, any values should work */
    for( i = 0 ; i < 10; ++i )
    {
        p_challenge[i] = i;
    }

    /* Get challenge from host */
    for( i = 0 ; i < 10 ; ++i )
    {
        p_buffer[9-i] = p_challenge[i];
    }

    /* Send challenge to LU */
    if( ioctl_SendChallenge( dvdcss->i_fd,
                             &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
        _dvdcss_error( dvdcss, "ioctl SendChallenge failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Get key1 from LU */
    if( ioctl_ReportKey1( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0)
    {
        _dvdcss_error( dvdcss, "ioctl ReportKey1 failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Send key1 to host */
    for( i = 0 ; i < KEY_SIZE ; i++ )
    {
        p_key1[i] = p_buffer[4-i];
    }

    for( i = 0 ; i < 32 ; ++i )
    {
        CryptKey( 0, i, p_challenge, p_key_check );

        if( memcmp( p_key_check, p_key1, KEY_SIZE ) == 0 )
        {
            snprintf( psz_warning, sizeof(psz_warning),
                      "drive authenticated, using variant %d", i );
            _dvdcss_debug( dvdcss, psz_warning );
            i_variant = i;
            break;
        }
    }

    if( i == 32 )
    {
        _dvdcss_error( dvdcss, "drive would not authenticate" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Get challenge from LU */
    if( ioctl_ReportChallenge( dvdcss->i_fd,
                               &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
        _dvdcss_error( dvdcss, "ioctl ReportKeyChallenge failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Send challenge to host */
    for( i = 0 ; i < 10 ; ++i )
    {
        p_challenge[i] = p_buffer[9-i];
    }

    CryptKey( 1, i_variant, p_challenge, p_key2 );

    /* Get key2 from host */
    for( i = 0 ; i < KEY_SIZE ; ++i )
    {
        p_buffer[4-i] = p_key2[i];
    }

    /* Send key2 to LU */
    if( ioctl_SendKey2( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
        _dvdcss_error( dvdcss, "ioctl SendKey2 failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* The drive has accepted us as authentic. */
    _dvdcss_debug( dvdcss, "authentication established" );

    memcpy( p_challenge, p_key1, KEY_SIZE );
    memcpy( p_challenge + KEY_SIZE, p_key2, KEY_SIZE );

    CryptKey( 2, i_variant, p_challenge, dvdcss->css.p_bus_key );

    return 0;
}

/*****************************************************************************
 * PrintKey : debug function that dumps a key value
 *****************************************************************************/
static void PrintKey( dvdcss_t dvdcss, char *prefix, uint8_t const *data )
{
    char psz_output[80];

    sprintf( psz_output, "%s%02x:%02x:%02x:%02x:%02x", prefix,
             data[0], data[1], data[2], data[3], data[4] );
    _dvdcss_debug( dvdcss, psz_output );
}

/*****************************************************************************
 * _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 )
        {
            if( read( i_fd, p_title_key, 5 ) == 5 )
            {
                _dvdcss_debug( dvdcss, "key found in cache" );
                /* 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 )
        {
            _dvdcss_error( dvdcss, "fatal error in vts css key" );
            return i_ret;
        }

        if( i_ret == 0 )
        {
            _dvdcss_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( b_cache )
    {
        i_fd = open( dvdcss->psz_cachefile, O_RDWR|O_CREAT|O_EXCL, 0644 );
        if( i_fd >= 0 )
        {
            write( i_fd, p_title_key, 5 );
            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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -