📄 css.c
字号:
* Function designed by Frank Stevenson
*****************************************************************************
* Called from Attack* which are in turn called by CrackTitleKey. Given
* a guessed(?) plain text and the cipher text. Returns -1 on failure.
*****************************************************************************/
static int RecoverTitleKey( int i_start, uint8_t const *p_crypted,
uint8_t const *p_decrypted,
uint8_t const *p_sector_seed, uint8_t *p_key )
{
uint8_t p_buffer[10];
unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
unsigned int i_try;
unsigned int i_candidate;
unsigned int i, j;
int i_exit = -1;
for( i = 0 ; i < 10 ; i++ )
{
p_buffer[i] = p_css_tab1[p_crypted[i]] ^ p_decrypted[i];
}
for( i_try = i_start ; i_try < 0x10000 ; i_try++ )
{
i_t1 = i_try >> 8 | 0x100;
i_t2 = i_try & 0xff;
i_t3 = 0; /* not needed */
i_t5 = 0;
/* iterate cipher 4 times to reconstruct LFSR2 */
for( i = 0 ; i < 4 ; i++ )
{
/* advance LFSR1 normaly */
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];
/* deduce i_t6 & i_t5 */
i_t6 = p_buffer[i];
if( i_t5 )
{
i_t6 = ( i_t6 + 0xff ) & 0x0ff;
}
if( i_t6 < i_t4 )
{
i_t6 += 0x100;
}
i_t6 -= i_t4;
i_t5 += i_t6 + i_t4;
i_t6 = p_css_tab4[ i_t6 ];
/* feed / advance i_t3 / i_t5 */
i_t3 = ( i_t3 << 8 ) | i_t6;
i_t5 >>= 8;
}
i_candidate = i_t3;
/* iterate 6 more times to validate candidate key */
for( ; i < 10 ; i++ )
{
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;
if( ( i_t5 & 0xff ) != p_buffer[i] )
{
break;
}
i_t5 >>= 8;
}
if( i == 10 )
{
/* Do 4 backwards steps of iterating t3 to deduce initial state */
i_t3 = i_candidate;
for( i = 0 ; i < 4 ; i++ )
{
i_t1 = i_t3 & 0xff;
i_t3 = ( i_t3 >> 8 );
/* easy to code, and fast enough bruteforce
* search for byte shifted in */
for( j = 0 ; j < 256 ; j++ )
{
i_t3 = ( i_t3 & 0x1ffff ) | ( j << 17 );
i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
if( i_t6 == i_t1 )
{
break;
}
}
}
i_t4 = ( i_t3 >> 1 ) - 4;
for( i_t5 = 0 ; i_t5 < 8; i_t5++ )
{
if( ( ( i_t4 + i_t5 ) * 2 + 8 - ( (i_t4 + i_t5 ) & 7 ) )
== i_t3 )
{
p_key[0] = i_try>>8;
p_key[1] = i_try & 0xFF;
p_key[2] = ( ( i_t4 + i_t5 ) >> 0 ) & 0xFF;
p_key[3] = ( ( i_t4 + i_t5 ) >> 8 ) & 0xFF;
p_key[4] = ( ( i_t4 + i_t5 ) >> 16 ) & 0xFF;
i_exit = i_try + 1;
}
}
}
}
if( i_exit >= 0 )
{
p_key[0] ^= p_sector_seed[0];
p_key[1] ^= p_sector_seed[1];
p_key[2] ^= p_sector_seed[2];
p_key[3] ^= p_sector_seed[3];
p_key[4] ^= p_sector_seed[4];
}
return i_exit;
}
/******************************************************************************
* Various pices for the title crack engine.
******************************************************************************
* The length of the PES packet is located at 0x12-0x13.
* The the copyrigth protection bits are located at 0x14 (bits 0x20 and 0x10).
* The data of the PES packet begins at 0x15 (if there isn't any PTS/DTS)
* or at 0x?? if there are both PTS and DTS's.
* The seed value used with the unscrambling key is the 5 bytes at 0x54-0x58.
* The scrabled part of a sector begins at 0x80.
*****************************************************************************/
/* Statistics */
static int i_tries = 0, i_success = 0;
/*****************************************************************************
* CrackTitleKey: try to crack title key from the contents of a VOB.
*****************************************************************************
* This function is called by _dvdcss_titlekey to find a title key, if we've
* chosen to crack title key instead of decrypting it with the disc key.
* The DVD should have been opened and be in an authenticated state.
* i_pos is the starting sector, i_len is the maximum number of sectors to read
*****************************************************************************/
static int CrackTitleKey( dvdcss_t dvdcss, int i_pos, int i_len,
dvd_key_t p_titlekey )
{
uint8_t p_buf[ DVDCSS_BLOCK_SIZE ];
const uint8_t p_packstart[4] = { 0x00, 0x00, 0x01, 0xba };
int i_reads = 0;
int i_encrypted = 0;
int b_stop_scanning = 0;
int b_read_error = 0;
int i_ret;
_dvdcss_debug( dvdcss, "cracking title key" );
i_tries = 0;
i_success = 0;
do
{
i_ret = dvdcss->pf_seek( dvdcss, i_pos );
if( i_ret != i_pos )
{
_dvdcss_error( dvdcss, "seek failed" );
}
i_ret = dvdcss_read( dvdcss, p_buf, 1, DVDCSS_NOFLAGS );
/* Either we are at the end of the physical device or the auth
* have failed / were not done and we got a read error. */
if( i_ret <= 0 )
{
if( i_ret == 0 )
{
_dvdcss_debug( dvdcss, "read returned 0 (end of device?)" );
}
else if( !b_read_error )
{
_dvdcss_debug( dvdcss, "read error, resorting to secret "
"arcanes to recover" );
/* Reset the drive before trying to continue */
_dvdcss_close( dvdcss );
_dvdcss_open( dvdcss );
b_read_error = 1;
continue;
}
break;
}
/* Stop when we find a non MPEG stream block.
* (We must have reached the end of the stream).
* For now, allow all blocks that begin with a start code. */
if( memcmp( p_buf, p_packstart, 3 ) )
{
_dvdcss_debug( dvdcss, "non MPEG block found (end of title)" );
break;
}
if( p_buf[0x0d] & 0x07 )
_dvdcss_debug( dvdcss, "stuffing in pack header" );
/* PES_scrambling_control does not exist in a system_header,
* a padding_stream or a private_stream2 (and others?). */
if( p_buf[0x14] & 0x30 && ! ( p_buf[0x11] == 0xbb
|| p_buf[0x11] == 0xbe
|| p_buf[0x11] == 0xbf ) )
{
i_encrypted++;
if( AttackPattern(p_buf, i_reads, p_titlekey) > 0 )
{
b_stop_scanning = 1;
}
#if 0
if( AttackPadding(p_buf, i_reads, p_titlekey) > 0 )
{
b_stop_scanning = 1;
}
#endif
}
i_pos++;
i_len--;
i_reads++;
/* Emit a progress indication now and then. */
if( !( i_reads & 0xfff ) )
{
_dvdcss_debug( dvdcss, "still cracking..." );
}
/* Stop after 2000 blocks if we haven't seen any encrypted blocks. */
if( i_reads >= 2000 && i_encrypted == 0 ) break;
} while( !b_stop_scanning && i_len > 0);
if( !b_stop_scanning )
{
_dvdcss_debug( dvdcss, "end of title reached" );
}
{ /* Print some statistics. */
char psz_info[128];
snprintf( psz_info, sizeof(psz_info),
"%d of %d attempts successful, %d of %d blocks scrambled",
i_success, i_tries, i_encrypted, i_reads );
_dvdcss_debug( dvdcss, psz_info );
}
if( i_success > 0 /* b_stop_scanning */ )
{
_dvdcss_debug( dvdcss, "vts key initialized" );
return 1;
}
if( i_encrypted == 0 && i_reads > 0 )
{
memset( p_titlekey, 0, KEY_SIZE );
_dvdcss_debug( dvdcss, "file was unscrambled" );
return 0;
}
memset( p_titlekey, 0, KEY_SIZE );
return -1;
}
/******************************************************************************
* The original Ethan Hawke (DeCSSPlus) attack (modified).
******************************************************************************
* Tries to find a repeating pattern just before the encrypted part starts.
* Then it guesses that the plain text for first encrypted bytes are
* a contiuation of that pattern.
*****************************************************************************/
static int AttackPattern( uint8_t const p_sec[ DVDCSS_BLOCK_SIZE ],
int i_pos, uint8_t *p_key )
{
unsigned int i_best_plen = 0;
unsigned int i_best_p = 0;
unsigned int i, j;
/* For all cycle length from 2 to 48 */
for( i = 2 ; i < 0x30 ; i++ )
{
/* Find the number of bytes that repeats in cycles. */
for( j = i + 1;
j < 0x80 && ( p_sec[0x7F - (j%i)] == p_sec[0x7F - j] );
j++ )
{
/* We have found j repeating bytes with a cycle length i. */
if( j > i_best_plen )
{
i_best_plen = j;
i_best_p = i;
}
}
}
/* We need at most 10 plain text bytes?, so a make sure that we
* have at least 20 repeated bytes and that they have cycled at
* least one time. */
if( ( i_best_plen > 3 ) && ( i_best_plen / i_best_p >= 2) )
{
int res;
i_tries++;
memset( p_key, 0, KEY_SIZE );
res = RecoverTitleKey( 0, &p_sec[0x80],
&p_sec[ 0x80 - (i_best_plen / i_best_p) * i_best_p ],
&p_sec[0x54] /* key_seed */, p_key );
i_success += ( res >= 0 );
#if 0
if( res >= 0 )
{
fprintf( stderr, "key is %02x:%02x:%02x:%02x:%02x ",
p_key[0], p_key[1], p_key[2], p_key[3], p_key[4] );
fprintf( stderr, "at block %5d pattern len %3d period %3d %s\n",
i_pos, i_best_plen, i_best_p, (res>=0?"y":"n") );
}
#endif
return ( res >= 0 );
}
return 0;
}
#if 0
/******************************************************************************
* Encrypted Padding_stream attack.
******************************************************************************
* DVD specifies that there must only be one type of data in every sector.
* Every sector is one pack and so must obviously be 2048 bytes long.
* For the last pice of video data before a VOBU boundary there might not
* be exactly the right amount of data to fill a sector. Then one has to
* pad the pack to 2048 bytes. For just a few bytes this is done in the
* header but for any large amount you insert a PES packet from the
* Padding stream. This looks like 0x00 00 01 be xx xx ff ff ...
* where xx xx is the length of the padding stream.
*****************************************************************************/
static int AttackPadding( uint8_t const p_sec[ DVDCSS_BLOCK_SIZE ],
int i_pos, uint8_t *p_key )
{
unsigned int i_pes_length;
/*static int i_tries = 0, i_success = 0;*/
i_pes_length = (p_sec[0x12]<<8) | p_sec[0x13];
/* Coverd by the test below but usfull for debuging. */
if( i_pes_length == DVDCSS_BLOCK_SIZE - 0x14 ) return 0;
/* There must be room for at least 4? bytes of padding stream,
* and it must be encrypted.
* sector size - pack/pes header - padding startcode - padding length */
if( ( DVDCSS_BLOCK_SIZE - 0x14 - 4 - 2 - i_pes_length < 4 ) ||
( p_sec[0x14 + i_pes_length + 0] == 0x00 &&
p_sec[0x14 + i_pes_length + 1] == 0x00 &&
p_sec[0x14 + i_pes_length + 2] == 0x01 ) )
{
fprintf( stderr, "plain %d %02x:%02x:%02x:%02x (type %02x sub %02x)\n",
DVDCSS_BLOCK_SIZE - 0x14 - 4 - 2 - i_pes_length,
p_sec[0x14 + i_pes_length + 0],
p_sec[0x14 + i_pes_length + 1],
p_sec[0x14 + i_pes_length + 2],
p_sec[0x14 + i_pes_length + 3],
p_sec[0x11], p_sec[0x17 + p_sec[0x16]]);
return 0;
}
/* If we are here we know that there is a where in the pack a
encrypted PES header is (startcode + length). It's never more
than two packets in the pack, so we 'know' the length. The
plaintext at offset (0x14 + i_pes_length) will then be
00 00 01 e0/bd/be xx xx, in the case of be the following bytes
are also known. */
/* An encrypted SPU PES packet with another encrypted PES packet following.
Normaly if the following was a padding stream that would be in plain
text. So it will be another SPU PES packet. */
if( p_sec[0x11] == 0xbd &&
p_sec[0x17 + p_sec[0x16]] >= 0x20 &&
p_sec[0x17 + p_sec[0x16]] <= 0x3f )
{
i_tries++;
}
/* A Video PES packet with another encrypted PES packet following.
* No reason execpt for time stamps to break the data into two packets.
* So it's likely that the following PES packet is a padding stream. */
if( p_sec[0x11] == 0xe0 )
{
i_tries++;
}
if( 1 )
{
/*fprintf( stderr, "key is %02x:%02x:%02x:%02x:%02x ",
p_key[0], p_key[1], p_key[2], p_key[3], p_key[4] );*/
fprintf( stderr, "at block %5d padding len %4d "
"type %02x sub %02x\n", i_pos, i_pes_length,
p_sec[0x11], p_sec[0x17 + p_sec[0x16]]);
}
return 0;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -