summaryrefslogtreecommitdiffstats
path: root/libdvdcss/css.c
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2011-03-01 22:37:15 +0200
committerUoti Urpala <uau@glyph.nonexistent.invalid>2011-03-01 22:37:15 +0200
commitb27e4ca37126e95f806d92bb8a2e38c14965376e (patch)
tree8dce7baa7cabb4e6dbacf6c72ccae64fb58b30a3 /libdvdcss/css.c
parente786c70de9a65c44f575ab8c61ff00fbbd2df585 (diff)
downloadmpv-b27e4ca37126e95f806d92bb8a2e38c14965376e.tar.bz2
mpv-b27e4ca37126e95f806d92bb8a2e38c14965376e.tar.xz
libdvdcss: drop internal libdvdcss tree
The internal libdvdcss version was only compiled if you used internal libdvdread too; and libdvdread was not included in the sources, so that'd only happen if you manually added libdvdread in the build tree. Keeping libdvdcss for that case probably isn't worth it, so delete it from the tree. The build system part is still there, so an internal build is possible if you add the directory back.
Diffstat (limited to 'libdvdcss/css.c')
-rw-r--r--libdvdcss/css.c1731
1 files changed, 0 insertions, 1731 deletions
diff --git a/libdvdcss/css.c b/libdvdcss/css.c
deleted file mode 100644
index 886a803efd..0000000000
--- a/libdvdcss/css.c
+++ /dev/null
@@ -1,1731 +0,0 @@
-/*****************************************************************************
- * css.c: Functions for DVD authentication and descrambling
- *****************************************************************************
- * Copyright (C) 1999-2008 VideoLAN
- * $Id$
- *
- * Authors: Stéphane Borel <stef@via.ecp.fr>
- * Håkan 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 library 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 library 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 library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
-#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"
-
-/*****************************************************************************
- * 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 0
-static int AttackPadding ( uint8_t const[], int, uint8_t * );
-#endif
-
-/*****************************************************************************
- * _dvdcss_test: check if the disc is encrypted or not
- *****************************************************************************
- * Sets b_scrambled, b_ioctls
- *****************************************************************************/
-void _dvdcss_test( dvdcss_t dvdcss )
-{
- char const *psz_type, *psz_rpc;
- int i_ret, i_copyright, i_type, i_mask, i_rpc;
-
- i_ret = ioctl_ReadCopyright( dvdcss->i_fd, 0 /* i_layer */, &i_copyright );
-
- 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. */
-#ifdef WIN32
- i_ret = 0;
-#else
- /* Since it's the first ioctl we try to issue, we add a notice */
- print_error( dvdcss, "css error: could not get \"copyright\""
- " information, make sure there is a DVD in the drive,"
- " and that you have used the correct device node." );
- /* Try without ioctls */
- dvdcss->b_ioctls = 0;
-#endif
- i_copyright = 1;
- if( _dvdcss_disckey( dvdcss ) < 0 )
- {
- i_copyright = 0;
- }
- }
-
- print_debug( dvdcss, "disc reports copyright information 0x%x",
- i_copyright );
- dvdcss->b_scrambled = i_copyright;
-
- i_ret = ioctl_ReportRPC( dvdcss->i_fd, &i_type, &i_mask, &i_rpc);
-
- if( i_ret < 0 )
- {
- print_error( dvdcss, "css error: could not get RPC status, region-free drive?" );
- return;
- }
-
- switch( i_rpc )
- {
- case 0: psz_rpc = "RPC-I"; break;
- case 1: psz_rpc = "RPC-II"; break;
- default: psz_rpc = "unknown RPC scheme"; break;
- }
-
- switch( i_type )
- {
- case 0: psz_type = "no region code set"; break;
- case 1: psz_type = "region code set"; break;
- case 2: psz_type = "one region change remaining"; break;
- case 3: psz_type = "region code set permanently"; break;
- default: psz_type = "unknown status"; break;
- }
-
- print_debug( dvdcss, "drive region mask 0x%x, %s, %s",
- i_mask, psz_rpc, psz_type );
-
- if( i_copyright && i_rpc == 1 && i_type == 0 )
- {
- print_error( dvdcss, "css error: drive will prevent access to "
- "scrambled data" );
- }
-}
-
-/*****************************************************************************
- * _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 */
- memset( p_disc_key, 0, KEY_SIZE );
- 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 )
- {
- i_ret = -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++ )
- {
- p_key[ i ] ^= dvdcss->css.p_bus_key[ 4 - (i % KEY_SIZE) ];
- }
-
- /* If p_key is all zero then there really wasn't any key present
- * even though we got to read it without an error. */
- if( !( p_key[0] | p_key[1] | p_key[2] | p_key[3] | p_key[4] ) )
- {
- i_ret = 0;
- }
- else
- {
- PrintKey( dvdcss, "initial disc key ", dvdcss->css.p_disc_key );
- DecryptTitleKey( dvdcss->css.p_disc_key, p_key );
- PrintKey( dvdcss, "decrypted title key ", p_key );
- i_ret = 1;
- }
-
- /* All went well either there wasn't a key or we have it now. */
- memcpy( p_title_key, p_key, KEY_SIZE );
- PrintKey( dvdcss, "title key is ", p_title_key );
-
- return i_ret;
- }
-
- /* The title key request failed */
- print_debug( dvdcss, "resetting drive and cracking title key" );
-
- /* Read an unscrambled sector and reset the drive */
- dvdcss->pf_seek( dvdcss, 0 );
- dvdcss->pf_read( dvdcss, p_garbage, 1 );
- dvdcss->pf_seek( dvdcss, 0 );
- _dvdcss_disckey( dvdcss );
-
- /* Fallback */
- }
-
- /* METHOD is TITLE, we can't use the ioctls or requesting the title key
- * failed above. For these cases we try to crack the key instead. */
-
- /* For now, the read limit is 9Gb / 2048 = 4718592 sectors. */
- i_ret = CrackTitleKey( dvdcss, i_pos, 4718592, p_key );
-
- memcpy( p_title_key, p_key, KEY_SIZE );
- PrintKey( dvdcss, "title key is ", p_title_key );
-
- return i_ret;
-}
-
-/*****************************************************************************
- * _dvdcss_unscramble: does the actual descrambling of data
- *****************************************************************************
- * sec : sector to unscramble
- * key : title key for this sector
- *****************************************************************************/
-int _dvdcss_unscramble( dvd_key_t p_key, uint8_t *p_sec )
-{
- unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
- uint8_t *p_end = p_sec + DVDCSS_BLOCK_SIZE;
-
- /* PES_scrambling_control */
- if( !(p_sec[0x14] & 0x30) )
- {
- return 0;
- }
-
- i_t1 = (p_key[0] ^ p_sec[0x54]) | 0x100;
- i_t2 = p_key[1] ^ p_sec[0x55];
- i_t3 = (p_key[2] | (p_key[3] << 8) |
- (p_key[4] << 16)) ^ (p_sec[0x56] |
- (p_sec[0x57] << 8) | (p_sec[0x58] << 16));
- i_t4 = i_t3 & 7;
- i_t3 = i_t3 * 2 + 8 - i_t4;
- p_sec += 0x80;
- i_t5 = 0;
-
- while( p_sec != p_end )
- {
- i_t4 = p_css_tab2[i_t2] ^ p_css_tab3[i_t1];
- i_t2 = i_t1>>1;
- i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
- i_t4 = p_css_tab5[i_t4];
- i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
- i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
- i_t3 = (i_t3 << 8 ) | i_t6;
- i_t6 = p_css_tab4[i_t6];
- i_t5 += i_t6 + i_t4;
- *p_sec = p_css_tab1[*p_sec] ^ ( i_t5 & 0xff );
- p_sec++;
- i_t5 >>= 8;
- }
-
- return 0;
-}
-
-/* Following functions are local */
-
-/*****************************************************************************
- * 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;
- int i_ret = -1;
- int i;
-
- print_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 )
- {
- print_debug( dvdcss, "ioctl ReportAgid failed, "
- "invalidating AGID %d", i );
-
- /* This is really _not good_, should be handled by the OS.
- * Invalidating an AGID could make another process fail somewhere
- * in its authentication process. */
- dvdcss->css.i_agid = i;
- ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
-
- print_debug( dvdcss, "requesting AGID" );
- i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
- }
-
- /* Unable to authenticate without AGID */
- if( i_ret == -1 )
- {
- print_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 )
- {
- print_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)
- {
- print_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 )
- {
- print_debug( dvdcss, "drive authenticated, using variant %d", i );
- i_variant = i;
- break;
- }
- }
-
- if( i == 32 )
- {
- print_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 )
- {
- print_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 )
- {
- print_error( dvdcss, "ioctl SendKey2 failed" );
- ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
- return -1;
- }
-
- /* The drive has accepted us as authentic. */
- print_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 )
-{
- print_debug( dvdcss, "%s%02x:%02x:%02x:%02x:%02x", prefix,
- data[0], data[1], data[2], data[3], data[4] );
-}
-
-/*****************************************************************************
- * GetASF : Get Authentication success flag
- *****************************************************************************
- * Returns :
- * -1 on ioctl error,
- * 0 if the device needs to be authenticated,
- * 1 either.
- *****************************************************************************/
-static int GetASF( dvdcss_t dvdcss )
-{
- int i_asf = 0;
-
- if( ioctl_ReportASF( dvdcss->i_fd, NULL, &i_asf ) != 0 )
- {
- /* The ioctl process has failed */
- print_error( dvdcss, "GetASF fatal error" );
- return -1;
- }
-
- if( i_asf )
- {
- print_debug( dvdcss, "GetASF authenticated, ASF=1" );
- }
- else
- {
- print_debug( dvdcss, "GetASF not authenticated, ASF=0" );
- }
-
- return i_asf;
-}
-
-/*****************************************************************************
- * CryptKey : shuffles bits and unencrypt keys.
- *****************************************************************************
- * Used during authentication and disc key negociation in GetBusKey.
- * i_key_type : 0->key1, 1->key2, 2->buskey.
- * i_variant : between 0 and 31.
- *****************************************************************************/
-static void CryptKey( int i_key_type, int i_variant,
- uint8_t const *p_challenge, uint8_t *p_key )
-{
- /* Permutation table for challenge */
- uint8_t pp_perm_challenge[3][10] =
- { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 },
- { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 },
- { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } };
-
- /* Permutation table for variant table for key2 and buskey */
- uint8_t pp_perm_variant[2][32] =
- { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d,
- 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d,
- 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05,
- 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 },
- { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e,
- 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c,
- 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f,
- 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } };
-
- uint8_t p_variants[32] =
- { 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73,
- 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42,
- 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B,
- 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 };
-
- /* The "secret" key */
- uint8_t p_secret[5] = { 0x55, 0xD6, 0xC4, 0xC5, 0x28 };
-
- uint8_t p_bits[30], p_scratch[10], p_tmp1[5], p_tmp2[5];
- uint8_t i_lfsr0_o; /* 1 bit used */
- uint8_t i_lfsr1_o; /* 1 bit used */
- uint8_t i_css_variant, i_cse, i_index, i_combined, i_carry;
- uint8_t i_val = 0;
- uint32_t i_lfsr0, i_lfsr1;
- int i_term = 0;
- int i_bit;
- int i;
-
- for (i = 9; i >= 0; --i)
- p_scratch[i] = p_challenge[pp_perm_challenge[i_key_type][i]];
-
- i_css_variant = ( i_key_type == 0 ) ? i_variant :
- pp_perm_variant[i_key_type-1][i_variant];
-
- /*
- * This encryption engine implements one of 32 variations
- * one the same theme depending upon the choice in the
- * variant parameter (0 - 31).
- *
- * The algorithm itself manipulates a 40 bit input into
- * a 40 bit output.
- * The parameter 'input' is 80 bits. It consists of
- * the 40 bit input value that is to be encrypted followed
- * by a 40 bit seed value for the pseudo random number
- * generators.
- */
-
- /* Feed the secret into the input values such that
- * we alter the seed to the LFSR's used above, then
- * generate the bits to play with.
- */
- for( i = 5 ; --i >= 0 ; )
- {
- p_tmp1[i] = p_scratch[5 + i] ^ p_secret[i] ^ p_crypt_tab2[i];
- }
-
- /*
- * We use two LFSR's (seeded from some of the input data bytes) to
- * generate two streams of pseudo-random bits. These two bit streams
- * are then combined by simply adding with carry to generate a final
- * sequence of pseudo-random bits which is stored in the buffer that
- * 'output' points to the end of - len is the size of this buffer.
- *
- * The first LFSR is of degree 25, and has a polynomial of:
- * x^13 + x^5 + x^4 + x^1 + 1
- *
- * The second LSFR is of degree 17, and has a (primitive) polynomial of:
- * x^15 + x^1 + 1
- *
- * I don't know if these polynomials are primitive modulo 2, and thus
- * represent maximal-period LFSR's.
- *
- *
- * Note that we take the output of each LFSR from the new shifted in
- * bit, not the old shifted out bit. Thus for ease of use the LFSR's
- * are implemented in bit reversed order.
- *
- */
-
- /* In order to ensure that the LFSR works we need to ensure that the
- * initial values are non-zero. Thus when we initialise them from
- * the seed, we ensure that a bit is set.
- */
- i_lfsr0 = ( p_tmp1[0] << 17 ) | ( p_tmp1[1] << 9 ) |
- (( p_tmp1[2] & ~7 ) << 1 ) | 8 | ( p_tmp1[2] & 7 );
- i_lfsr1 = ( p_tmp1[3] << 9 ) | 0x100 | p_tmp1[4];
-
- i_index = sizeof(p_bits);
- i_carry = 0;
-
- do
- {
- for( i_bit = 0, i_val = 0 ; i_bit < 8 ; ++i_bit )
- {
-
- i_lfsr0_o = ( ( i_lfsr0 >> 24 ) ^ ( i_lfsr0 >> 21 ) ^
- ( i_lfsr0 >> 20 ) ^ ( i_lfsr0 >> 12 ) ) & 1;
- i_lfsr0 = ( i_lfsr0 << 1 ) | i_lfsr0_o;
-
- i_lfsr1_o = ( ( i_lfsr1 >> 16 ) ^ ( i_lfsr1 >> 2 ) ) & 1;
- i_lfsr1 = ( i_lfsr1 << 1 ) | i_lfsr1_o;
-
- i_combined = !i_lfsr1_o + i_carry + !i_lfsr0_o;
- /* taking bit 1 */
- i_carry = ( i_combined >> 1 ) & 1;
- i_val |= ( i_combined & 1 ) << i_bit;
- }
-
- p_bits[--i_index] = i_val;
- } while( i_index > 0 );
-
- /* This term is used throughout the following to
- * select one of 32 different variations on the
- * algorithm.
- */
- i_cse = p_variants[i_css_variant] ^ p_crypt_tab2[i_css_variant];
-
- /* Now the actual blocks doing the encryption. Each
- * of these works on 40 bits at a time and are quite
- * similar.
- */
- i_index = 0;
- for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_scratch[i] )
- {
- i_index = p_bits[25 + i] ^ p_scratch[i];
- i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
-
- p_tmp1[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
- }
- p_tmp1[4] ^= p_tmp1[0];
-
- for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
- {
- i_index = p_bits[20 + i] ^ p_tmp1[i];
- i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
-
- p_tmp2[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
- }
- p_tmp2[4] ^= p_tmp2[0];
-
- for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] )
- {
- i_index = p_bits[15 + i] ^ p_tmp2[i];
- i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
- i_index = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
-
- p_tmp1[i] = p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index];
- }
- p_tmp1[4] ^= p_tmp1[0];
-
- for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
- {
- i_index = p_bits[10 + i] ^ p_tmp1[i];
- i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
-
- i_index = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
-
- p_tmp2[i] = p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index];
- }
- p_tmp2[4] ^= p_tmp2[0];
-
- for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] )
- {
- i_index = p_bits[5 + i] ^ p_tmp2[i];
- i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
-
- p_tmp1[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
- }
- p_tmp1[4] ^= p_tmp1[0];
-
- for(i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
- {
- i_index = p_bits[i] ^ p_tmp1[i];
- i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
-
- p_key[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
- }
-
- return;
-}
-
-/*****************************************************************************
- * DecryptKey: decrypt p_crypted with p_key.
- *****************************************************************************
- * Used to decrypt the disc key, with a player key, after requesting it
- * in _dvdcss_disckey and to decrypt title keys, with a disc key, requested
- * in _dvdcss_titlekey.
- * The player keys and the resulting disc key are only used as KEKs
- * (key encryption keys).
- * Decryption is slightly dependant on the type of key:
- * -for disc key, invert is 0x00,
- * -for title key, invert if 0xff.
- *****************************************************************************/
-static void DecryptKey( uint8_t invert, uint8_t const *p_key,
- uint8_t const *p_crypted, uint8_t *p_result )
-{
- unsigned int i_lfsr1_lo;
- unsigned int i_lfsr1_hi;
- unsigned int i_lfsr0;
- unsigned int i_combined;
- uint8_t o_lfsr0;
- uint8_t o_lfsr1;
- uint8_t k[5];
- int i;
-
- i_lfsr1_lo = p_key[0] | 0x100;
- i_lfsr1_hi = p_key[1];
-
- i_lfsr0 = ( ( p_key[4] << 17 )
- | ( p_key[3] << 9 )
- | ( p_key[2] << 1 ) )
- + 8 - ( p_key[2] & 7 );
- i_lfsr0 = ( p_css_tab4[i_lfsr0 & 0xff] << 24 ) |
- ( p_css_tab