📄 drms.c
字号:
/***************************************************************************** * drms.c: DRMS ***************************************************************************** * Copyright (C) 2004 VideoLAN * $Id: drms.c,v 1.6 2004/04/12 18:17:41 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 + -