Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

drms.c

00001 /*****************************************************************************
00002  * drms.c: DRMS
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: drms.c 12748 2005-10-02 16:33:40Z jpsaman $
00006  *
00007  * Authors: Jon Lech Johansen <[email protected]>
00008  *          Sam Hocevar <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #include <stdlib.h>                                      /* malloc(), free() */
00026 
00027 #ifdef WIN32
00028 #   include <io.h>
00029 #else
00030 #   include <stdio.h>
00031 #endif
00032 
00033 #ifdef __VLC__
00034 #   include <vlc/vlc.h>
00035 #   include <vlc_md5.h>
00036 #   include "libmp4.h"
00037 #else
00038 #   include "drmsvl.h"
00039 #endif
00040 
00041 #ifdef HAVE_ERRNO_H
00042 #   include <errno.h>
00043 #endif
00044 
00045 #ifdef WIN32
00046 #   if !defined( UNDER_CE )
00047 #       include <direct.h>
00048 #   endif
00049 #   include <tchar.h>
00050 #   include <shlobj.h>
00051 #   include <windows.h>
00052 #endif
00053 
00054 #ifdef HAVE_SYS_STAT_H
00055 #   include <sys/stat.h>
00056 #endif
00057 #ifdef HAVE_SYS_TYPES_H
00058 #   include <sys/types.h>
00059 #endif
00060 
00061 /* In Solaris (and perhaps others) PATH_MAX is in limits.h. */
00062 #ifdef HAVE_LIMITS_H
00063 #   include <limits.h>
00064 #endif
00065 
00066 #ifdef SYS_DARWIN
00067 #   include <mach/mach.h>
00068 #   include <IOKit/IOKitLib.h>
00069 #   include <CoreFoundation/CFNumber.h>
00070 #endif
00071 
00072 #ifdef HAVE_SYSFS_LIBSYSFS_H
00073 #   include <sysfs/libsysfs.h>
00074 #endif
00075 
00076 #include "drms.h"
00077 #include "drmstables.h"
00078 
00079 #if !defined( UNDER_CE )
00080 /*****************************************************************************
00081  * aes_s: AES keys structure
00082  *****************************************************************************
00083  * This structure stores a set of keys usable for encryption and decryption
00084  * with the AES/Rijndael algorithm.
00085  *****************************************************************************/
00086 struct aes_s
00087 {
00088     uint32_t pp_enc_keys[ AES_KEY_COUNT + 1 ][ 4 ];
00089     uint32_t pp_dec_keys[ AES_KEY_COUNT + 1 ][ 4 ];
00090 };
00091 
00092 #ifdef __VLC__
00093 # define Digest DigestMD5
00094 #else
00095 /*****************************************************************************
00096  * md5_s: MD5 message structure
00097  *****************************************************************************
00098  * This structure stores the static information needed to compute an MD5
00099  * hash. It has an extra data buffer to allow non-aligned writes.
00100  *****************************************************************************/
00101 struct md5_s
00102 {
00103     uint64_t i_bits;      /* Total written bits */
00104     uint32_t p_digest[4]; /* The MD5 digest */
00105     uint32_t p_data[16];  /* Buffer to cache non-aligned writes */
00106 };
00107 #endif
00108 
00109 /*****************************************************************************
00110  * shuffle_s: shuffle structure
00111  *****************************************************************************
00112  * This structure stores the static information needed to shuffle data using
00113  * a custom algorithm.
00114  *****************************************************************************/
00115 struct shuffle_s
00116 {
00117     uint32_t i_version;
00118     uint32_t p_commands[ 20 ];
00119     uint32_t p_bordel[ 16 ];
00120 };
00121 
00122 #define SWAP( a, b ) { (a) ^= (b); (b) ^= (a); (a) ^= (b); }
00123 
00124 /*****************************************************************************
00125  * drms_s: DRMS structure
00126  *****************************************************************************
00127  * This structure stores the static information needed to decrypt DRMS data.
00128  *****************************************************************************/
00129 struct drms_s
00130 {
00131     uint32_t i_user;
00132     uint32_t i_key;
00133     uint8_t  p_iviv[ 16 ];
00134     uint8_t *p_name;
00135 
00136     uint32_t p_key[ 4 ];
00137     struct aes_s aes;
00138 
00139     char     psz_homedir[ PATH_MAX ];
00140 };
00141 
00142 /*****************************************************************************
00143  * Local prototypes
00144  *****************************************************************************/
00145 static void InitAES       ( struct aes_s *, uint32_t * );
00146 static void DecryptAES    ( struct aes_s *, uint32_t *, const uint32_t * );
00147 
00148 #ifndef __VLC__
00149 static void InitMD5       ( struct md5_s * );
00150 static void AddMD5        ( struct md5_s *, const uint8_t *, uint32_t );
00151 static void EndMD5        ( struct md5_s * );
00152 static void Digest        ( struct md5_s *, uint32_t * );
00153 #endif
00154 
00155 static void InitShuffle   ( struct shuffle_s *, uint32_t *, uint32_t );
00156 static void DoShuffle     ( struct shuffle_s *, uint32_t *, uint32_t );
00157 
00158 static uint32_t FirstPass ( uint32_t * );
00159 static void SecondPass    ( uint32_t *, uint32_t );
00160 static void ThirdPass     ( uint32_t * );
00161 static void FourthPass    ( uint32_t * );
00162 static void TinyShuffle1  ( uint32_t * );
00163 static void TinyShuffle2  ( uint32_t * );
00164 static void TinyShuffle3  ( uint32_t * );
00165 static void TinyShuffle4  ( uint32_t * );
00166 static void TinyShuffle5  ( uint32_t * );
00167 static void TinyShuffle6  ( uint32_t * );
00168 static void TinyShuffle7  ( uint32_t * );
00169 static void TinyShuffle8  ( uint32_t * );
00170 static void DoExtShuffle  ( uint32_t * );
00171 
00172 static int GetSystemKey   ( uint32_t *, vlc_bool_t );
00173 static int WriteUserKey   ( void *, uint32_t * );
00174 static int ReadUserKey    ( void *, uint32_t * );
00175 static int GetUserKey     ( void *, uint32_t * );
00176 
00177 static int GetSCIData     ( char *, uint32_t **, uint32_t * );
00178 static int HashSystemInfo ( uint32_t * );
00179 static int GetiPodID      ( int64_t * );
00180 
00181 #ifdef WORDS_BIGENDIAN
00182 /*****************************************************************************
00183  * Reverse: reverse byte order
00184  *****************************************************************************/
00185 static inline void Reverse( uint32_t *p_buffer, int n )
00186 {
00187     int i;
00188 
00189     for( i = 0; i < n; i++ )
00190     {
00191         p_buffer[ i ] = GetDWLE(&p_buffer[ i ]);
00192     }
00193 }
00194 #    define REVERSE( p, n ) Reverse( p, n )
00195 #else
00196 #    define REVERSE( p, n )
00197 #endif
00198 
00199 /*****************************************************************************
00200  * BlockXOR: XOR two 128 bit blocks
00201  *****************************************************************************/
00202 static inline void BlockXOR( uint32_t *p_dest, uint32_t *p_s1, uint32_t *p_s2 )
00203 {
00204     int i;
00205 
00206     for( i = 0; i < 4; i++ )
00207     {
00208         p_dest[ i ] = p_s1[ i ] ^ p_s2[ i ];
00209     }
00210 }
00211 
00212 /*****************************************************************************
00213  * drms_alloc: allocate a DRMS structure
00214  *****************************************************************************/
00215 void *drms_alloc( char *psz_homedir )
00216 {
00217     struct drms_s *p_drms;
00218 
00219     p_drms = malloc( sizeof(struct drms_s) );
00220 
00221     if( p_drms == NULL )
00222     {
00223         return NULL;
00224     }
00225 
00226     memset( p_drms, 0, sizeof(struct drms_s) );
00227 
00228     strncpy( p_drms->psz_homedir, psz_homedir, PATH_MAX );
00229     p_drms->psz_homedir[ PATH_MAX - 1 ] = '\0';
00230 
00231     return (void *)p_drms;
00232 }
00233 
00234 /*****************************************************************************
00235  * drms_free: free a previously allocated DRMS structure
00236  *****************************************************************************/
00237 void drms_free( void *_p_drms )
00238 {
00239     struct drms_s *p_drms = (struct drms_s *)_p_drms;
00240 
00241     if( p_drms->p_name != NULL )
00242     {
00243         free( (void *)p_drms->p_name );
00244     }
00245 
00246     free( p_drms );
00247 }
00248 
00249 /*****************************************************************************
00250  * drms_decrypt: unscramble a chunk of data
00251  *****************************************************************************/
00252 void drms_decrypt( void *_p_drms, uint32_t *p_buffer, uint32_t i_bytes )
00253 {
00254     struct drms_s *p_drms = (struct drms_s *)_p_drms;
00255     uint32_t p_key[ 4 ];
00256     unsigned int i_blocks;
00257 
00258     /* AES is a block cypher, round down the byte count */
00259     i_blocks = i_bytes / 16;
00260     i_bytes = i_blocks * 16;
00261 
00262     /* Initialise the key */
00263     memcpy( p_key, p_drms->p_key, 16 );
00264 
00265     /* Unscramble */
00266     while( i_blocks-- )
00267     {
00268         uint32_t p_tmp[ 4 ];
00269 
00270         REVERSE( p_buffer, 4 );
00271         DecryptAES( &p_drms->aes, p_tmp, p_buffer );
00272         BlockXOR( p_tmp, p_key, p_tmp );
00273 
00274         /* Use the previous scrambled data as the key for next block */
00275         memcpy( p_key, p_buffer, 16 );
00276 
00277         /* Copy unscrambled data back to the buffer */
00278         memcpy( p_buffer, p_tmp, 16 );
00279         REVERSE( p_buffer, 4 );
00280 
00281         p_buffer += 4;
00282     }
00283 }
00284 
00285 /*****************************************************************************
00286  * drms_init: initialise a DRMS structure
00287  *****************************************************************************/
00288 int drms_init( void *_p_drms, uint32_t i_type,
00289                uint8_t *p_info, uint32_t i_len )
00290 {
00291     struct drms_s *p_drms = (struct drms_s *)_p_drms;
00292     int i_ret = 0;
00293 
00294     switch( i_type )
00295     {
00296         case FOURCC_user:
00297             if( i_len < sizeof(p_drms->i_user) )
00298             {
00299                 i_ret = -1;
00300                 break;
00301             }
00302 
00303             p_drms->i_user = U32_AT( p_info );
00304             break;
00305 
00306         case FOURCC_key:
00307             if( i_len < sizeof(p_drms->i_key) )
00308             {
00309                 i_ret = -1;
00310                 break;
00311             }
00312 
00313             p_drms->i_key = U32_AT( p_info );
00314             break;
00315 
00316         case FOURCC_iviv:
00317             if( i_len < sizeof(p_drms->p_key) )
00318             {
00319                 i_ret = -1;
00320                 break;
00321             }
00322 
00323             memcpy( p_drms->p_iviv, p_info, 16 );
00324             break;
00325 
00326         case FOURCC_name:
00327             p_drms->p_name = strdup( p_info );
00328 
00329             if( p_drms->p_name == NULL )
00330             {
00331                 i_ret = -1;
00332             }
00333             break;
00334 
00335         case FOURCC_priv:
00336         {
00337             uint32_t p_priv[ 64 ];
00338             struct md5_s md5;
00339 
00340             if( i_len < 64 )
00341             {
00342                 i_ret = -1;
00343                 break;
00344             }
00345 
00346             InitMD5( &md5 );
00347             AddMD5( &md5, p_drms->p_name, strlen( p_drms->p_name ) );
00348             AddMD5( &md5, p_drms->p_iviv, 16 );
00349             EndMD5( &md5 );
00350 
00351             if( p_drms->i_user == 0 && p_drms->i_key == 0 )
00352             {
00353                 static char const p_secret[] = "tr1-th3n.y00_by3";
00354                 memcpy( p_drms->p_key, p_secret, 16 );
00355                 REVERSE( p_drms->p_key, 4 );
00356             }
00357             else
00358             {
00359                 if( GetUserKey( p_drms, p_drms->p_key ) )
00360                 {
00361                     i_ret = -1;
00362                     break;
00363                 }
00364             }
00365 
00366             InitAES( &p_drms->aes, p_drms->p_key );
00367 
00368             memcpy( p_priv, p_info, 64 );
00369             memcpy( p_drms->p_key, md5.p_digest, 16 );
00370             drms_decrypt( p_drms, p_priv, 64 );
00371             REVERSE( p_priv, 64 );
00372 
00373             if( p_priv[ 0 ] != 0x6e757469 ) /* itun */
00374             {
00375                 i_ret = -1;
00376                 break;
00377             }
00378 
00379             InitAES( &p_drms->aes, p_priv + 6 );
00380             memcpy( p_drms->p_key, p_priv + 12, 16 );
00381 
00382             free( (void *)p_drms->p_name );
00383             p_drms->p_name = NULL;
00384         }
00385         break;
00386     }
00387 
00388     return i_ret;
00389 }
00390 
00391 /* The following functions are local */
00392 
00393 /*****************************************************************************
00394  * InitAES: initialise AES/Rijndael encryption/decryption tables
00395  *****************************************************************************
00396  * The Advanced Encryption Standard (AES) is described in RFC 3268
00397  *****************************************************************************/
00398 static void InitAES( struct aes_s *p_aes, uint32_t *p_key )
00399 {
00400     unsigned int i, t;
00401     uint32_t i_key, i_seed;
00402 
00403     memset( p_aes->pp_enc_keys[1], 0, 16 );
00404     memcpy( p_aes->pp_enc_keys[0], p_key, 16 );
00405 
00406     /* Generate the key tables */
00407     i_seed = p_aes->pp_enc_keys[ 0 ][ 3 ];
00408 
00409     for( i_key = 0; i_key < AES_KEY_COUNT; i_key++ )
00410     {
00411         uint32_t j;
00412 
00413         i_seed = AES_ROR( i_seed, 8 );
00414 
00415         j = p_aes_table[ i_key ];
00416 
00417         j ^= p_aes_encrypt[ (i_seed >> 24) & 0xff ]
00418               ^ AES_ROR( p_aes_encrypt[ (i_seed >> 16) & 0xff ], 8 )
00419               ^ AES_ROR( p_aes_encrypt[ (i_seed >> 8) & 0xff ], 16 )
00420               ^ AES_ROR( p_aes_encrypt[ i_seed & 0xff ], 24 );
00421 
00422         j ^= p_aes->pp_enc_keys[ i_key ][ 0 ];
00423         p_aes->pp_enc_keys[ i_key + 1 ][ 0 ] = j;
00424         j ^= p_aes->pp_enc_keys[ i_key ][ 1 ];
00425         p_aes->pp_enc_keys[ i_key + 1 ][ 1 ] = j;
00426         j ^= p_aes->pp_enc_keys[ i_key ][ 2 ];
00427         p_aes->pp_enc_keys[ i_key + 1 ][ 2 ] = j;
00428         j ^= p_aes->pp_enc_keys[ i_key ][ 3 ];
00429         p_aes->pp_enc_keys[ i_key + 1 ][ 3 ] = j;
00430 
00431         i_seed = j;
00432     }
00433 
00434     memcpy( p_aes->pp_dec_keys[ 0 ],
00435             p_aes->pp_enc_keys[ 0 ], 16 );
00436 
00437     for( i = 1; i < AES_KEY_COUNT; i++ )
00438     {
00439         for( t = 0; t < 4; t++ )
00440         {
00441             uint32_t j, k, l, m, n;
00442 
00443             j = p_aes->pp_enc_keys[ i ][ t ];
00444 
00445             k = (((j >> 7) & 0x01010101) * 27) ^ ((j & 0xff7f7f7f) << 1);
00446             l = (((k >> 7) & 0x01010101) * 27) ^ ((k & 0xff7f7f7f) << 1);
00447             m = (((l >> 7) & 0x01010101) * 27) ^ ((l & 0xff7f7f7f) << 1);
00448 
00449             j ^= m;
00450 
00451             n = AES_ROR( l ^ j, 16 ) ^ AES_ROR( k ^ j, 8 ) ^ AES_ROR( j, 24 );
00452 
00453             p_aes->pp_dec_keys[ i ][ t ] = k ^ l ^ m ^ n;
00454         }
00455     }
00456 }
00457 
00458 /*****************************************************************************
00459  * DecryptAES: decrypt an AES/Rijndael 128 bit block
00460  *****************************************************************************/
00461 static void DecryptAES( struct aes_s *p_aes,
00462                         uint32_t *p_dest, const uint32_t *p_src )
00463 {
00464     uint32_t p_wtxt[ 4 ]; /* Working cyphertext */
00465     uint32_t p_tmp[ 4 ];
00466     unsigned int i_round, t;
00467 
00468     for( t = 0; t < 4; t++ )
00469     {
00470         /* FIXME: are there any endianness issues here? */
00471         p_wtxt[ t ] = p_src[ t ] ^ p_aes->pp_enc_keys[ AES_KEY_COUNT ][ t ];
00472     }
00473 
00474     /* Rounds 0 - 8 */
00475     for( i_round = 0; i_round < (AES_KEY_COUNT - 1); i_round++ )
00476     {
00477         for( t = 0; t < 4; t++ )
00478         {
00479             p_tmp[ t ] = AES_XOR_ROR( p_aes_itable, p_wtxt );
00480         }
00481 
00482         for( t = 0; t < 4; t++ )
00483         {
00484             p_wtxt[ t ] = p_tmp[ t ]
00485                     ^ p_aes->pp_dec_keys[ (AES_KEY_COUNT - 1) - i_round ][ t ];
00486         }
00487     }
00488 
00489     /* Final round (9) */
00490     for( t = 0; t < 4; t++ )
00491     {
00492         p_dest[ t ] = AES_XOR_ROR( p_aes_decrypt, p_wtxt );
00493         p_dest[ t ] ^= p_aes->pp_dec_keys[ 0 ][ t ];
00494     }
00495 }
00496 
00497 #ifndef __VLC__
00498 /*****************************************************************************
00499  * InitMD5: initialise an MD5 message
00500  *****************************************************************************
00501  * The MD5 message-digest algorithm is described in RFC 1321
00502  *****************************************************************************/
00503 static void InitMD5( struct md5_s *p_md5 )
00504 {
00505     p_md5->p_digest[ 0 ] = 0x67452301;
00506     p_md5->p_digest[ 1 ] = 0xefcdab89;
00507     p_md5->p_digest[ 2 ] = 0x98badcfe;
00508     p_md5->p_digest[ 3 ] = 0x10325476;
00509 
00510     memset( p_md5->p_data, 0, 64 );
00511     p_md5->i_bits = 0;
00512 }
00513 
00514 /*****************************************************************************
00515  * AddMD5: add i_len bytes to an MD5 message
00516  *****************************************************************************/
00517 static void AddMD5( struct md5_s *p_md5, const uint8_t *p_src, uint32_t i_len )
00518 {
00519     unsigned int i_current; /* Current bytes in the spare buffer */
00520     unsigned int i_offset = 0;
00521 
00522     i_current = (p_md5->i_bits / 8) & 63;
00523 
00524     p_md5->i_bits += 8 * i_len;
00525 
00526     /* If we can complete our spare buffer to 64 bytes, do it and add the
00527      * resulting buffer to the MD5 message */
00528     if( i_len >= (64 - i_current) )
00529     {
00530         memcpy( ((uint8_t *)p_md5->p_data) + i_current, p_src,
00531                 (64 - i_current) );
00532         Digest( p_md5, p_md5->p_data );
00533 
00534         i_offset += (64 - i_current);
00535         i_len -= (64 - i_current);
00536         i_current = 0;
00537     }
00538 
00539     /* Add as many entire 64 bytes blocks as we can to the MD5 message */
00540     while( i_len >= 64 )
00541     {
00542         uint32_t p_tmp[ 16 ];
00543         memcpy( p_tmp, p_src + i_offset, 64 );
00544         Digest( p_md5, p_tmp );
00545         i_offset += 64;
00546         i_len -= 64;
00547     }
00548 
00549     /* Copy our remaining data to the message's spare buffer */
00550     memcpy( ((uint8_t *)p_md5->p_data) + i_current, p_src + i_offset, i_len );
00551 }
00552 
00553 /*****************************************************************************
00554  * EndMD5: finish an MD5 message
00555  *****************************************************************************
00556  * This function adds adequate padding to the end of the message, and appends
00557  * the bit count so that we end at a block boundary.
00558  *****************************************************************************/
00559 static void EndMD5( struct md5_s *p_md5 )
00560 {
00561     unsigned int i_current;
00562 
00563     i_current = (p_md5->i_bits / 8) & 63;
00564 
00565     /* Append 0x80 to our buffer. No boundary check because the temporary
00566      * buffer cannot be full, otherwise AddMD5 would have emptied it. */
00567     ((uint8_t *)p_md5->p_data)[ i_current++ ] = 0x80;
00568 
00569     /* If less than 8 bytes are available at the end of the block, complete
00570      * this 64 bytes block with zeros and add it to the message. We'll add
00571      * our length at the end of the next block. */
00572     if( i_current > 56 )
00573     {
00574         memset( ((uint8_t *)p_md5->p_data) + i_current, 0, (64 - i_current) );
00575         Digest( p_md5, p_md5->p_data );
00576         i_current = 0;
00577     }
00578 
00579     /* Fill the unused space in our last block with zeroes and put the
00580      * message length at the end. */
00581     memset( ((uint8_t *)p_md5->p_data) + i_current, 0, (56 - i_current) );
00582     p_md5->p_data[ 14 ] = p_md5->i_bits & 0xffffffff;
00583     p_md5->p_data[ 15 ] = (p_md5->i_bits >> 32);
00584     REVERSE( &p_md5->p_data[ 14 ], 2 );
00585 
00586     Digest( p_md5, p_md5->p_data );
00587 }
00588 
00589 #define F1( x, y, z ) ((z) ^ ((x) & ((y) ^ (z))))
00590 #define F2( x, y, z ) F1((z), (x), (y))
00591 #define F3( x, y, z ) ((x) ^ (y) ^ (z))
00592 #define F4( x, y, z ) ((y) ^ ((x) | ~(z)))
00593 
00594 #define MD5_DO( f, w, x, y, z, data, s ) \
00595     ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
00596 
00597 /*****************************************************************************
00598  * Digest: update the MD5 digest with 64 bytes of data
00599  *****************************************************************************/
00600 static void Digest( struct md5_s *p_md5, uint32_t *p_input )
00601 {
00602     uint32_t a, b, c, d;
00603 
00604     REVERSE( p_input, 16 );
00605 
00606     a = p_md5->p_digest[ 0 ];
00607     b = p_md5->p_digest[ 1 ];
00608     c = p_md5->p_digest[ 2 ];
00609     d = p_md5->p_digest[ 3 ];
00610 
00611     MD5_DO( F1, a, b, c, d, p_input[  0 ] + 0xd76aa478,  7 );
00612     MD5_DO( F1, d, a, b, c, p_input[  1 ] + 0xe8c7b756, 12 );
00613     MD5_DO( F1, c, d, a, b, p_input[  2 ] + 0x242070db, 17 );
00614     MD5_DO( F1, b, c, d, a, p_input[  3 ] + 0xc1bdceee, 22 );
00615     MD5_DO( F1, a, b, c, d, p_input[  4 ] + 0xf57c0faf,  7 );
00616     MD5_DO( F1, d, a, b, c, p_input[  5 ] + 0x4787c62a, 12 );
00617     MD5_DO( F1, c, d, a, b, p_input[  6 ] + 0xa8304613, 17 );
00618     MD5_DO( F1, b, c, d, a, p_input[  7 ] + 0xfd469501, 22 );
00619     MD5_DO( F1, a, b, c, d, p_input[  8 ] + 0x698098d8,  7 );
00620     MD5_DO( F1, d, a, b, c, p_input[  9 ] + 0x8b44f7af, 12 );
00621     MD5_DO( F1, c, d, a, b, p_input[ 10 ] + 0xffff5bb1, 17 );
00622     MD5_DO( F1, b, c, d, a, p_input[ 11 ] + 0x895cd7be, 22 );
00623     MD5_DO( F1, a, b, c, d, p_input[ 12 ] + 0x6b901122,  7 );
00624     MD5_DO( F1, d, a, b, c, p_input[ 13 ] + 0xfd987193, 12 );
00625     MD5_DO( F1, c, d, a, b, p_input[ 14 ] + 0xa679438e, 17 );
00626     MD5_DO( F1, b, c, d, a, p_input[ 15 ] + 0x49b40821, 22 );
00627 
00628     MD5_DO( F2, a, b, c, d, p_input[  1 ] + 0xf61e2562,  5 );
00629     MD5_DO( F2, d, a, b, c, p_input[  6 ] + 0xc040b340,  9 );
00630     MD5_DO( F2, c, d, a, b, p_input[ 11 ] + 0x265e5a51, 14 );
00631     MD5_DO( F2, b, c, d, a, p_input[  0 ] + 0xe9b6c7aa, 20 );
00632     MD5_DO( F2, a, b, c, d, p_input[  5 ] + 0xd62f105d,  5 );
00633     MD5_DO( F2, d, a, b, c, p_input[ 10 ] + 0x02441453,  9 );
00634     MD5_DO( F2, c, d, a, b, p_input[ 15 ] + 0xd8a1e681, 14 );
00635     MD5_DO( F2, b, c, d, a, p_input[  4 ] + 0xe7d3fbc8, 20 );
00636     MD5_DO( F2, a, b, c, d, p_input[  9 ] + 0x21e1cde6,  5 );
00637     MD5_DO( F2, d, a, b, c, p_input[ 14 ] + 0xc33707d6,  9 );
00638     MD5_DO( F2, c, d, a, b, p_input[  3 ] + 0xf4d50d87, 14 );
00639     MD5_DO( F2, b, c, d, a, p_input[  8 ] + 0x455a14ed, 20 );
00640     MD5_DO( F2, a, b, c, d, p_input[ 13 ] + 0xa9e3e905,  5 );
00641     MD5_DO( F2, d, a, b, c, p_input[  2 ] + 0xfcefa3f8,  9 );
00642     MD5_DO( F2, c, d, a, b, p_input[  7 ] + 0x676f02d9, 14 );
00643     MD5_DO( F2, b, c, d, a, p_input[ 12 ] + 0x8d2a4c8a, 20 );
00644 
00645     MD5_DO( F3, a, b, c, d, p_input[  5 ] + 0xfffa3942,  4 );
00646     MD5_DO( F3, d, a, b, c, p_input[  8 ] + 0x8771f681, 11 );
00647     MD5_DO( F3, c, d, a, b, p_input[ 11 ] + 0x6d9d6122, 16 );
00648     MD5_DO( F3, b, c, d, a, p_input[ 14 ] + 0xfde5380c, 23 );
00649     MD5_DO( F3, a, b, c, d, p_input[  1 ] + 0xa4beea44,  4 );
00650     MD5_DO( F3, d, a, b, c, p_input[  4 ] + 0x4bdecfa9, 11 );
00651     MD5_DO( F3, c, d, a, b, p_input[  7 ] + 0xf6bb4b60, 16 );
00652     MD5_DO( F3, b, c, d, a, p_input[ 10 ] + 0xbebfbc70, 23 );
00653     MD5_DO( F3, a, b, c, d, p_input[ 13 ] + 0x289b7ec6,  4 );
00654     MD5_DO( F3, d, a, b, c, p_input[  0 ] + 0xeaa127fa, 11 );
00655     MD5_DO( F3, c, d, a, b, p_input[  3 ] + 0xd4ef3085, 16 );
00656     MD5_DO( F3, b, c, d, a, p_input[  6 ] + 0x04881d05, 23 );
00657     MD5_DO( F3, a, b, c, d, p_input[  9 ] + 0xd9d4d039,  4 );
00658     MD5_DO( F3, d, a, b, c, p_input[ 12 ] + 0xe6db99e5, 11 );
00659     MD5_DO( F3, c, d, a, b, p_input[ 15 ] + 0x1fa27cf8, 16 );
00660     MD5_DO( F3, b, c, d, a, p_input[  2 ] + 0xc4ac5665, 23 );
00661 
00662     MD5_DO( F4, a, b, c, d, p_input[  0 ] + 0xf4292244,  6 );
00663     MD5_DO( F4, d, a, b, c, p_input[  7 ] + 0x432aff97, 10 );
00664     MD5_DO( F4, c, d, a, b, p_input[ 14 ] + 0xab9423a7, 15 );
00665     MD5_DO( F4, b, c, d, a, p_input[  5 ] + 0xfc93a039, 21 );
00666     MD5_DO( F4, a, b, c, d, p_input[ 12 ] + 0x655b59c3,  6 );
00667     MD5_DO( F4, d, a, b, c, p_input[  3 ] + 0x8f0ccc92, 10 );
00668     MD5_DO( F4, c, d, a, b, p_input[ 10 ] + 0xffeff47d, 15 );
00669     MD5_DO( F4, b, c, d, a, p_input[  1 ] + 0x85845dd1, 21 );
00670     MD5_DO( F4, a, b, c, d, p_input[  8 ] + 0x6fa87e4f,  6 );
00671     MD5_DO( F4, d, a, b, c, p_input[ 15 ] + 0xfe2ce6e0, 10 );
00672     MD5_DO( F4, c, d, a, b, p_input[  6 ] + 0xa3014314, 15 );
00673     MD5_DO( F4, b, c, d, a, p_input[ 13 ] + 0x4e0811a1, 21 );
00674     MD5_DO( F4, a, b, c, d, p_input[  4 ] + 0xf7537e82,  6 );
00675     MD5_DO( F4, d, a, b, c, p_input[ 11 ] + 0xbd3af235, 10 );
00676     MD5_DO( F4, c, d, a, b, p_input[  2 ] + 0x2ad7d2bb, 15 );
00677     MD5_DO( F4, b, c, d, a, p_input[  9 ] + 0xeb86d391, 21 );
00678 
00679     p_md5->p_digest[ 0 ] += a;
00680     p_md5->p_digest[ 1 ] += b;
00681     p_md5->p_digest[ 2 ] += c;
00682     p_md5->p_digest[ 3 ] += d;
00683 }
00684 #endif
00685 
00686 /*****************************************************************************
00687  * InitShuffle: initialise a shuffle structure
00688  *****************************************************************************
00689  * This function initialises tables in the p_shuffle structure that will be
00690  * used later by DoShuffle. The only external parameter is p_sys_key.
00691  *****************************************************************************/
00692 static void InitShuffle( struct shuffle_s *p_shuffle, uint32_t *p_sys_key,
00693                          uint32_t i_version )
00694 {
00695     char p_secret1[] = "Tv!*";
00696     static char const p_secret2[] = "v8rhvsaAvOKMFfUH%798=[;."
00697                                     "f8677680a634ba87fnOIf)(*";
00698     unsigned int i;
00699 
00700     p_shuffle->i_version = i_version;
00701 
00702     /* Fill p_commands using the key and a secret seed */
00703     for( i = 0; i < 20; i++ )
00704     {
00705         struct md5_s md5;
00706         int32_t i_hash;
00707 
00708         InitMD5( &md5 );
00709         AddMD5( &md5, (uint8_t *)p_sys_key, 16 );
00710         AddMD5( &md5, (uint8_t *)p_secret1, 4 );
00711         EndMD5( &md5 );
00712 
00713         p_secret1[ 3 ]++;
00714 
00715         REVERSE( md5.p_digest, 1 );
00716         i_hash = ((int32_t)U32_AT(md5.p_digest)) % 1024;
00717 
00718         p_shuffle->p_commands[ i ] = i_hash < 0 ? i_hash * -1 : i_hash;
00719     }
00720 
00721     /* Fill p_bordel with completely meaningless initial values. */
00722     for( i = 0; i < 4; i++ )
00723     {
00724         p_shuffle->p_bordel[ 4 * i ] = U32_AT(p_sys_key + i);
00725         memcpy( p_shuffle->p_bordel + 4 * i + 1, p_secret2 + 12 * i, 12 );
00726         REVERSE( p_shuffle->p_bordel + 4 * i + 1, 3 );
00727     }
00728 }
00729 
00730 /*****************************************************************************
00731  * DoShuffle: shuffle buffer
00732  *****************************************************************************
00733  * This is so ugly and uses so many MD5 checksums that it is most certainly
00734  * one-way, though why it needs to be so complicated is beyond me.
00735  *****************************************************************************/
00736 static void DoShuffle( struct shuffle_s *p_shuffle,
00737                        uint32_t *p_buffer, uint32_t i_size )
00738 {
00739     struct md5_s md5;
00740     uint32_t p_big_bordel[ 16 ];
00741     uint32_t *p_bordel = p_shuffle->p_bordel;
00742     unsigned int i;
00743 
00744     static uint32_t i_secret = 0;
00745 
00746     static uint32_t p_secret1[] =
00747     {
00748         0xAAAAAAAA, 0x01757700, 0x00554580, 0x01724500, 0x00424580,
00749         0x01427700, 0x00000080, 0xC1D59D01, 0x80144981, 0x815C8901,
00750         0x80544981, 0x81D45D01, 0x00000080, 0x81A3BB03, 0x00A2AA82,
00751         0x01A3BB03, 0x0022A282, 0x813BA202, 0x00000080, 0x6D575737,
00752         0x4A5275A5, 0x6D525725, 0x4A5254A5, 0x6B725437, 0x00000080,
00753         0xD5DDB938, 0x5455A092, 0x5D95A013, 0x4415A192, 0xC5DD393A,
00754         0x00000080, 0x55555555
00755     };
00756 
00757     static char p_secret2[] =
00758         "pbclevtug (p) Nccyr Pbzchgre, Vap.  Nyy Evtugf Erfreirq.";
00759 
00760     if( i_secret == 0 )
00761     {
00762         REVERSE( p_secret1, sizeof(p_secret1)/sizeof(p_secret1[ 0 ]) );
00763         for( ; p_secret2[ i_secret ] != '\0'; i_secret++ )
00764         {
00765 #define ROT13(c) (((c)>='A'&&(c)<='Z')?(((c)-'A'+13)%26)+'A':\
00766                   ((c)>='a'&&(c)<='z')?(((c)-'a'+13)%26)+'a':c)
00767             p_secret2[ i_secret ] = ROT13(p_secret2[ i_secret ]);
00768         }
00769         i_secret++; /* include zero terminator */
00770     }
00771 
00772     /* Using the MD5 hash of a memory block is probably not one-way enough
00773      * for the iTunes people. This function randomises p_bordel depending on
00774      * the values in p_commands to make things even more messy in p_bordel. */
00775     for( i = 0; i < 20; i++ )
00776     {
00777         uint8_t i_command, i_index;
00778 
00779         if( !p_shuffle->p_commands[ i ] )
00780         {
00781             continue;
00782         }
00783 
00784         i_command = (p_shuffle->p_commands[ i ] & 0x300) >> 8;
00785         i_index = p_shuffle->p_commands[ i ] & 0xff;
00786 
00787         switch( i_command )
00788         {
00789         case 0x3:
00790             p_bordel[ i_index & 0xf ] = p_bordel[ i_index >> 4 ]
00791                                       + p_bordel[ ((i_index + 0x10) >> 4) & 0xf ];
00792             break;
00793         case 0x2:
00794             p_bordel[ i_index >> 4 ] ^= p_shuffle_xor[ 0xff - i_index ];
00795             break;
00796         case 0x1:
00797             p_bordel[ i_index >> 4 ] -= p_shuffle_sub[ 0xff - i_index ];
00798             break;
00799         default:
00800             p_bordel[ i_index >> 4 ] += p_shuffle_add[ 0xff - i_index ];
00801             break;
00802         }
00803     }
00804 
00805     if( p_shuffle->i_version == 0x01000300 )
00806     {
00807         DoExtShuffle( p_bordel );
00808     }
00809 
00810     /* Convert our newly randomised p_bordel to big endianness and take
00811      * its MD5 hash. */
00812     InitMD5( &md5 );
00813     for( i = 0; i < 16; i++ )
00814     {
00815         p_big_bordel[ i ] = U32_AT(p_bordel + i);
00816     }
00817     AddMD5( &md5, (uint8_t *)p_big_bordel, 64 );
00818     if( p_shuffle->i_version == 0x01000300 )
00819     {
00820         AddMD5( &md5, (uint8_t *)p_secret1, sizeof(p_secret1) );
00821         AddMD5( &md5, (uint8_t *)p_secret2, i_secret );
00822     }
00823     EndMD5( &md5 );
00824 
00825     /* XOR our buffer with the computed checksum */
00826     for( i = 0; i < i_size; i++ )
00827     {
00828         p_buffer[ i ] ^= md5.p_digest[ i ];
00829     }
00830 }
00831 
00832 /*****************************************************************************
00833  * DoExtShuffle: extended shuffle
00834  *****************************************************************************
00835  * This is even uglier.
00836  *****************************************************************************/
00837 static void DoExtShuffle( uint32_t * p_bordel )
00838 {
00839     uint32_t i_ret;
00840 
00841     i_ret = FirstPass( p_bordel );
00842 
00843     SecondPass( p_bordel, i_ret );
00844 
00845     ThirdPass( p_bordel );
00846 
00847     FourthPass( p_bordel );
00848 }
00849 
00850 static uint32_t FirstPass( uint32_t * p_bordel )
00851 {
00852     uint32_t i, i_cmd, i_ret = 5;
00853 
00854     TinyShuffle1( p_bordel );
00855 
00856     for( ; ; )
00857     {
00858         for( ; ; )
00859         {
00860             p_bordel[ 1 ] += 0x10000000;
00861             p_bordel[ 3 ] += 0x12777;
00862 
00863             if( (p_bordel[ 10 ] & 1) && i_ret )
00864             {
00865                 i_ret--;
00866                 p_bordel[ 1 ] -= p_bordel[ 2 ];
00867                 p_bordel[ 11 ] += p_bordel[ 12 ];
00868                 break;
00869             }
00870 
00871             if( (p_bordel[ 1 ] + p_bordel[ 2 ]) >= 0x7D0 )
00872             {
00873                 switch( ((p_bordel[ 3 ] ^ 0x567F) >> 2) & 7 )
00874                 {
00875                     case 0:
00876                         for( i = 0; i < 3; i++ )
00877                         {
00878                             if( p_bordel[ i + 10 ] > 0x4E20 )
00879                             {
00880                                 p_bordel[ i + 1 ] += p_bordel[ i + 2 ];
00881                             }
00882                         }
00883                         break;
00884                     case 4:
00885                         p_bordel[ 1 ] -= p_bordel[ 2 ];
00886                         /* no break */
00887                     case 3:
00888                         p_bordel[ 11 ] += p_bordel[ 12 ];
00889                         break;
00890                     case 6:
00891                         p_bordel[ 3 ] ^= p_bordel[ 4 ];
00892                         /* no break */
00893                     case 8:
00894                         p_bordel[ 13 ] &= p_bordel[ 14 ];
00895                         /* no break */
00896                     case 1:
00897                         p_bordel[ 0 ] |= p_bordel[ 1 ];
00898                         if( i_ret )
00899                         {
00900                             return i_ret;
00901                         }
00902                         break;
00903                 }
00904 
00905                 break;
00906             }
00907         }
00908 
00909         for( i = 0, i_cmd = 0; i < 16; i++ )
00910         {
00911             if( p_bordel[ i ] < p_bordel[ i_cmd ] )
00912             {
00913                 i_cmd = i;
00914             }
00915         }
00916 
00917         if( i_ret && i_cmd != 5 )
00918         {
00919             i_ret--;
00920         }
00921         else
00922         {
00923             if( i_cmd == 5 )
00924             {
00925                 p_bordel[ 8 ] &= p_bordel[ 6 ] >> 1;
00926                 p_bordel[ 3 ] <<= 1;
00927             }
00928 
00929             for( i = 0; i < 3; i++ )
00930             {
00931                 p_bordel[ 11 ] += 1;
00932                 if( p_bordel[ 11 ] & 5 )
00933                 {
00934                     p_bordel[ 8 ] += p_bordel[ 9 ];
00935                 }
00936                 else if( i_ret )
00937                 {
00938                     i_ret--;
00939                     i_cmd = 3;
00940                     goto break2;
00941                 }
00942             }
00943 
00944             i_cmd = (p_bordel[ 15 ] + 0x93) >> 3;
00945             if( p_bordel[ 15 ] & 0x100 )
00946             {
00947                 i_cmd ^= 0xDEAD;
00948             }
00949         }
00950 
00951         switch( i_cmd & 3 )
00952         {
00953             case 0:
00954                 while( p_bordel[ 11 ] & 1 )
00955                 {
00956                     p_bordel[ 11 ] >>= 1;
00957                     p_bordel[ 12 ] += 1;
00958                 }
00959                 /* no break */
00960             case 2:
00961                 p_bordel[ 14 ] -= 0x19FE;
00962                 break;
00963             case 3:
00964                 if( i_ret )
00965                 {
00966                     i_ret--;
00967                     p_bordel[ 5 ] += 5;
00968                     continue;
00969                 }
00970                 break;
00971         }
00972 
00973         i_cmd = ((p_bordel[ 3 ] + p_bordel[ 4 ] + 10) >> 1) - p_bordel[ 4 ];
00974         break;
00975     }
00976 break2:
00977 
00978     switch( i_cmd & 3 )
00979     {
00980         case 0:
00981             p_bordel[ 14 ] >>= 1;
00982             break;
00983         case 1:
00984             p_bordel[ 5 ] <<= 2;
00985             break;
00986         case 2:
00987             p_bordel[ 12 ] |= 5;
00988             break;
00989         case 3:
00990             p_bordel[ 15 ] &= 0x55;
00991             if( i_ret )
00992             {
00993                 p_bordel[ 2 ] &= 0xB62FC;
00994                 return i_ret;
00995             }
00996             break;
00997     }
00998 
00999     TinyShuffle2( p_bordel );
01000 
01001     return i_ret;
01002 }
01003 
01004 static void SecondPass( uint32_t * p_bordel, uint32_t i_tmp )
01005 {
01006     uint32_t i, i_cmd, i_jc = 5;
01007 
01008     TinyShuffle3( p_bordel );
01009 
01010     for( i = 0, i_cmd = 0; i < 16; i++ )
01011     {
01012         if( p_bordel[ i ] > p_bordel[ i_cmd ] )
01013         {
01014             i_cmd = i;
01015         }
01016     }
01017 
01018     switch( i_cmd )
01019     {
01020         case 0:
01021             if( p_bordel[ 1 ] < p_bordel[ 8 ] )
01022             {
01023                 p_bordel[ 5 ] += 1;
01024             }
01025             break;
01026         case 4:
01027             if( (p_bordel[ 9 ] & 0x7777) == 0x3333 )
01028             {
01029                 p_bordel[ 5 ] -= 1;
01030             }
01031             else
01032             {
01033                 i_jc--;
01034                 if( p_bordel[ 1 ] < p_bordel[ 8 ] )
01035                 {
01036                     p_bordel[ 5 ] += 1;
01037                 }
01038                 break;
01039             }
01040             /* no break */
01041         case 7:
01042             p_bordel[ 2 ] -= 1;
01043             p_bordel[ 1 ] -= p_bordel[ 5 ];
01044             for( i = 0; i < 3; i++ )
01045             {
01046                 switch( p_bordel[ 1 ] & 3 )
01047                 {
01048                     case 0:
01049                         p_bordel[ 1 ] += 1;
01050                         /* no break */
01051                     case 1:
01052                         p_bordel[ 3 ] -= 8;
01053                         break;
01054                     case 2:
01055                         p_bordel[ 13 ] &= 0xFEFEFEF7;
01056                         break;
01057                     case 3:
01058                         p_bordel[ 8 ] |= 0x80080011;
01059                         break;
01060                 }
01061             }
01062             return;
01063         case 10:
01064             p_bordel[ 4 ] -= 1;
01065             p_bordel[ 5 ] += 1;
01066             p_bordel[ 6 ] -= 1;
01067             p_bordel[ 7 ] += 1;
01068             break;
01069         default:
01070             p_bordel[ 15 ] ^= 0x18547EFF;
01071             break;
01072     }
01073 
01074     for( i = 3; i--; )
01075     {
01076         switch( ( p_bordel[ 12 ] + p_bordel[ 13 ] + p_bordel[ 6 ] ) % 5 )
01077         {
01078             case 0:
01079                 p_bordel[ 12 ] -= 1;
01080                 /* no break */
01081             case 1:
01082                 p_bordel[ 12 ] -= 1;
01083                 p_bordel[ 13 ] += 1;
01084                 break;
01085             case 2:
01086                 p_bordel[ 13 ] += 4;
01087                 /* no break */
01088             case 3:
01089                 p_bordel[ 12 ] -= 1;
01090                 break;
01091             case 4:
01092                 i_jc--;
01093                 p_bordel[ 5 ] += 1;
01094                 p_bordel[ 6 ] -= 1;
01095                 p_bordel[ 7 ] += 1;
01096                 i = 3; /* Restart the whole loop */
01097                 break;
01098         }
01099     }
01100 
01101     TinyShuffle4( p_bordel );
01102 
01103     for( ; ; )
01104     {
01105         TinyShuffle5( p_bordel );
01106 
01107         switch( ( p_bordel[ 2 ] * 2 + 15 ) % 5 )
01108         {
01109             case 0:
01110                 if( ( p_bordel[ 3 ] + i_tmp ) <=
01111                     ( p_bordel[ 1 ] + p_bordel[ 15 ] ) )
01112                 {
01113                     p_bordel[ 3 ] += 1;
01114                 }
01115                 break;
01116             case 4:
01117                 p_bordel[ 10 ] -= 0x13;
01118                 break;
01119             case 3:
01120                 p_bordel[ 5 ] >>= 2;
01121                 break;
01122         }
01123 
01124         if( !( p_bordel[ 2 ] & 1 ) || i_jc == 0 )
01125         {
01126             break;
01127         }
01128 
01129         i_jc--;
01130         p_bordel[ 2 ] += 0x13;
01131         p_bordel[ 12 ] += 1;
01132     }
01133 
01134     p_bordel[ 2 ] &= 0x10076000;
01135 }
01136 
01137 static void ThirdPass( uint32_t * p_bordel )
01138 {
01139     uint32_t i_cmd;
01140 
01141     i_cmd = ((p_bordel[ 7 ] + p_bordel[ 14 ] + 10) >> 1) - p_bordel[ 14 ];
01142     i_cmd = i_cmd % 10;
01143 
01144     switch( i_cmd )
01145     {
01146         case 0:
01147             p_bordel[ 1 ] <<= 1;
01148             p_bordel[ 2 ] <<= 2;
01149             p_bordel[ 3 ] <<= 3;
01150             break;
01151         case 6:
01152             p_bordel[ i_cmd + 3 ] &= 0x5EDE36B;
01153             p_bordel[ 5 ] += p_bordel[ 8 ];
01154             p_bordel[ 4 ] += p_bordel[ 7 ];
01155             p_bordel[ 3 ] += p_bordel[ 6 ];
01156             p_bordel[ 2 ] += p_bordel[ 5 ];
01157             /* no break */
01158         case 2:
01159             p_bordel[ 1 ] += p_bordel[ 4 ];
01160             p_bordel[ 0 ] += p_bordel[ 3 ];
01161             TinyShuffle6( p_bordel );
01162             return; /* jc = 4 */
01163         case 3:
01164             if( (p_bordel[ 11 ] & p_bordel[ 2 ]) > 0x211B )
01165             {
01166                 p_bordel[ 6 ] += 1;
01167             }
01168             break;
01169         case 4:
01170             p_bordel[ 7 ] += 1;
01171             /* no break */
01172         case 5:
01173             p_bordel[ 9 ] ^= p_bordel[ 2 ];
01174             break;
01175         case 7:
01176             p_bordel[ 2 ] ^= (p_bordel[ 1 ] & p_bordel[ 13 ]);
01177             break;
01178         case 8:
01179             p_bordel[ 0 ] -= p_bordel[ 11 ] & p_bordel[ 15 ];
01180             return; /* jc = 4 */
01181         case 9:
01182             p_bordel[ 6 ] >>= (p_bordel[ 14 ] & 3);
01183             break;
01184     }
01185 
01186     SWAP( p_bordel[ 0 ], p_bordel[ 10 ] );
01187 
01188     TinyShuffle6( p_bordel );
01189 
01190     return; /* jc = 5 */
01191 }
01192 
01193 static void FourthPass( uint32_t * p_bordel )
01194 {
01195     uint32_t i, j;
01196 
01197     TinyShuffle7( p_bordel );
01198 
01199     switch( p_bordel[ 5 ] % 5)
01200     {
01201         case 0:
01202             p_bordel[ 0 ] += 1;
01203             break;
01204         case 2:
01205             p_bordel[ 11 ] ^= (p_bordel[ 3 ] + p_bordel[ 6 ] + p_bordel[ 8 ]);
01206             break;
01207         case 3:
01208             for( i = 4; i < 15 && (p_bordel[ i ] & 5) == 0; i++ )
01209             {
01210                 SWAP( p_bordel[ i ], p_bordel[ 15 - i ] );
01211             }
01212             break;
01213         case 4:
01214             p_bordel[ 12 ] -= 1;
01215             p_bordel[ 13 ] += 1;
01216             p_bordel[ 2 ] -= 0x64;
01217             p_bordel[ 3 ] += 0x64;
01218             TinyShuffle8( p_bordel );
01219             return;
01220     }
01221 
01222     for( i = 0, j = 0; i < 16; i++ )
01223     {
01224         if( p_bordel[ i ] > p_bordel[ j ] )
01225         {
01226             j = i;
01227         }
01228     }
01229 
01230     switch( p_bordel[ j ] % 100 )
01231     {
01232         case 0:
01233             SWAP( p_bordel[ 0 ], p_bordel[ j ] );
01234             break;
01235         case 8:
01236             p_bordel[ 1 ] >>= 1;
01237             p_bordel[ 2 ] <<= 1;
01238             p_bordel[ 14 ] >>= 3;
01239             p_bordel[ 15 ] <<= 4;
01240             break;
01241         case 57:
01242             p_bordel[ j ] += p_bordel[ 13 ];
01243             break;
01244         case 76:
01245             p_bordel[ 1 ] += 0x20E;
01246             p_bordel[ 5 ] += 0x223D;
01247             p_bordel[ 13 ] -= 0x576;
01248             p_bordel[ 15 ] += 0x576;
01249             return;
01250         case 91:
01251             p_bordel[ 2 ] -= 0x64;
01252             p_bordel[ 3 ] += 0x64;
01253             p_bordel[ 12 ] -= 1;
01254             p_bordel[ 13 ] += 1;
01255             break;
01256         case 99:
01257             p_bordel[ 0 ] += 1;
01258             p_bordel[ j ] += p_bordel[ 13 ];
01259             break;
01260     }
01261 
01262     TinyShuffle8( p_bordel );
01263 }
01264 
01265 /*****************************************************************************
01266  * TinyShuffle[12345678]: tiny shuffle subroutines
01267  *****************************************************************************
01268  * These standalone functions are little helpers for the shuffling process.
01269  *****************************************************************************/
01270 static void TinyShuffle1( uint32_t * p_bordel )
01271 {
01272     uint32_t i_cmd = (p_bordel[ 5 ] + 10) >> 2;
01273 
01274     if( p_bordel[ 5 ] > 0x7D0 )
01275     {
01276         i_cmd -= 0x305;
01277     }
01278 
01279     switch( i_cmd & 3 )
01280     {
01281         case 0:
01282             p_bordel[ 5 ] += 5;
01283             break;
01284         case 1:
01285             p_bordel[ 4 ] -= 1;
01286             break;
01287         case 2:
01288             if( p_bordel[ 4 ] & 5 )
01289             {
01290                 p_bordel[ 1 ] ^= 0x4D;
01291             }
01292             /* no break */
01293         case 3:
01294             p_bordel[ 12 ] += 5;
01295             break;
01296     }
01297 }
01298 
01299 static void TinyShuffle2( uint32_t * p_bordel )
01300 {
01301     uint32_t i, j;
01302 
01303     for( i = 0, j = 0; i < 16; i++ )
01304     {
01305         if( (p_bordel[ i ] & 0x777) > (p_bordel[ j ] & 0x777) )
01306         {
01307             j = i;
01308         }
01309     }
01310 
01311     if( j > 5 )
01312     {
01313         for( ; j < 15; j++ )
01314         {
01315             p_bordel[ j ] += p_bordel[ j + 1 ];
01316         }
01317     }
01318     else
01319     {
01320         p_bordel[ 2 ] &= 0xB62FC;
01321     }
01322 }
01323 
01324 static void TinyShuffle3( uint32_t * p_bordel )
01325 {
01326     uint32_t i_cmd = p_bordel[ 6 ] + 0x194B;
01327 
01328     if( p_bordel[ 6 ] > 0x2710 )
01329     {
01330         i_cmd >>= 1;
01331     }
01332 
01333     switch( i_cmd & 3 )
01334     {
01335         case 1:
01336             p_bordel[ 3 ] += 0x19FE;
01337             break;
01338         case 2:
01339             p_bordel[ 7 ] -= p_bordel[ 3 ] >> 2;
01340             /* no break */
01341         case 0:
01342             p_bordel[ 5 ] ^= 0x248A;
01343             break;
01344     }
01345 }
01346 
01347 static void TinyShuffle4( uint32_t * p_bordel )
01348 {
01349     uint32_t i, j;
01350 
01351     for( i = 0, j = 0; i < 16; i++ )
01352     {
01353         if( p_bordel[ i ] < p_bordel[ j ] )
01354         {
01355             j = i;
01356         }
01357     }
01358 
01359     if( (p_bordel[ j ] % (j + 1)) > 10 )
01360     {
01361         p_bordel[ 1 ] -= 1;
01362         p_bordel[ 2 ] += 0x13;
01363         p_bordel[ 12 ] += 1;
01364     }
01365 }
01366 
01367 static void TinyShuffle5( uint32_t * p_bordel )
01368 {
01369     uint32_t i;
01370 
01371     p_bordel[ 2 ] &= 0x7F3F;
01372 
01373     for( i = 0; i < 5; i++ )
01374     {
01375         switch( ( p_bordel[ 2 ] + 10 + i ) % 5 )
01376         {
01377             case 0:
01378                 p_bordel[ 12 ] &= p_bordel[ 2 ];
01379                 /* no break */
01380             case 1:
01381                 p_bordel[ 3 ] ^= p_bordel[ 15 ];
01382                 break;
01383             case 2:
01384                 p_bordel[ 15 ] += 0x576;
01385                 /* no break */
01386             case 3:
01387                 p_bordel[ 7 ] -= 0x2D;
01388                 /* no break */
01389             case 4:
01390                 p_bordel[ 1 ] <<= 1;
01391                 break;
01392         }
01393     }
01394 }
01395 
01396 static void TinyShuffle6( uint32_t * p_bordel )
01397 {
01398     uint32_t i, j;
01399 
01400     for( i = 0; i < 8; i++ )
01401     {
01402         j = p_bordel[ 3 ] & 0x7514 ? 5 : 7;
01403         SWAP( p_bordel[ i ], p_bordel[ i + j ] );
01404     }
01405 }
01406 
01407 static void TinyShuffle7( uint32_t * p_bordel )
01408 {
01409     uint32_t i;
01410 
01411     i = (((p_bordel[ 9 ] + p_bordel[ 15 ] + 12) >> 2) - p_bordel[ 4 ]) & 7;
01412 
01413     while( i-- )
01414     {
01415         SWAP( p_bordel[ i ], p_bordel[ i + 3 ] );
01416     }
01417 
01418     SWAP( p_bordel[ 1 ], p_bordel[ 10 ] );
01419 }
01420 
01421 static void TinyShuffle8( uint32_t * p_bordel )
01422 {
01423     uint32_t i;
01424 
01425     i = (p_bordel[ 0 ] & p_bordel[ 6 ]) & 0xF;
01426 
01427     switch( p_bordel[ i ] % 1000 )
01428     {
01429         case 7:
01430             if( (p_bordel[ i ] & 0x777) > (p_bordel[ 7 ] & 0x5555) )
01431             {
01432                 p_bordel[ i ] ^= p_bordel[ 5 ] & p_bordel[ 3 ];
01433             }
01434             break;
01435         case 19:
01436             p_bordel[ 15 ] &= 0x5555;
01437             break;
01438         case 93:
01439             p_bordel[ i ] ^= p_bordel[ 15 ];
01440             break;
01441         case 100:
01442             SWAP( p_bordel[ 0 ], p_bordel[ 3 ] );
01443             SWAP( p_bordel[ 1 ], p_bordel[ 6 ] );
01444             SWAP( p_bordel[ 3 ], p_bordel[ 6 ] );
01445             SWAP( p_bordel[ 4 ], p_bordel[ 9 ] );
01446             SWAP( p_bordel[ 5 ], p_bordel[ 8 ] );
01447             SWAP( p_bordel[ 6 ], p_bordel[ 7 ] );
01448             SWAP( p_bordel[ 13 ], p_bordel[ 14 ] );
01449             break;
01450         case 329:
01451             p_bordel[ i ] += p_bordel[ 1 ] ^ 0x80080011;
01452             p_bordel[ i ] += p_bordel[ 2 ] ^ 0xBEEFDEAD;
01453             p_bordel[ i ] += p_bordel[ 3 ] ^ 0x8765F444;
01454             p_bordel[ i ] += p_bordel[ 4 ] ^ 0x78145326;
01455             break;
01456         case 567:
01457             p_bordel[ 12 ] -= p_bordel[ i ];
01458             p_bordel[ 13 ] += p_bordel[ i ];
01459             break;
01460         case 612:
01461             p_bordel[ i ] += p_bordel[ 1 ];
01462             p_bordel[ i ] -= p_bordel[ 7 ];
01463             p_bordel[ i ] -= p_bordel[ 8 ];
01464             p_bordel[ i ] += p_bordel[ 9 ];
01465             p_bordel[ i ] += p_bordel[ 13 ];
01466             break;
01467         case 754:
01468             i = __MIN( i, 12 );
01469             p_bordel[ i + 1 ] >>= 1;
01470             p_bordel[ i + 2 ] <<= 4;
01471             p_bordel[ i + 3 ] >>= 3;
01472             break;
01473         case 777:
01474             p_bordel[ 1 ] += 0x20E;
01475             p_bordel[ 5 ] += 0x223D;
01476             p_bordel[ 13 ] -= 0x576;
01477             p_bordel[ 15 ] += 0x576;
01478             break;
01479         case 981:
01480             if( (p_bordel[ i ] ^ 0x8765F441) < 0x2710 )
01481             {
01482                 SWAP( p_bordel[ 0 ], p_bordel[ 1 ] );
01483             }
01484             else
01485             {
01486                 SWAP( p_bordel[ 1 ], p_bordel[ 11 ] );
01487             }
01488             break;
01489     }
01490 }
01491 
01492 /*****************************************************************************
01493  * GetSystemKey: get the system key
01494  *****************************************************************************
01495  * Compute the system key from various system information, see HashSystemInfo.
01496  *****************************************************************************/
01497 static int GetSystemKey( uint32_t *p_sys_key, vlc_bool_t b_ipod )
01498 {
01499     static char const p_secret1[ 8 ] = "YuaFlafu";
01500     static char const p_secret2[ 8 ] = "zPif98ga";
01501     struct md5_s md5;
01502     int64_t i_ipod_id;
01503     uint32_t p_system_hash[ 4 ];
01504 
01505     /* Compute the MD5 hash of our system info */
01506     if( ( !b_ipod && HashSystemInfo( p_system_hash ) ) ||
01507         (  b_ipod && GetiPodID( &i_ipod_id ) ) )
01508     {
01509         return -1;
01510     }
01511 
01512     /* Combine our system info hash with additional secret data. The resulting
01513      * MD5 hash will be our system key. */
01514     InitMD5( &md5 );
01515     AddMD5( &md5, p_secret1, 8 );
01516 
01517     if( !b_ipod )
01518     {
01519         AddMD5( &md5, (uint8_t *)p_system_hash, 6 );
01520         AddMD5( &md5, (uint8_t *)p_system_hash, 6 );
01521         AddMD5( &md5, (uint8_t *)p_system_hash, 6 );
01522         AddMD5( &md5, p_secret2, 8 );
01523     }
01524     else
01525     {
01526         i_ipod_id = U64_AT(&i_ipod_id);
01527         AddMD5( &md5, (uint8_t *)&i_ipod_id, sizeof(i_ipod_id) );
01528         AddMD5( &md5, (uint8_t *)&i_ipod_id, sizeof(i_ipod_id) );
01529         AddMD5( &md5, (uint8_t *)&i_ipod_id, sizeof(i_ipod_id) );
01530     }
01531 
01532     EndMD5( &md5 );
01533 
01534     memcpy( p_sys_key, md5.p_digest, 16 );
01535 
01536     return 0;
01537 }
01538 
01539 #ifdef WIN32
01540 #   define DRMS_DIRNAME "drms"
01541 #else
01542 #   define DRMS_DIRNAME ".drms"
01543 #endif
01544 
01545 /*****************************************************************************
01546  * WriteUserKey: write the user key to hard disk
01547  *****************************************************************************
01548  * Write the user key to the hard disk so that it can be reused later or used
01549  * on operating systems other than Win32.
01550  *****************************************************************************/
01551 static int WriteUserKey( void *_p_drms, uint32_t *p_user_key )
01552 {
01553     struct drms_s *p_drms = (struct drms_s *)_p_drms;
01554     FILE *file;
01555     int i_ret = -1;
01556     char psz_path[ PATH_MAX ];
01557 
01558     snprintf( psz_path, PATH_MAX - 1,
01559               "%s/" DRMS_DIRNAME, p_drms->psz_homedir );
01560 
01561 #if defined( HAVE_ERRNO_H )
01562 #   if defined( WIN32 )
01563     if( !mkdir( psz_path ) || errno == EEXIST )
01564 #   else
01565     if( !mkdir( psz_path, 0755 ) || errno == EEXIST )
01566 #   endif
01567 #else
01568     if( !mkdir( psz_path ) )
01569 #endif
01570     {
01571         snprintf( psz_path, PATH_MAX - 1, "%s/" DRMS_DIRNAME "/%08X.%03d",
01572                   p_drms->psz_homedir, p_drms->i_user, p_drms->i_key );
01573 
01574         file = fopen( psz_path, "wb" );
01575         if( file != NULL )
01576         {
01577             i_ret = fwrite( p_user_key, sizeof(uint32_t),
01578                             4, file ) == 4 ? 0 : -1;
01579             fclose( file );
01580         }
01581     }
01582 
01583     return i_ret;
01584 }
01585 
01586 /*****************************************************************************
01587  * ReadUserKey: read the user key from hard disk
01588  *****************************************************************************
01589  * Retrieve the user key from the hard disk if available.
01590  *****************************************************************************/
01591 static int ReadUserKey( void *_p_drms, uint32_t *p_user_key )
01592 {
01593     struct drms_s *p_drms = (struct drms_s *)_p_drms;
01594     FILE *file;
01595     int i_ret = -1;
01596     char psz_path[ PATH_MAX ];
01597 
01598     snprintf( psz_path, PATH_MAX - 1,
01599               "%s/" DRMS_DIRNAME "/%08X.%03d", p_drms->psz_homedir,
01600               p_drms->i_user, p_drms->i_key );
01601 
01602     file = fopen( psz_path, "rb" );
01603     if( file != NULL )
01604     {
01605         i_ret = fread( p_user_key, sizeof(uint32_t),
01606                        4, file ) == 4 ? 0 : -1;
01607         fclose( file );
01608     }
01609 
01610     return i_ret;
01611 }
01612 
01613 /*****************************************************************************
01614  * GetUserKey: get the user key
01615  *****************************************************************************
01616  * Retrieve the user key from the hard disk if available, otherwise generate
01617  * it from the system key. If the key could be successfully generated, write
01618  * it to the hard disk for future use.
01619  *****************************************************************************/
01620 static int GetUserKey( void *_p_drms, uint32_t *p_user_key )
01621 {
01622     static char const p_secret[] = "mUfnpognadfgf873";
01623     struct drms_s *p_drms = (struct drms_s *)_p_drms;
01624     struct aes_s aes;
01625     struct shuffle_s shuffle;
01626     uint32_t i, y;
01627     uint32_t *p_sci_data;
01628     uint32_t i_user, i_key;
01629     uint32_t p_sys_key[ 4 ];
01630     uint32_t i_sci_size, i_blocks, i_remaining;
01631     uint32_t *p_sci0, *p_sci1, *p_buffer;
01632     uint32_t p_sci_key[ 4 ];
01633     char *psz_ipod;
01634     int i_ret = -1;
01635 
01636     if( !ReadUserKey( p_drms, p_user_key ) )
01637     {
01638         REVERSE( p_user_key, 4 );
01639         return 0;
01640     }
01641 
01642     psz_ipod = getenv( "IPOD" );
01643 
01644     if( GetSystemKey( p_sys_key, psz_ipod ? VLC_TRUE : VLC_FALSE ) )
01645     {
01646         return -1;
01647     }
01648 
01649     if( GetSCIData( psz_ipod, &p_sci_data, &i_sci_size ) )
01650     {
01651         return -1;
01652     }
01653 
01654     /* Phase 1: unscramble the SCI data using the system key and shuffle
01655      *          it using DoShuffle(). */
01656 
01657     /* Skip the first 4 bytes (some sort of header). Decrypt the rest. */
01658     i_blocks = (i_sci_size - 4) / 16;
01659     i_remaining = (i_sci_size - 4) - (i_blocks * 16);
01660     p_buffer = p_sci_data + 1;
01661 
01662     /* Decrypt and shuffle our data at the same time */
01663     InitAES( &aes, p_sys_key );
01664     REVERSE( p_sys_key, 4 );
01665     REVERSE( p_sci_data, 1 );
01666     InitShuffle( &shuffle, p_sys_key, p_sci_data[ 0 ] );
01667 
01668     memcpy( p_sci_key, p_secret, 16 );
01669     REVERSE( p_sci_key, 4 );
01670 
01671     while( i_blocks-- )
01672     {
01673         uint32_t p_tmp[ 4 ];
01674 
01675         REVERSE( p_buffer, 4 );
01676         DecryptAES( &aes, p_tmp, p_buffer );
01677         BlockXOR( p_tmp, p_sci_key, p_tmp );
01678 
01679         /* Use the previous scrambled data as the key for next block */
01680         memcpy( p_sci_key, p_buffer, 16 );
01681 
01682         /* Shuffle the decrypted data using a custom routine */
01683         DoShuffle( &shuffle, p_tmp, 4 );
01684 
01685         /* Copy this block back to p_buffer */
01686         memcpy( p_buffer, p_tmp, 16 );
01687 
01688         p_buffer += 4;
01689     }
01690 
01691     if( i_remaining >= 4 )
01692     {
01693         i_remaining /= 4;
01694         REVERSE( p_buffer, i_remaining );
01695         DoShuffle( &shuffle, p_buffer, i_remaining );
01696     }
01697 
01698     /* Phase 2: look for the user key in the generated data. I must admit I
01699      *          do not understand what is going on here, because it almost
01700      *          looks like we are browsing data that makes sense, even though
01701      *          the DoShuffle() part made it completely meaningless. */
01702 
01703     y = 0;
01704     REVERSE( p_sci_data + 5, 1 );
01705     i = U32_AT( p_sci_data + 5 );
01706     i_sci_size -= 22 * sizeof(uint32_t);
01707     p_sci1 = p_sci_data + 22;
01708     p_sci0 = NULL;
01709 
01710     while( i_sci_size >= 20 && i > 0 )
01711     {
01712         if( p_sci0 == NULL )
01713         {
01714             i_sci_size -= 18 * sizeof(uint32_t);
01715             if( i_sci_size < 20 )
01716             {
01717                 break;
01718             }
01719 
01720             p_sci0 = p_sci1;
01721             REVERSE( p_sci1 + 17, 1 );
01722             y = U32_AT( p_sci1 + 17 );
01723             p_sci1 += 18;
01724         }
01725 
01726         if( !y )
01727         {
01728             i--;
01729             p_sci0 = NULL;
01730             continue;
01731         }
01732 
01733         i_user = U32_AT( p_sci0 );
01734         i_key = U32_AT( p_sci1 );
01735         REVERSE( &i_user, 1 );
01736         REVERSE( &i_key, 1 );
01737         if( i_user == p_drms->i_user && ( ( i_key == p_drms->i_key ) ||
01738             ( !p_drms->i_key && ( p_sci1 == (p_sci0 + 18) ) ) ) )
01739         {
01740             memcpy( p_user_key, p_sci1 + 1, 16 );
01741             REVERSE( p_sci1 + 1, 4 );
01742             WriteUserKey( p_drms, p_sci1 + 1 );
01743             i_ret = 0;
01744             break;
01745         }
01746 
01747         y--;
01748         p_sci1 += 5;
01749         i_sci_size -= 5 * sizeof(uint32_t);
01750     }
01751 
01752     free( p_sci_data );
01753 
01754     return i_ret;
01755 }
01756 
01757 /*****************************************************************************
01758  * GetSCIData: get SCI data from "SC Info.sidb"
01759  *****************************************************************************
01760  * Read SCI data from "\Apple Computer\iTunes\SC Info\SC Info.sidb"
01761  *****************************************************************************/
01762 static int GetSCIData( char *psz_ipod, uint32_t **pp_sci,
01763                        uint32_t *pi_sci_size )
01764 {
01765     FILE *file;
01766     char *psz_path = NULL;
01767     char p_tmp[ PATH_MAX ];
01768     int i_ret = -1;
01769 
01770     if( psz_ipod == NULL )
01771     {
01772 #ifdef WIN32
01773         char *p_filename = "\\Apple Computer\\iTunes\\SC Info\\SC Info.sidb";
01774         typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
01775                                                    LPSTR );
01776         HINSTANCE shfolder_dll = NULL;
01777         SHGETFOLDERPATH dSHGetFolderPath = NULL;
01778 
01779         if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
01780         {
01781             dSHGetFolderPath =
01782                 (SHGETFOLDERPATH)GetProcAddress( shfolder_dll,
01783                                                  _T("SHGetFolderPathA") );
01784         }
01785 
01786         if( dSHGetFolderPath != NULL &&
01787             SUCCEEDED( dSHGetFolderPath( NULL, CSIDL_COMMON_APPDATA,
01788                                          NULL, 0, p_tmp ) ) )
01789         {
01790             strncat( p_tmp, p_filename, min( strlen( p_filename ),
01791                      (sizeof(p_tmp)/sizeof(p_tmp[0]) - 1) -
01792                      strlen( p_tmp ) ) );
01793             psz_path = p_tmp;
01794         }
01795 
01796         if( shfolder_dll != NULL )
01797         {
01798             FreeLibrary( shfolder_dll );
01799         }
01800 #endif
01801     }
01802     else
01803     {
01804 #define ISCINFO "iSCInfo"
01805         if( strstr( psz_ipod, ISCINFO ) == NULL )
01806         {
01807             snprintf( p_tmp, sizeof(p_tmp)/sizeof(p_tmp[0]) - 1,
01808                       "%s/iPod_Control/iTunes/" ISCINFO "2", psz_ipod );
01809             psz_path = p_tmp;
01810         }
01811         else
01812         {
01813             psz_path = psz_ipod;
01814         }
01815     }
01816 
01817     if( psz_path == NULL )
01818     {
01819         return -1;
01820     }
01821 
01822     file = fopen( psz_path, "rb" );
01823     if( file != NULL )
01824     {
01825         struct stat st;
01826 
01827         if( !fstat( fileno( file ), &st ) && st.st_size >= 4 )
01828         {
01829             *pp_sci = malloc( st.st_size );
01830             if( *pp_sci != NULL )
01831             {
01832                 if( fread( *pp_sci, 1, st.st_size,
01833                            file ) == (size_t)st.st_size )
01834                 {
01835                     *pi_sci_size = st.st_size;
01836                     i_ret = 0;
01837                 }
01838                 else
01839                 {
01840                     free( (void *)*pp_sci );
01841                     *pp_sci = NULL;
01842                 }
01843             }
01844         }
01845 
01846         fclose( file );
01847     }
01848 
01849     return i_ret;
01850 }
01851 
01852 /*****************************************************************************
01853  * HashSystemInfo: hash system information
01854  *****************************************************************************
01855  * This function computes the MD5 hash of the C: hard drive serial number,
01856  * BIOS version, CPU type and Windows version.
01857  *****************************************************************************/
01858 static int HashSystemInfo( uint32_t *p_system_hash )
01859 {
01860     struct md5_s md5;
01861     int i_ret = 0;
01862 
01863 #ifdef WIN32
01864     HKEY i_key;
01865     unsigned int i;
01866     DWORD i_size;
01867     DWORD i_serial;
01868     LPBYTE p_reg_buf;
01869 
01870     static LPCTSTR p_reg_keys[ 3 ][ 2 ] =
01871     {
01872         {
01873             _T("HARDWARE\\DESCRIPTION\\System"),
01874             _T("SystemBiosVersion")
01875         },
01876 
01877         {
01878             _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
01879             _T("ProcessorNameString")
01880         },
01881 
01882         {
01883             _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
01884             _T("ProductId")
01885         }
01886     };
01887 
01888     InitMD5( &md5 );
01889 
01890     AddMD5( &md5, "cache-control", 13 );
01891     AddMD5( &md5, "Ethernet", 8 );
01892 
01893     GetVolumeInformation( _T("C:\\"), NULL, 0, &i_serial,
01894                           NULL, NULL, NULL, 0 );
01895     AddMD5( &md5, (uint8_t *)&i_serial, 4 );
01896 
01897     for( i = 0; i < sizeof(p_reg_keys) / sizeof(p_reg_keys[ 0 ]); i++ )
01898     {
01899         if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, p_reg_keys[ i ][ 0 ],
01900                           0, KEY_READ, &i_key ) != ERROR_SUCCESS )
01901         {
01902             continue;
01903         }
01904 
01905         if( RegQueryValueEx( i_key, p_reg_keys[ i ][ 1 ],
01906                              NULL, NULL, NULL, &i_size ) != ERROR_SUCCESS )
01907         {
01908             RegCloseKey( i_key );
01909             continue;
01910         }
01911 
01912         p_reg_buf = malloc( i_size );
01913 
01914         if( p_reg_buf != NULL )
01915         {
01916             if( RegQueryValueEx( i_key, p_reg_keys[ i ][ 1 ],
01917                                  NULL, NULL, p_reg_buf,
01918                                  &i_size ) == ERROR_SUCCESS )
01919             {
01920                 AddMD5( &md5, (uint8_t *)p_reg_buf, i_size );
01921             }
01922 
01923             free( p_reg_buf );
01924         }
01925 
01926         RegCloseKey( i_key );
01927     }
01928 
01929 #else
01930     InitMD5( &md5 );
01931     i_ret = -1;
01932 #endif
01933 
01934     EndMD5( &md5 );
01935     memcpy( p_system_hash, md5.p_digest, 16 );
01936 
01937     return i_ret;
01938 }
01939 
01940 /*****************************************************************************
01941  * GetiPodID: Get iPod ID
01942  *****************************************************************************
01943  * This function gets the iPod ID.
01944  *****************************************************************************/
01945 static int GetiPodID( int64_t *p_ipod_id )
01946 {
01947     int i_ret = -1;
01948 
01949 #define PROD_NAME   "iPod"
01950 #define VENDOR_NAME "Apple Computer, Inc."
01951 
01952     char *psz_ipod_id = getenv( "IPODID" );
01953     if( psz_ipod_id != NULL )
01954     {
01955         *p_ipod_id = strtoll( psz_ipod_id, NULL, 16 );
01956         return 0;
01957     }
01958 
01959 #ifdef SYS_DARWIN
01960     CFTypeRef value;
01961     mach_port_t port;
01962     io_object_t device;
01963     io_iterator_t iterator;
01964     CFMutableDictionaryRef match_dic;
01965     CFMutableDictionaryRef smatch_dic;
01966 
01967     if( IOMasterPort( MACH_PORT_NULL, &port ) == KERN_SUCCESS )
01968     {
01969         smatch_dic = IOServiceMatching( "IOFireWireUnit" );
01970         match_dic = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
01971                                            &kCFTypeDictionaryKeyCallBacks,
01972                                            &kCFTypeDictionaryValueCallBacks );
01973 
01974         if( smatch_dic != NULL && match_dic != NULL )
01975         {
01976             CFDictionarySetValue( smatch_dic,
01977                                   CFSTR("FireWire Vendor Name"),
01978                                   CFSTR(VENDOR_NAME) );
01979             CFDictionarySetValue( smatch_dic,
01980                                   CFSTR("FireWire Product Name"),
01981                                   CFSTR(PROD_NAME) );
01982 
01983             CFDictionarySetValue( match_dic,
01984                                   CFSTR(kIOPropertyMatchKey),
01985                                   smatch_dic );
01986 
01987             if( IOServiceGetMatchingServices( port, match_dic,
01988                                               &iterator ) == KERN_SUCCESS )
01989             {
01990                 while( ( device = IOIteratorNext( iterator ) ) != NULL )
01991                 {
01992                     value = IORegistryEntryCreateCFProperty( device,
01993                         CFSTR("GUID"), kCFAllocatorDefault, kNilOptions );
01994 
01995                     if( value != NULL )
01996                     {
01997                         if( CFGetTypeID( value ) == CFNumberGetTypeID() )
01998                         {
01999                             int64_t i_ipod_id;
02000                             CFNumberGetValue( (CFNumberRef)value,
02001                                               kCFNumberLongLongType,
02002                                               &i_ipod_id );
02003                             *p_ipod_id = i_ipod_id;
02004                             i_ret = 0;
02005                         }
02006 
02007                         CFRelease( value );
02008                     }
02009 
02010                     IOObjectRelease( device );
02011 
02012                     if( !i_ret ) break;
02013                 }
02014 
02015                 IOObjectRelease( iterator );
02016             }
02017         }
02018 
02019         mach_port_deallocate( mach_task_self(), port );
02020     }
02021 
02022 #elif HAVE_SYSFS_LIBSYSFS_H
02023     struct sysfs_bus *bus = NULL;
02024     struct dlist *devlist = NULL;
02025     struct dlist *attributes = NULL;
02026     struct sysfs_device *curdev = NULL;
02027     struct sysfs_attribute *curattr = NULL;
02028 
02029     bus = sysfs_open_bus( "ieee1394" );
02030     if( bus != NULL )
02031     {
02032         devlist = sysfs_get_bus_devices( bus );
02033         if( devlist != NULL )
02034         {
02035             dlist_for_each_data( devlist, curdev, struct sysfs_device )
02036             {
02037                 attributes = sysfs_get_device_attributes( curdev );
02038                 if( attributes != NULL )
02039                 {
02040                     dlist_for_each_data( attributes, curattr,
02041                                          struct sysfs_attribute )
02042                     {
02043                         if( ( strcmp( curattr->name, "model_name" ) == 0 ) &&
02044                             ( strncmp( curattr->value, PROD_NAME,
02045                                        sizeof(PROD_NAME) ) == 0 ) )
02046                         {
02047                             *p_ipod_id = strtoll( curdev->name, NULL, 16 );
02048                             i_ret = 0;
02049                             break;
02050                         }
02051                     }
02052                 }
02053 
02054                 if( !i_ret ) break;
02055             }
02056         }
02057 
02058         sysfs_close_bus( bus );
02059     }
02060 #endif
02061 
02062     return i_ret;
02063 }
02064 
02065 #else /* !defined( UNDER_CE ) */
02066 
02067 void *drms_alloc( char *psz_homedir ){ return 0; }
02068 void drms_free( void *a ){}
02069 void drms_decrypt( void *a, uint32_t *b, uint32_t c  ){}
02070 int drms_init( void *a, uint32_t b, uint8_t *c, uint32_t d ){ return -1; }
02071 
02072 #endif /* defined( UNDER_CE ) */

Generated on Tue Dec 20 10:14:34 2005 for vlc-0.8.4a by  doxygen 1.4.2