css.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 1,697 行 · 第 1/4 页

C
1,697
字号
    free( BigTable );    return 0;}/***************************************************************************** * RecoverTitleKey: (title) key recovery from cipher and plain text * 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 pieces 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;    print_debug( dvdcss, "cracking title key at block %i", i_pos );    i_tries = 0;    i_success = 0;    do    {        i_ret = dvdcss->pf_seek( dvdcss, i_pos );        if( i_ret != i_pos )        {            print_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 )            {                print_debug( dvdcss, "read returned 0 (end of device?)" );            }            else if( !b_read_error )            {                print_debug( dvdcss, "read error at block %i, resorting to "                                     "secret arcanes to recover", i_pos );                /* 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 ) )        {            print_debug( dvdcss, "non MPEG block found at block %i "                                 "(end of title)", i_pos );            break;        }        if( p_buf[0x0d] & 0x07 )            print_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 ) )        {            print_debug( dvdcss, "at block %i, still cracking...", i_pos );        }        /* 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 )    {        print_debug( dvdcss, "end of title reached" );    }    /* Print some statistics. */    print_debug( dvdcss, "successful attempts %d/%d, scrambled blocks %d/%d",                         i_success, i_tries, i_encrypted, i_reads );    if( i_success > 0 /* b_stop_scanning */ )    {        print_debug( dvdcss, "vts key initialized" );        return 1;    }    if( i_encrypted == 0 && i_reads > 0 )    {        memset( p_titlekey, 0, KEY_SIZE );        print_debug( dvdcss, "no scrambled sectors found" );        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 + =
减小字号Ctrl + -
显示快捷键?