📄 drms.c
字号:
/*****************************************************************************
* 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 + -