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

📄 drms.c

📁 WINCE mp4 format source
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
 * drms.c: DRMS
 *****************************************************************************
 * Copyright (C) 2004 VideoLAN
 * $Id: drms.c,v 1.7 2005/02/01 13:15:55 menno Exp $
 *
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
 *          Sam Hocevar <sam@zoy.org>
 *
 * 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.
 *****************************************************************************/

#include <stdlib.h>                                      /* malloc(), free() */

#ifndef _WIN32
#include "config.h"
#endif
#include "mp4ffint.h"

#ifdef ITUNES_DRM

#ifdef _WIN32
#   include <io.h>
#   include <stdio.h>
#   include <sys/stat.h>
#   define PATH_MAX MAX_PATH
#else
#   include <stdio.h>
#endif

#ifdef HAVE_ERRNO_H
#   include <errno.h>
#endif

#ifdef _WIN32
#   include <tchar.h>
#   include <shlobj.h>
#   include <windows.h>
#endif

#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#   include <sys/types.h>
#endif

/* In Solaris (and perhaps others) PATH_MAX is in limits.h. */
#ifdef HAVE_LIMITS_H
#   include <limits.h>
#endif

#ifdef HAVE_IOKIT_IOKITLIB_H
#   include <mach/mach.h>
#   include <IOKit/IOKitLib.h>
#   include <CoreFoundation/CFNumber.h>
#endif

#ifdef HAVE_SYSFS_LIBSYSFS_H
#   include <sysfs/libsysfs.h>
#endif

#include "drms.h"
#include "drmstables.h"

/*****************************************************************************
 * aes_s: AES keys structure
 *****************************************************************************
 * This structure stores a set of keys usable for encryption and decryption
 * with the AES/Rijndael algorithm.
 *****************************************************************************/
struct aes_s
{
    uint32_t pp_enc_keys[ AES_KEY_COUNT + 1 ][ 4 ];
    uint32_t pp_dec_keys[ AES_KEY_COUNT + 1 ][ 4 ];
};

/*****************************************************************************
 * md5_s: MD5 message structure
 *****************************************************************************
 * This structure stores the static information needed to compute an MD5
 * hash. It has an extra data buffer to allow non-aligned writes.
 *****************************************************************************/
struct md5_s
{
    uint64_t i_bits;      /* Total written bits */
    uint32_t p_digest[4]; /* The MD5 digest */
    uint32_t p_data[16];  /* Buffer to cache non-aligned writes */
};

/*****************************************************************************
 * shuffle_s: shuffle structure
 *****************************************************************************
 * This structure stores the static information needed to shuffle data using
 * a custom algorithm.
 *****************************************************************************/
struct shuffle_s
{
    uint32_t p_commands[ 20 ];
    uint32_t p_bordel[ 16 ];
};

/*****************************************************************************
 * drms_s: DRMS structure
 *****************************************************************************
 * This structure stores the static information needed to decrypt DRMS data.
 *****************************************************************************/
struct drms_s
{
    uint32_t i_user;
    uint32_t i_key;
    uint8_t  p_iviv[ 16 ];
    uint8_t *p_name;

    uint32_t p_key[ 4 ];
    struct aes_s aes;

    char     psz_homedir[ PATH_MAX ];
};

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static void InitAES       ( struct aes_s *, uint32_t * );
static void DecryptAES    ( struct aes_s *, uint32_t *, const uint32_t * );

static void InitMD5       ( struct md5_s * );
static void AddMD5        ( struct md5_s *, const uint8_t *, uint32_t );
static void EndMD5        ( struct md5_s * );
static void Digest        ( struct md5_s *, uint32_t * );

static void InitShuffle   ( struct shuffle_s *, uint32_t * );
static void DoShuffle     ( struct shuffle_s *, uint32_t *, uint32_t );

static int GetSystemKey   ( uint32_t *, uint32_t );
static int WriteUserKey   ( void *, uint32_t * );
static int ReadUserKey    ( void *, uint32_t * );
static int GetUserKey     ( void *, uint32_t * );

static int GetSCIData     ( char *, uint32_t **, uint32_t * );
static int HashSystemInfo ( uint32_t * );
static int GetiPodID      ( int64_t * );

#ifdef WORDS_BIGENDIAN
/*****************************************************************************
 * Reverse: reverse byte order
 *****************************************************************************/
static __inline void Reverse( uint32_t *p_buffer, int n )
{
    int i;

    for( i = 0; i < n; i++ )
    {
        p_buffer[ i ] = GetDWLE(&p_buffer[ i ]);
    }
}
#    define REVERSE( p, n ) Reverse( p, n )
#else
#    define REVERSE( p, n )
#endif

/*****************************************************************************
 * BlockXOR: XOR two 128 bit blocks
 *****************************************************************************/
static __inline void BlockXOR( uint32_t *p_dest, uint32_t *p_s1, uint32_t *p_s2 )
{
    int i;

    for( i = 0; i < 4; i++ )
    {
        p_dest[ i ] = p_s1[ i ] ^ p_s2[ i ];
    }
}

/*****************************************************************************
 * drms_alloc: allocate a DRMS structure
 *****************************************************************************/
void *drms_alloc( char *psz_homedir )
{
    struct drms_s *p_drms;

    p_drms = malloc( sizeof(struct drms_s) );

    if( p_drms == NULL )
    {
        return NULL;
    }

    memset( p_drms, 0, sizeof(struct drms_s) );

    strncpy( p_drms->psz_homedir, psz_homedir, PATH_MAX );
    p_drms->psz_homedir[ PATH_MAX - 1 ] = '\0';

    return (void *)p_drms;
}

/*****************************************************************************
 * drms_free: free a previously allocated DRMS structure
 *****************************************************************************/
void drms_free( void *_p_drms )
{
    struct drms_s *p_drms = (struct drms_s *)_p_drms;

    if( p_drms->p_name != NULL )
    {
        free( (void *)p_drms->p_name );
    }

    free( p_drms );
}

/*****************************************************************************
 * drms_decrypt: unscramble a chunk of data
 *****************************************************************************/
void drms_decrypt( void *_p_drms, uint32_t *p_buffer, uint32_t i_bytes )
{
    struct drms_s *p_drms = (struct drms_s *)_p_drms;
    uint32_t p_key[ 4 ];
    unsigned int i_blocks;

    /* AES is a block cypher, round down the byte count */
    i_blocks = i_bytes / 16;
    i_bytes = i_blocks * 16;

    /* Initialise the key */
    memcpy( p_key, p_drms->p_key, 16 );

    /* Unscramble */
    while( i_blocks-- )
    {
        uint32_t p_tmp[ 4 ];

        REVERSE( p_buffer, 4 );
        DecryptAES( &p_drms->aes, p_tmp, p_buffer );
        BlockXOR( p_tmp, p_key, p_tmp );

        /* Use the previous scrambled data as the key for next block */
        memcpy( p_key, p_buffer, 16 );

        /* Copy unscrambled data back to the buffer */
        memcpy( p_buffer, p_tmp, 16 );
        REVERSE( p_buffer, 4 );

        p_buffer += 4;
    }
}

/*****************************************************************************
 * drms_init: initialise a DRMS structure
 *****************************************************************************/
int drms_init( void *_p_drms, uint32_t i_type,
               uint8_t *p_info, uint32_t i_len )
{
    struct drms_s *p_drms = (struct drms_s *)_p_drms;
    int i_ret = 0;

    switch( i_type )
    {
        case FOURCC_user:
            if( i_len < sizeof(p_drms->i_user) )
            {
                i_ret = -1;
                break;
            }

            p_drms->i_user = U32_AT( p_info );
            break;

        case FOURCC_key:
            if( i_len < sizeof(p_drms->i_key) )
            {
                i_ret = -1;
                break;
            }

            p_drms->i_key = U32_AT( p_info );
            break;

        case FOURCC_iviv:
            if( i_len < sizeof(p_drms->p_key) )
            {
                i_ret = -1;
                break;
            }

            memcpy( p_drms->p_iviv, p_info, 16 );
            break;

        case FOURCC_name:
            p_drms->p_name = strdup( p_info );

            if( p_drms->p_name == NULL )
            {
                i_ret = -1;
            }
            break;

        case FOURCC_priv:
        {
            uint32_t p_priv[ 64 ];
            struct md5_s md5;

            if( i_len < 64 )
            {
                i_ret = -1;
                break;
            }

            InitMD5( &md5 );
            AddMD5( &md5, p_drms->p_name, strlen( p_drms->p_name ) );
            AddMD5( &md5, p_drms->p_iviv, 16 );
            EndMD5( &md5 );

            if( GetUserKey( p_drms, p_drms->p_key ) )
            {
                i_ret = -1;
                break;
            }

            InitAES( &p_drms->aes, p_drms->p_key );

            memcpy( p_priv, p_info, 64 );
            memcpy( p_drms->p_key, md5.p_digest, 16 );
            drms_decrypt( p_drms, p_priv, 64 );
            REVERSE( p_priv, 64 );

            if( p_priv[ 0 ] != 0x6e757469 ) /* itun */
            {
                i_ret = -1;
                break;
            }

            InitAES( &p_drms->aes, p_priv + 6 );
            memcpy( p_drms->p_key, p_priv + 12, 16 );

            free( (void *)p_drms->p_name );
            p_drms->p_name = NULL;
        }
        break;
    }

    return i_ret;
}

/* The following functions are local */

/*****************************************************************************
 * InitAES: initialise AES/Rijndael encryption/decryption tables
 *****************************************************************************
 * The Advanced Encryption Standard (AES) is described in RFC 3268
 *****************************************************************************/
static void InitAES( struct aes_s *p_aes, uint32_t *p_key )
{
    unsigned int i, t;
    uint32_t i_key, i_seed;

    memset( p_aes->pp_enc_keys[1], 0, 16 );
    memcpy( p_aes->pp_enc_keys[0], p_key, 16 );

    /* Generate the key tables */
    i_seed = p_aes->pp_enc_keys[ 0 ][ 3 ];

    for( i_key = 0; i_key < AES_KEY_COUNT; i_key++ )
    {
        uint32_t j;

        i_seed = AES_ROR( i_seed, 8 );

        j = p_aes_table[ i_key ];

        j ^= p_aes_encrypt[ (i_seed >> 24) & 0xff ]
              ^ AES_ROR( p_aes_encrypt[ (i_seed >> 16) & 0xff ], 8 )
              ^ AES_ROR( p_aes_encrypt[ (i_seed >> 8) & 0xff ], 16 )
              ^ AES_ROR( p_aes_encrypt[ i_seed & 0xff ], 24 );

        j ^= p_aes->pp_enc_keys[ i_key ][ 0 ];
        p_aes->pp_enc_keys[ i_key + 1 ][ 0 ] = j;
        j ^= p_aes->pp_enc_keys[ i_key ][ 1 ];
        p_aes->pp_enc_keys[ i_key + 1 ][ 1 ] = j;
        j ^= p_aes->pp_enc_keys[ i_key ][ 2 ];
        p_aes->pp_enc_keys[ i_key + 1 ][ 2 ] = j;
        j ^= p_aes->pp_enc_keys[ i_key ][ 3 ];
        p_aes->pp_enc_keys[ i_key + 1 ][ 3 ] = j;

        i_seed = j;
    }

    memcpy( p_aes->pp_dec_keys[ 0 ],
            p_aes->pp_enc_keys[ 0 ], 16 );

    for( i = 1; i < AES_KEY_COUNT; i++ )
    {
        for( t = 0; t < 4; t++ )
        {
            uint32_t j, k, l, m, n;

            j = p_aes->pp_enc_keys[ i ][ t ];

            k = (((j >> 7) & 0x01010101) * 27) ^ ((j & 0xff7f7f7f) << 1);
            l = (((k >> 7) & 0x01010101) * 27) ^ ((k & 0xff7f7f7f) << 1);
            m = (((l >> 7) & 0x01010101) * 27) ^ ((l & 0xff7f7f7f) << 1);

            j ^= m;

            n = AES_ROR( l ^ j, 16 ) ^ AES_ROR( k ^ j, 8 ) ^ AES_ROR( j, 24 );

            p_aes->pp_dec_keys[ i ][ t ] = k ^ l ^ m ^ n;
        }
    }
}

/*****************************************************************************
 * DecryptAES: decrypt an AES/Rijndael 128 bit block
 *****************************************************************************/
static void DecryptAES( struct aes_s *p_aes,
                        uint32_t *p_dest, const uint32_t *p_src )
{
    uint32_t p_wtxt[ 4 ]; /* Working cyphertext */
    uint32_t p_tmp[ 4 ];
    unsigned int i_round, t;

    for( t = 0; t < 4; t++ )
    {
        /* FIXME: are there any endianness issues here? */
        p_wtxt[ t ] = p_src[ t ] ^ p_aes->pp_enc_keys[ AES_KEY_COUNT ][ t ];
    }

    /* Rounds 0 - 8 */
    for( i_round = 0; i_round < (AES_KEY_COUNT - 1); i_round++ )

⌨️ 快捷键说明

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