📄 drms.c
字号:
/***************************************************************************** * drms.c: DRMS ***************************************************************************** * Copyright (C) 2004 VideoLAN * $Id: drms.c 10101 2005-03-02 16:47:31Z robux4 $ * * 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() */#ifdef WIN32# include <io.h>#else# include <stdio.h>#endif#ifdef __VLC__# include <vlc/vlc.h># include "libmp4.h"#else# include "drmsvl.h"#endif#ifdef HAVE_ERRNO_H# include <errno.h>#endif#ifdef WIN32# if !defined( UNDER_CE )# include <direct.h># endif# 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 SYS_DARWIN# 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"#if !defined( UNDER_CE )/***************************************************************************** * 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 i_version; uint32_t p_commands[ 20 ]; uint32_t p_bordel[ 16 ];};#define SWAP( a, b ) { (a) ^= (b); (b) ^= (a); (a) ^= (b); }/***************************************************************************** * 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 *, uint32_t );static void DoShuffle ( struct shuffle_s *, uint32_t *, uint32_t );static uint32_t FirstPass ( uint32_t * );static void SecondPass ( uint32_t *, uint32_t );static void ThirdPass ( uint32_t * );static void FourthPass ( uint32_t * );static void TinyShuffle1 ( uint32_t * );static void TinyShuffle2 ( uint32_t * );static void TinyShuffle3 ( uint32_t * );static void TinyShuffle4 ( uint32_t * );static void TinyShuffle5 ( uint32_t * );static void TinyShuffle6 ( uint32_t * );static void TinyShuffle7 ( uint32_t * );static void TinyShuffle8 ( uint32_t * );static void DoExtShuffle ( uint32_t * );static int GetSystemKey ( uint32_t *, vlc_bool_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( p_drms->i_user == 0 && p_drms->i_key == 0 ) { static char const p_secret[] = "tr1-th3n.y00_by3"; memcpy( p_drms->p_key, p_secret, 16 ); REVERSE( p_drms->p_key, 4 ); } else { 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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -