]> git.sesse.net Git - vlc/blob - modules/demux/mp4/drms.c
Remove stdlib.h
[vlc] / modules / demux / mp4 / drms.c
1 /*****************************************************************************
2  * drms.c: DRMS
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Sam Hocevar <sam@zoy.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25
26 #ifdef WIN32
27 #   include <io.h>
28 #else
29 #   include <stdio.h>
30 #endif
31
32 #ifdef __LIBVLC__
33 #   include <vlc/vlc.h>
34 #   include <vlc_md5.h>
35 #   include "libmp4.h"
36 #   include <vlc_charset.h>
37 #else
38 #   include "drmsvl.h"
39 #endif
40
41 #ifdef HAVE_ERRNO_H
42 #   include <errno.h>
43 #endif
44
45 #ifdef WIN32
46 #   if !defined( UNDER_CE )
47 #       include <direct.h>
48 #   endif
49 #   include <tchar.h>
50 #   include <shlobj.h>
51 #   include <windows.h>
52 #endif
53
54 #ifdef HAVE_SYS_STAT_H
55 #   include <sys/stat.h>
56 #endif
57 #ifdef HAVE_SYS_TYPES_H
58 #   include <sys/types.h>
59 #endif
60
61 /* In Solaris (and perhaps others) PATH_MAX is in limits.h. */
62 #ifdef HAVE_LIMITS_H
63 #   include <limits.h>
64 #endif
65
66 #ifdef __APPLE__
67 #   include <mach/mach.h>
68 #   include <IOKit/IOKitLib.h>
69 #   include <CoreFoundation/CFNumber.h>
70 #endif
71
72 #ifdef HAVE_SYSFS_LIBSYSFS_H
73 #   include <sysfs/libsysfs.h>
74 #endif
75
76 #include "drms.h"
77 #include "drmstables.h"
78
79 #if !defined( UNDER_CE )
80 /*****************************************************************************
81  * aes_s: AES keys structure
82  *****************************************************************************
83  * This structure stores a set of keys usable for encryption and decryption
84  * with the AES/Rijndael algorithm.
85  *****************************************************************************/
86 struct aes_s
87 {
88     uint32_t pp_enc_keys[ AES_KEY_COUNT + 1 ][ 4 ];
89     uint32_t pp_dec_keys[ AES_KEY_COUNT + 1 ][ 4 ];
90 };
91
92 #ifdef __LIBVLC__
93 # define Digest DigestMD5
94 #else
95 /*****************************************************************************
96  * md5_s: MD5 message structure
97  *****************************************************************************
98  * This structure stores the static information needed to compute an MD5
99  * hash. It has an extra data buffer to allow non-aligned writes.
100  *****************************************************************************/
101 struct md5_s
102 {
103     uint64_t i_bits;      /* Total written bits */
104     uint32_t p_digest[4]; /* The MD5 digest */
105     uint32_t p_data[16];  /* Buffer to cache non-aligned writes */
106 };
107 #endif
108
109 /*****************************************************************************
110  * shuffle_s: shuffle structure
111  *****************************************************************************
112  * This structure stores the static information needed to shuffle data using
113  * a custom algorithm.
114  *****************************************************************************/
115 struct shuffle_s
116 {
117     uint32_t i_version;
118     uint32_t p_commands[ 20 ];
119     uint32_t p_bordel[ 16 ];
120 };
121
122 #define SWAP( a, b ) { (a) ^= (b); (b) ^= (a); (a) ^= (b); }
123
124 /*****************************************************************************
125  * drms_s: DRMS structure
126  *****************************************************************************
127  * This structure stores the static information needed to decrypt DRMS data.
128  *****************************************************************************/
129 struct drms_s
130 {
131     uint32_t i_user;
132     uint32_t i_key;
133     uint8_t  p_iviv[ 16 ];
134     uint8_t *p_name;
135
136     uint32_t p_key[ 4 ];
137     struct aes_s aes;
138
139     char     psz_homedir[ PATH_MAX ];
140 };
141
142 /*****************************************************************************
143  * Local prototypes
144  *****************************************************************************/
145 static void InitAES       ( struct aes_s *, uint32_t * );
146 static void DecryptAES    ( struct aes_s *, uint32_t *, const uint32_t * );
147
148 #ifndef __LIBVLC__
149 static void InitMD5       ( struct md5_s * );
150 static void AddMD5        ( struct md5_s *, const uint8_t *, uint32_t );
151 static void EndMD5        ( struct md5_s * );
152 static void Digest        ( struct md5_s *, uint32_t * );
153 #endif
154
155 static void InitShuffle   ( struct shuffle_s *, uint32_t *, uint32_t );
156 static void DoShuffle     ( struct shuffle_s *, uint32_t *, uint32_t );
157
158 static uint32_t FirstPass ( uint32_t * );
159 static void SecondPass    ( uint32_t *, uint32_t );
160 static void ThirdPass     ( uint32_t * );
161 static void FourthPass    ( uint32_t * );
162 static void TinyShuffle1  ( uint32_t * );
163 static void TinyShuffle2  ( uint32_t * );
164 static void TinyShuffle3  ( uint32_t * );
165 static void TinyShuffle4  ( uint32_t * );
166 static void TinyShuffle5  ( uint32_t * );
167 static void TinyShuffle6  ( uint32_t * );
168 static void TinyShuffle7  ( uint32_t * );
169 static void TinyShuffle8  ( uint32_t * );
170 static void DoExtShuffle  ( uint32_t * );
171
172 static int GetSystemKey   ( uint32_t *, vlc_bool_t );
173 static int WriteUserKey   ( void *, uint32_t * );
174 static int ReadUserKey    ( void *, uint32_t * );
175 static int GetUserKey     ( void *, uint32_t * );
176
177 static int GetSCIData     ( char *, uint32_t **, uint32_t * );
178 static int HashSystemInfo ( uint32_t * );
179 static int GetiPodID      ( int64_t * );
180
181 #ifdef WORDS_BIGENDIAN
182 /*****************************************************************************
183  * Reverse: reverse byte order
184  *****************************************************************************/
185 static inline void Reverse( uint32_t *p_buffer, int n )
186 {
187     int i;
188
189     for( i = 0; i < n; i++ )
190     {
191         p_buffer[ i ] = GetDWLE(&p_buffer[ i ]);
192     }
193 }
194 #    define REVERSE( p, n ) Reverse( p, n )
195 #else
196 #    define REVERSE( p, n )
197 #endif
198
199 /*****************************************************************************
200  * BlockXOR: XOR two 128 bit blocks
201  *****************************************************************************/
202 static inline void BlockXOR( uint32_t *p_dest, uint32_t *p_s1, uint32_t *p_s2 )
203 {
204     int i;
205
206     for( i = 0; i < 4; i++ )
207     {
208         p_dest[ i ] = p_s1[ i ] ^ p_s2[ i ];
209     }
210 }
211
212 /*****************************************************************************
213  * drms_alloc: allocate a DRMS structure
214  *****************************************************************************/
215 void *drms_alloc( char *psz_homedir )
216 {
217     struct drms_s *p_drms;
218
219     p_drms = malloc( sizeof(struct drms_s) );
220
221     if( p_drms == NULL )
222     {
223         return NULL;
224     }
225
226     memset( p_drms, 0, sizeof(struct drms_s) );
227
228     strncpy( p_drms->psz_homedir, psz_homedir, PATH_MAX );
229     p_drms->psz_homedir[ PATH_MAX - 1 ] = '\0';
230
231     return (void *)p_drms;
232 }
233
234 /*****************************************************************************
235  * drms_free: free a previously allocated DRMS structure
236  *****************************************************************************/
237 void drms_free( void *_p_drms )
238 {
239     struct drms_s *p_drms = (struct drms_s *)_p_drms;
240
241     if( p_drms->p_name != NULL )
242     {
243         free( (void *)p_drms->p_name );
244     }
245
246     free( p_drms );
247 }
248
249 /*****************************************************************************
250  * drms_decrypt: unscramble a chunk of data
251  *****************************************************************************/
252 void drms_decrypt( void *_p_drms, uint32_t *p_buffer, uint32_t i_bytes )
253 {
254     struct drms_s *p_drms = (struct drms_s *)_p_drms;
255     uint32_t p_key[ 4 ];
256     unsigned int i_blocks;
257
258     /* AES is a block cypher, round down the byte count */
259     i_blocks = i_bytes / 16;
260     i_bytes = i_blocks * 16;
261
262     /* Initialise the key */
263     memcpy( p_key, p_drms->p_key, 16 );
264
265     /* Unscramble */
266     while( i_blocks-- )
267     {
268         uint32_t p_tmp[ 4 ];
269
270         REVERSE( p_buffer, 4 );
271         DecryptAES( &p_drms->aes, p_tmp, p_buffer );
272         BlockXOR( p_tmp, p_key, p_tmp );
273
274         /* Use the previous scrambled data as the key for next block */
275         memcpy( p_key, p_buffer, 16 );
276
277         /* Copy unscrambled data back to the buffer */
278         memcpy( p_buffer, p_tmp, 16 );
279         REVERSE( p_buffer, 4 );
280
281         p_buffer += 4;
282     }
283 }
284
285 /*****************************************************************************
286  * drms_init: initialise a DRMS structure
287  *****************************************************************************
288  * Return values:
289  *  0: success
290  * -1: unimplemented
291  * -2: invalid argument
292  * -3: could not get system key
293  * -4: could not get SCI data
294  * -5: no user key found in SCI data
295  * -6: invalid user key
296  *****************************************************************************/
297 int drms_init( void *_p_drms, uint32_t i_type,
298                uint8_t *p_info, uint32_t i_len )
299 {
300     struct drms_s *p_drms = (struct drms_s *)_p_drms;
301     int i_ret = 0;
302
303     switch( i_type )
304     {
305         case FOURCC_user:
306             if( i_len < sizeof(p_drms->i_user) )
307             {
308                 i_ret = -2;
309                 break;
310             }
311
312             p_drms->i_user = U32_AT( p_info );
313             break;
314
315         case FOURCC_key:
316             if( i_len < sizeof(p_drms->i_key) )
317             {
318                 i_ret = -2;
319                 break;
320             }
321
322             p_drms->i_key = U32_AT( p_info );
323             break;
324
325         case FOURCC_iviv:
326             if( i_len < sizeof(p_drms->p_key) )
327             {
328                 i_ret = -2;
329                 break;
330             }
331
332             memcpy( p_drms->p_iviv, p_info, 16 );
333             break;
334
335         case FOURCC_name:
336             p_drms->p_name = (uint8_t*) strdup( (char *)p_info );
337
338             if( p_drms->p_name == NULL )
339             {
340                 i_ret = -2;
341             }
342             break;
343
344         case FOURCC_priv:
345         {
346             uint32_t p_priv[ 64 ];
347             struct md5_s md5;
348
349             if( i_len < 64 )
350             {
351                 i_ret = -2;
352                 break;
353             }
354
355             InitMD5( &md5 );
356             AddMD5( &md5, p_drms->p_name, strlen( (char *)p_drms->p_name ) );
357             AddMD5( &md5, p_drms->p_iviv, 16 );
358             EndMD5( &md5 );
359
360             if( p_drms->i_user == 0 && p_drms->i_key == 0 )
361             {
362                 static char const p_secret[] = "tr1-th3n.y00_by3";
363                 memcpy( p_drms->p_key, p_secret, 16 );
364                 REVERSE( p_drms->p_key, 4 );
365             }
366             else
367             {
368                 i_ret = GetUserKey( p_drms, p_drms->p_key );
369                 if( i_ret )
370                 {
371                     break;
372                 }
373             }
374
375             InitAES( &p_drms->aes, p_drms->p_key );
376
377             memcpy( p_priv, p_info, 64 );
378             memcpy( p_drms->p_key, md5.p_digest, 16 );
379             drms_decrypt( p_drms, p_priv, 64 );
380             REVERSE( p_priv, 64 );
381
382             if( p_priv[ 0 ] != 0x6e757469 ) /* itun */
383             {
384                 i_ret = -6;
385                 break;
386             }
387
388             InitAES( &p_drms->aes, p_priv + 6 );
389             memcpy( p_drms->p_key, p_priv + 12, 16 );
390
391             free( (void *)p_drms->p_name );
392             p_drms->p_name = NULL;
393         }
394         break;
395     }
396
397     return i_ret;
398 }
399
400 /* The following functions are local */
401
402 /*****************************************************************************
403  * InitAES: initialise AES/Rijndael encryption/decryption tables
404  *****************************************************************************
405  * The Advanced Encryption Standard (AES) is described in RFC 3268
406  *****************************************************************************/
407 static void InitAES( struct aes_s *p_aes, uint32_t *p_key )
408 {
409     unsigned int i, t;
410     uint32_t i_key, i_seed;
411
412     memset( p_aes->pp_enc_keys[1], 0, 16 );
413     memcpy( p_aes->pp_enc_keys[0], p_key, 16 );
414
415     /* Generate the key tables */
416     i_seed = p_aes->pp_enc_keys[ 0 ][ 3 ];
417
418     for( i_key = 0; i_key < AES_KEY_COUNT; i_key++ )
419     {
420         uint32_t j;
421
422         i_seed = AES_ROR( i_seed, 8 );
423
424         j = p_aes_table[ i_key ];
425
426         j ^= p_aes_encrypt[ (i_seed >> 24) & 0xff ]
427               ^ AES_ROR( p_aes_encrypt[ (i_seed >> 16) & 0xff ], 8 )
428               ^ AES_ROR( p_aes_encrypt[ (i_seed >> 8) & 0xff ], 16 )
429               ^ AES_ROR( p_aes_encrypt[ i_seed & 0xff ], 24 );
430
431         j ^= p_aes->pp_enc_keys[ i_key ][ 0 ];
432         p_aes->pp_enc_keys[ i_key + 1 ][ 0 ] = j;
433         j ^= p_aes->pp_enc_keys[ i_key ][ 1 ];
434         p_aes->pp_enc_keys[ i_key + 1 ][ 1 ] = j;
435         j ^= p_aes->pp_enc_keys[ i_key ][ 2 ];
436         p_aes->pp_enc_keys[ i_key + 1 ][ 2 ] = j;
437         j ^= p_aes->pp_enc_keys[ i_key ][ 3 ];
438         p_aes->pp_enc_keys[ i_key + 1 ][ 3 ] = j;
439
440         i_seed = j;
441     }
442
443     memcpy( p_aes->pp_dec_keys[ 0 ],
444             p_aes->pp_enc_keys[ 0 ], 16 );
445
446     for( i = 1; i < AES_KEY_COUNT; i++ )
447     {
448         for( t = 0; t < 4; t++ )
449         {
450             uint32_t j, k, l, m, n;
451
452             j = p_aes->pp_enc_keys[ i ][ t ];
453
454             k = (((j >> 7) & 0x01010101) * 27) ^ ((j & 0xff7f7f7f) << 1);
455             l = (((k >> 7) & 0x01010101) * 27) ^ ((k & 0xff7f7f7f) << 1);
456             m = (((l >> 7) & 0x01010101) * 27) ^ ((l & 0xff7f7f7f) << 1);
457
458             j ^= m;
459
460             n = AES_ROR( l ^ j, 16 ) ^ AES_ROR( k ^ j, 8 ) ^ AES_ROR( j, 24 );
461
462             p_aes->pp_dec_keys[ i ][ t ] = k ^ l ^ m ^ n;
463         }
464     }
465 }
466
467 /*****************************************************************************
468  * DecryptAES: decrypt an AES/Rijndael 128 bit block
469  *****************************************************************************/
470 static void DecryptAES( struct aes_s *p_aes,
471                         uint32_t *p_dest, const uint32_t *p_src )
472 {
473     uint32_t p_wtxt[ 4 ]; /* Working cyphertext */
474     uint32_t p_tmp[ 4 ];
475     unsigned int i_round, t;
476
477     for( t = 0; t < 4; t++ )
478     {
479         /* FIXME: are there any endianness issues here? */
480         p_wtxt[ t ] = p_src[ t ] ^ p_aes->pp_enc_keys[ AES_KEY_COUNT ][ t ];
481     }
482
483     /* Rounds 0 - 8 */
484     for( i_round = 0; i_round < (AES_KEY_COUNT - 1); i_round++ )
485     {
486         for( t = 0; t < 4; t++ )
487         {
488             p_tmp[ t ] = AES_XOR_ROR( p_aes_itable, p_wtxt );
489         }
490
491         for( t = 0; t < 4; t++ )
492         {
493             p_wtxt[ t ] = p_tmp[ t ]
494                     ^ p_aes->pp_dec_keys[ (AES_KEY_COUNT - 1) - i_round ][ t ];
495         }
496     }
497
498     /* Final round (9) */
499     for( t = 0; t < 4; t++ )
500     {
501         p_dest[ t ] = AES_XOR_ROR( p_aes_decrypt, p_wtxt );
502         p_dest[ t ] ^= p_aes->pp_dec_keys[ 0 ][ t ];
503     }
504 }
505
506 #ifndef __LIBVLC__
507 /*****************************************************************************
508  * InitMD5: initialise an MD5 message
509  *****************************************************************************
510  * The MD5 message-digest algorithm is described in RFC 1321
511  *****************************************************************************/
512 static void InitMD5( struct md5_s *p_md5 )
513 {
514     p_md5->p_digest[ 0 ] = 0x67452301;
515     p_md5->p_digest[ 1 ] = 0xefcdab89;
516     p_md5->p_digest[ 2 ] = 0x98badcfe;
517     p_md5->p_digest[ 3 ] = 0x10325476;
518
519     memset( p_md5->p_data, 0, 64 );
520     p_md5->i_bits = 0;
521 }
522
523 /*****************************************************************************
524  * AddMD5: add i_len bytes to an MD5 message
525  *****************************************************************************/
526 static void AddMD5( struct md5_s *p_md5, const uint8_t *p_src, uint32_t i_len )
527 {
528     unsigned int i_current; /* Current bytes in the spare buffer */
529     unsigned int i_offset = 0;
530
531     i_current = (p_md5->i_bits / 8) & 63;
532
533     p_md5->i_bits += 8 * i_len;
534
535     /* If we can complete our spare buffer to 64 bytes, do it and add the
536      * resulting buffer to the MD5 message */
537     if( i_len >= (64 - i_current) )
538     {
539         memcpy( ((uint8_t *)p_md5->p_data) + i_current, p_src,
540                 (64 - i_current) );
541         Digest( p_md5, p_md5->p_data );
542
543         i_offset += (64 - i_current);
544         i_len -= (64 - i_current);
545         i_current = 0;
546     }
547
548     /* Add as many entire 64 bytes blocks as we can to the MD5 message */
549     while( i_len >= 64 )
550     {
551         uint32_t p_tmp[ 16 ];
552         memcpy( p_tmp, p_src + i_offset, 64 );
553         Digest( p_md5, p_tmp );
554         i_offset += 64;
555         i_len -= 64;
556     }
557
558     /* Copy our remaining data to the message's spare buffer */
559     memcpy( ((uint8_t *)p_md5->p_data) + i_current, p_src + i_offset, i_len );
560 }
561
562 /*****************************************************************************
563  * EndMD5: finish an MD5 message
564  *****************************************************************************
565  * This function adds adequate padding to the end of the message, and appends
566  * the bit count so that we end at a block boundary.
567  *****************************************************************************/
568 static void EndMD5( struct md5_s *p_md5 )
569 {
570     unsigned int i_current;
571
572     i_current = (p_md5->i_bits / 8) & 63;
573
574     /* Append 0x80 to our buffer. No boundary check because the temporary
575      * buffer cannot be full, otherwise AddMD5 would have emptied it. */
576     ((uint8_t *)p_md5->p_data)[ i_current++ ] = 0x80;
577
578     /* If less than 8 bytes are available at the end of the block, complete
579      * this 64 bytes block with zeros and add it to the message. We'll add
580      * our length at the end of the next block. */
581     if( i_current > 56 )
582     {
583         memset( ((uint8_t *)p_md5->p_data) + i_current, 0, (64 - i_current) );
584         Digest( p_md5, p_md5->p_data );
585         i_current = 0;
586     }
587
588     /* Fill the unused space in our last block with zeroes and put the
589      * message length at the end. */
590     memset( ((uint8_t *)p_md5->p_data) + i_current, 0, (56 - i_current) );
591     p_md5->p_data[ 14 ] = p_md5->i_bits & 0xffffffff;
592     p_md5->p_data[ 15 ] = (p_md5->i_bits >> 32);
593     REVERSE( &p_md5->p_data[ 14 ], 2 );
594
595     Digest( p_md5, p_md5->p_data );
596 }
597
598 #define F1( x, y, z ) ((z) ^ ((x) & ((y) ^ (z))))
599 #define F2( x, y, z ) F1((z), (x), (y))
600 #define F3( x, y, z ) ((x) ^ (y) ^ (z))
601 #define F4( x, y, z ) ((y) ^ ((x) | ~(z)))
602
603 #define MD5_DO( f, w, x, y, z, data, s ) \
604     ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
605
606 /*****************************************************************************
607  * Digest: update the MD5 digest with 64 bytes of data
608  *****************************************************************************/
609 static void Digest( struct md5_s *p_md5, uint32_t *p_input )
610 {
611     uint32_t a, b, c, d;
612
613     REVERSE( p_input, 16 );
614
615     a = p_md5->p_digest[ 0 ];
616     b = p_md5->p_digest[ 1 ];
617     c = p_md5->p_digest[ 2 ];
618     d = p_md5->p_digest[ 3 ];
619
620     MD5_DO( F1, a, b, c, d, p_input[  0 ] + 0xd76aa478,  7 );
621     MD5_DO( F1, d, a, b, c, p_input[  1 ] + 0xe8c7b756, 12 );
622     MD5_DO( F1, c, d, a, b, p_input[  2 ] + 0x242070db, 17 );
623     MD5_DO( F1, b, c, d, a, p_input[  3 ] + 0xc1bdceee, 22 );
624     MD5_DO( F1, a, b, c, d, p_input[  4 ] + 0xf57c0faf,  7 );
625     MD5_DO( F1, d, a, b, c, p_input[  5 ] + 0x4787c62a, 12 );
626     MD5_DO( F1, c, d, a, b, p_input[  6 ] + 0xa8304613, 17 );
627     MD5_DO( F1, b, c, d, a, p_input[  7 ] + 0xfd469501, 22 );
628     MD5_DO( F1, a, b, c, d, p_input[  8 ] + 0x698098d8,  7 );
629     MD5_DO( F1, d, a, b, c, p_input[  9 ] + 0x8b44f7af, 12 );
630     MD5_DO( F1, c, d, a, b, p_input[ 10 ] + 0xffff5bb1, 17 );
631     MD5_DO( F1, b, c, d, a, p_input[ 11 ] + 0x895cd7be, 22 );
632     MD5_DO( F1, a, b, c, d, p_input[ 12 ] + 0x6b901122,  7 );
633     MD5_DO( F1, d, a, b, c, p_input[ 13 ] + 0xfd987193, 12 );
634     MD5_DO( F1, c, d, a, b, p_input[ 14 ] + 0xa679438e, 17 );
635     MD5_DO( F1, b, c, d, a, p_input[ 15 ] + 0x49b40821, 22 );
636
637     MD5_DO( F2, a, b, c, d, p_input[  1 ] + 0xf61e2562,  5 );
638     MD5_DO( F2, d, a, b, c, p_input[  6 ] + 0xc040b340,  9 );
639     MD5_DO( F2, c, d, a, b, p_input[ 11 ] + 0x265e5a51, 14 );
640     MD5_DO( F2, b, c, d, a, p_input[  0 ] + 0xe9b6c7aa, 20 );
641     MD5_DO( F2, a, b, c, d, p_input[  5 ] + 0xd62f105d,  5 );
642     MD5_DO( F2, d, a, b, c, p_input[ 10 ] + 0x02441453,  9 );
643     MD5_DO( F2, c, d, a, b, p_input[ 15 ] + 0xd8a1e681, 14 );
644     MD5_DO( F2, b, c, d, a, p_input[  4 ] + 0xe7d3fbc8, 20 );
645     MD5_DO( F2, a, b, c, d, p_input[  9 ] + 0x21e1cde6,  5 );
646     MD5_DO( F2, d, a, b, c, p_input[ 14 ] + 0xc33707d6,  9 );
647     MD5_DO( F2, c, d, a, b, p_input[  3 ] + 0xf4d50d87, 14 );
648     MD5_DO( F2, b, c, d, a, p_input[  8 ] + 0x455a14ed, 20 );
649     MD5_DO( F2, a, b, c, d, p_input[ 13 ] + 0xa9e3e905,  5 );
650     MD5_DO( F2, d, a, b, c, p_input[  2 ] + 0xfcefa3f8,  9 );
651     MD5_DO( F2, c, d, a, b, p_input[  7 ] + 0x676f02d9, 14 );
652     MD5_DO( F2, b, c, d, a, p_input[ 12 ] + 0x8d2a4c8a, 20 );
653
654     MD5_DO( F3, a, b, c, d, p_input[  5 ] + 0xfffa3942,  4 );
655     MD5_DO( F3, d, a, b, c, p_input[  8 ] + 0x8771f681, 11 );
656     MD5_DO( F3, c, d, a, b, p_input[ 11 ] + 0x6d9d6122, 16 );
657     MD5_DO( F3, b, c, d, a, p_input[ 14 ] + 0xfde5380c, 23 );
658     MD5_DO( F3, a, b, c, d, p_input[  1 ] + 0xa4beea44,  4 );
659     MD5_DO( F3, d, a, b, c, p_input[  4 ] + 0x4bdecfa9, 11 );
660     MD5_DO( F3, c, d, a, b, p_input[  7 ] + 0xf6bb4b60, 16 );
661     MD5_DO( F3, b, c, d, a, p_input[ 10 ] + 0xbebfbc70, 23 );
662     MD5_DO( F3, a, b, c, d, p_input[ 13 ] + 0x289b7ec6,  4 );
663     MD5_DO( F3, d, a, b, c, p_input[  0 ] + 0xeaa127fa, 11 );
664     MD5_DO( F3, c, d, a, b, p_input[  3 ] + 0xd4ef3085, 16 );
665     MD5_DO( F3, b, c, d, a, p_input[  6 ] + 0x04881d05, 23 );
666     MD5_DO( F3, a, b, c, d, p_input[  9 ] + 0xd9d4d039,  4 );
667     MD5_DO( F3, d, a, b, c, p_input[ 12 ] + 0xe6db99e5, 11 );
668     MD5_DO( F3, c, d, a, b, p_input[ 15 ] + 0x1fa27cf8, 16 );
669     MD5_DO( F3, b, c, d, a, p_input[  2 ] + 0xc4ac5665, 23 );
670
671     MD5_DO( F4, a, b, c, d, p_input[  0 ] + 0xf4292244,  6 );
672     MD5_DO( F4, d, a, b, c, p_input[  7 ] + 0x432aff97, 10 );
673     MD5_DO( F4, c, d, a, b, p_input[ 14 ] + 0xab9423a7, 15 );
674     MD5_DO( F4, b, c, d, a, p_input[  5 ] + 0xfc93a039, 21 );
675     MD5_DO( F4, a, b, c, d, p_input[ 12 ] + 0x655b59c3,  6 );
676     MD5_DO( F4, d, a, b, c, p_input[  3 ] + 0x8f0ccc92, 10 );
677     MD5_DO( F4, c, d, a, b, p_input[ 10 ] + 0xffeff47d, 15 );
678     MD5_DO( F4, b, c, d, a, p_input[  1 ] + 0x85845dd1, 21 );
679     MD5_DO( F4, a, b, c, d, p_input[  8 ] + 0x6fa87e4f,  6 );
680     MD5_DO( F4, d, a, b, c, p_input[ 15 ] + 0xfe2ce6e0, 10 );
681     MD5_DO( F4, c, d, a, b, p_input[  6 ] + 0xa3014314, 15 );
682     MD5_DO( F4, b, c, d, a, p_input[ 13 ] + 0x4e0811a1, 21 );
683     MD5_DO( F4, a, b, c, d, p_input[  4 ] + 0xf7537e82,  6 );
684     MD5_DO( F4, d, a, b, c, p_input[ 11 ] + 0xbd3af235, 10 );
685     MD5_DO( F4, c, d, a, b, p_input[  2 ] + 0x2ad7d2bb, 15 );
686     MD5_DO( F4, b, c, d, a, p_input[  9 ] + 0xeb86d391, 21 );
687
688     p_md5->p_digest[ 0 ] += a;
689     p_md5->p_digest[ 1 ] += b;
690     p_md5->p_digest[ 2 ] += c;
691     p_md5->p_digest[ 3 ] += d;
692 }
693 #endif
694
695 /*****************************************************************************
696  * InitShuffle: initialise a shuffle structure
697  *****************************************************************************
698  * This function initialises tables in the p_shuffle structure that will be
699  * used later by DoShuffle. The only external parameter is p_sys_key.
700  *****************************************************************************/
701 static void InitShuffle( struct shuffle_s *p_shuffle, uint32_t *p_sys_key,
702                          uint32_t i_version )
703 {
704     char p_secret1[] = "Tv!*";
705     static char const p_secret2[] = "____v8rhvsaAvOKM____FfUH%798=[;."
706                                     "____f8677680a634____ba87fnOIf)(*";
707     unsigned int i;
708
709     p_shuffle->i_version = i_version;
710
711     /* Fill p_commands using the key and a secret seed */
712     for( i = 0; i < 20; i++ )
713     {
714         struct md5_s md5;
715         int32_t i_hash;
716
717         InitMD5( &md5 );
718         AddMD5( &md5, (const uint8_t *)p_sys_key, 16 );
719         AddMD5( &md5, (const uint8_t *)p_secret1, 4 );
720         EndMD5( &md5 );
721
722         p_secret1[ 3 ]++;
723
724         REVERSE( md5.p_digest, 1 );
725         i_hash = ((int32_t)U32_AT(md5.p_digest)) % 1024;
726
727         p_shuffle->p_commands[ i ] = i_hash < 0 ? i_hash * -1 : i_hash;
728     }
729
730     /* Fill p_bordel with completely meaningless initial values. */
731     memcpy( p_shuffle->p_bordel, p_secret2, 64 );
732     for( i = 0; i < 4; i++ )
733     {
734         p_shuffle->p_bordel[ 4 * i ] = U32_AT(p_sys_key + i);
735         REVERSE( p_shuffle->p_bordel + 4 * i + 1, 3 );
736     }
737 }
738
739 /*****************************************************************************
740  * DoShuffle: shuffle buffer
741  *****************************************************************************
742  * This is so ugly and uses so many MD5 checksums that it is most certainly
743  * one-way, though why it needs to be so complicated is beyond me.
744  *****************************************************************************/
745 static void DoShuffle( struct shuffle_s *p_shuffle,
746                        uint32_t *p_buffer, uint32_t i_size )
747 {
748     struct md5_s md5;
749     uint32_t p_big_bordel[ 16 ];
750     uint32_t *p_bordel = p_shuffle->p_bordel;
751     unsigned int i;
752
753     static uint32_t i_secret = 0;
754
755     static uint32_t p_secret3[] =
756     {
757         0xAAAAAAAA, 0x01757700, 0x00554580, 0x01724500, 0x00424580,
758         0x01427700, 0x00000080, 0xC1D59D01, 0x80144981, 0x815C8901,
759         0x80544981, 0x81D45D01, 0x00000080, 0x81A3BB03, 0x00A2AA82,
760         0x01A3BB03, 0x0022A282, 0x813BA202, 0x00000080, 0x6D575737,
761         0x4A5275A5, 0x6D525725, 0x4A5254A5, 0x6B725437, 0x00000080,
762         0xD5DDB938, 0x5455A092, 0x5D95A013, 0x4415A192, 0xC5DD393A,
763         0x00000080, 0x55555555
764     };
765
766     static char p_secret4[] =
767         "pbclevtug (p) Nccyr Pbzchgre, Vap.  Nyy Evtugf Erfreirq.";
768
769     if( i_secret == 0 )
770     {
771         REVERSE( p_secret3, sizeof(p_secret3)/sizeof(p_secret3[ 0 ]) );
772         for( ; p_secret4[ i_secret ] != '\0'; i_secret++ )
773         {
774 #define ROT13(c) (((c)>='A'&&(c)<='Z')?(((c)-'A'+13)%26)+'A':\
775                   ((c)>='a'&&(c)<='z')?(((c)-'a'+13)%26)+'a':c)
776             p_secret4[ i_secret ] = ROT13(p_secret4[ i_secret ]);
777         }
778         i_secret++; /* include zero terminator */
779     }
780
781     /* Using the MD5 hash of a memory block is probably not one-way enough
782      * for the iTunes people. This function randomises p_bordel depending on
783      * the values in p_commands to make things even more messy in p_bordel. */
784     for( i = 0; i < 20; i++ )
785     {
786         uint8_t i_command, i_index;
787
788         if( !p_shuffle->p_commands[ i ] )
789         {
790             continue;
791         }
792
793         i_command = (p_shuffle->p_commands[ i ] & 0x300) >> 8;
794         i_index = p_shuffle->p_commands[ i ] & 0xff;
795
796         switch( i_command )
797         {
798         case 0x3:
799             p_bordel[ i_index & 0xf ] = p_bordel[ i_index >> 4 ]
800                                       + p_bordel[ ((i_index + 0x10) >> 4) & 0xf ];
801             break;
802         case 0x2:
803             p_bordel[ i_index >> 4 ] ^= p_shuffle_xor[ 0xff - i_index ];
804             break;
805         case 0x1:
806             p_bordel[ i_index >> 4 ] -= p_shuffle_sub[ 0xff - i_index ];
807             break;
808         default:
809             p_bordel[ i_index >> 4 ] += p_shuffle_add[ 0xff - i_index ];
810             break;
811         }
812     }
813
814     if( p_shuffle->i_version == 0x01000300 )
815     {
816         DoExtShuffle( p_bordel );
817     }
818
819     /* Convert our newly randomised p_bordel to big endianness and take
820      * its MD5 hash. */
821     InitMD5( &md5 );
822     for( i = 0; i < 16; i++ )
823     {
824         p_big_bordel[ i ] = U32_AT(p_bordel + i);
825     }
826     AddMD5( &md5, (const uint8_t *)p_big_bordel, 64 );
827     if( p_shuffle->i_version == 0x01000300 )
828     {
829         AddMD5( &md5, (const uint8_t *)p_secret3, sizeof(p_secret3) );
830         AddMD5( &md5, (const uint8_t *)p_secret4, i_secret );
831     }
832     EndMD5( &md5 );
833
834     /* XOR our buffer with the computed checksum */
835     for( i = 0; i < i_size; i++ )
836     {
837         p_buffer[ i ] ^= md5.p_digest[ i ];
838     }
839 }
840
841 /*****************************************************************************
842  * DoExtShuffle: extended shuffle
843  *****************************************************************************
844  * This is even uglier.
845  *****************************************************************************/
846 static void DoExtShuffle( uint32_t * p_bordel )
847 {
848     uint32_t i_ret;
849
850     i_ret = FirstPass( p_bordel );
851
852     SecondPass( p_bordel, i_ret );
853
854     ThirdPass( p_bordel );
855
856     FourthPass( p_bordel );
857 }
858
859 static uint32_t FirstPass( uint32_t * p_bordel )
860 {
861     uint32_t i, i_cmd, i_ret = 5;
862
863     TinyShuffle1( p_bordel );
864
865     for( ; ; )
866     {
867         for( ; ; )
868         {
869             p_bordel[ 1 ] += 0x10000000;
870             p_bordel[ 3 ] += 0x12777;
871
872             if( (p_bordel[ 10 ] & 1) && i_ret )
873             {
874                 i_ret--;
875                 p_bordel[ 1 ] -= p_bordel[ 2 ];
876                 p_bordel[ 11 ] += p_bordel[ 12 ];
877                 break;
878             }
879
880             if( (p_bordel[ 1 ] + p_bordel[ 2 ]) >= 0x7D0 )
881             {
882                 switch( ((p_bordel[ 3 ] ^ 0x567F) >> 2) & 7 )
883                 {
884                     case 0:
885                         for( i = 0; i < 3; i++ )
886                         {
887                             if( p_bordel[ i + 10 ] > 0x4E20 )
888                             {
889                                 p_bordel[ i + 1 ] += p_bordel[ i + 2 ];
890                             }
891                         }
892                         break;
893                     case 4:
894                         p_bordel[ 1 ] -= p_bordel[ 2 ];
895                         /* no break */
896                     case 3:
897                         p_bordel[ 11 ] += p_bordel[ 12 ];
898                         break;
899                     case 6:
900                         p_bordel[ 3 ] ^= p_bordel[ 4 ];
901                         /* no break */
902                     case 8:
903                         p_bordel[ 13 ] &= p_bordel[ 14 ];
904                         /* no break */
905                     case 1:
906                         p_bordel[ 0 ] |= p_bordel[ 1 ];
907                         if( i_ret )
908                         {
909                             return i_ret;
910                         }
911                         break;
912                 }
913
914                 break;
915             }
916         }
917
918         for( i = 0, i_cmd = 0; i < 16; i++ )
919         {
920             if( p_bordel[ i ] < p_bordel[ i_cmd ] )
921             {
922                 i_cmd = i;
923             }
924         }
925
926         if( i_ret && i_cmd != 5 )
927         {
928             i_ret--;
929         }
930         else
931         {
932             if( i_cmd == 5 )
933             {
934                 p_bordel[ 8 ] &= p_bordel[ 6 ] >> 1;
935                 p_bordel[ 3 ] <<= 1;
936             }
937
938             for( i = 0; i < 3; i++ )
939             {
940                 p_bordel[ 11 ] += 1;
941                 if( p_bordel[ 11 ] & 5 )
942                 {
943                     p_bordel[ 8 ] += p_bordel[ 9 ];
944                 }
945                 else if( i_ret )
946                 {
947                     i_ret--;
948                     i_cmd = 3;
949                     goto break2;
950                 }
951             }
952
953             i_cmd = (p_bordel[ 15 ] + 0x93) >> 3;
954             if( p_bordel[ 15 ] & 0x100 )
955             {
956                 i_cmd ^= 0xDEAD;
957             }
958         }
959
960         switch( i_cmd & 3 )
961         {
962             case 0:
963                 while( p_bordel[ 11 ] & 1 )
964                 {
965                     p_bordel[ 11 ] >>= 1;
966                     p_bordel[ 12 ] += 1;
967                 }
968                 /* no break */
969             case 2:
970                 p_bordel[ 14 ] -= 0x19FE;
971                 break;
972             case 3:
973                 if( i_ret )
974                 {
975                     i_ret--;
976                     p_bordel[ 5 ] += 5;
977                     continue;
978                 }
979                 break;
980         }
981
982         i_cmd = ((p_bordel[ 3 ] + p_bordel[ 4 ] + 10) >> 1) - p_bordel[ 4 ];
983         break;
984     }
985 break2:
986
987     switch( i_cmd & 3 )
988     {
989         case 0:
990             p_bordel[ 14 ] >>= 1;
991             break;
992         case 1:
993             p_bordel[ 5 ] <<= 2;
994             break;
995         case 2:
996             p_bordel[ 12 ] |= 5;
997             break;
998         case 3:
999             p_bordel[ 15 ] &= 0x55;
1000             if( i_ret )
1001             {
1002                 p_bordel[ 2 ] &= 0xB62FC;
1003                 return i_ret;
1004             }
1005             break;
1006     }
1007
1008     TinyShuffle2( p_bordel );
1009
1010     return i_ret;
1011 }
1012
1013 static void SecondPass( uint32_t * p_bordel, uint32_t i_tmp )
1014 {
1015     uint32_t i, i_cmd, i_jc = 5;
1016
1017     TinyShuffle3( p_bordel );
1018
1019     for( i = 0, i_cmd = 0; i < 16; i++ )
1020     {
1021         if( p_bordel[ i ] > p_bordel[ i_cmd ] )
1022         {
1023             i_cmd = i;
1024         }
1025     }
1026
1027     switch( i_cmd )
1028     {
1029         case 0:
1030             if( p_bordel[ 1 ] < p_bordel[ 8 ] )
1031             {
1032                 p_bordel[ 5 ] += 1;
1033             }
1034             break;
1035         case 4:
1036             if( (p_bordel[ 9 ] & 0x7777) == 0x3333 )
1037             {
1038                 p_bordel[ 5 ] -= 1;
1039             }
1040             else
1041             {
1042                 i_jc--;
1043                 if( p_bordel[ 1 ] < p_bordel[ 8 ] )
1044                 {
1045                     p_bordel[ 5 ] += 1;
1046                 }
1047                 break;
1048             }
1049             /* no break */
1050         case 7:
1051             p_bordel[ 2 ] -= 1;
1052             p_bordel[ 1 ] -= p_bordel[ 5 ];
1053             for( i = 0; i < 3; i++ )
1054             {
1055                 switch( p_bordel[ 1 ] & 3 )
1056                 {
1057                     case 0:
1058                         p_bordel[ 1 ] += 1;
1059                         /* no break */
1060                     case 1:
1061                         p_bordel[ 3 ] -= 8;
1062                         break;
1063                     case 2:
1064                         p_bordel[ 13 ] &= 0xFEFEFEF7;
1065                         break;
1066                     case 3:
1067                         p_bordel[ 8 ] |= 0x80080011;
1068                         break;
1069                 }
1070             }
1071             return;
1072         case 10:
1073             p_bordel[ 4 ] -= 1;
1074             p_bordel[ 5 ] += 1;
1075             p_bordel[ 6 ] -= 1;
1076             p_bordel[ 7 ] += 1;
1077             break;
1078         default:
1079             p_bordel[ 15 ] ^= 0x18547EFF;
1080             break;
1081     }
1082
1083     for( i = 3; i--; )
1084     {
1085         switch( ( p_bordel[ 12 ] + p_bordel[ 13 ] + p_bordel[ 6 ] ) % 5 )
1086         {
1087             case 0:
1088                 p_bordel[ 12 ] -= 1;
1089                 /* no break */
1090             case 1:
1091                 p_bordel[ 12 ] -= 1;
1092                 p_bordel[ 13 ] += 1;
1093                 break;
1094             case 2:
1095                 p_bordel[ 13 ] += 4;
1096                 /* no break */
1097             case 3:
1098                 p_bordel[ 12 ] -= 1;
1099                 break;
1100             case 4:
1101                 i_jc--;
1102                 p_bordel[ 5 ] += 1;
1103                 p_bordel[ 6 ] -= 1;
1104                 p_bordel[ 7 ] += 1;
1105                 i = 3; /* Restart the whole loop */
1106                 break;
1107         }
1108     }
1109
1110     TinyShuffle4( p_bordel );
1111
1112     for( ; ; )
1113     {
1114         TinyShuffle5( p_bordel );
1115
1116         switch( ( p_bordel[ 2 ] * 2 + 15 ) % 5 )
1117         {
1118             case 0:
1119                 if( ( p_bordel[ 3 ] + i_tmp ) <=
1120                     ( p_bordel[ 1 ] + p_bordel[ 15 ] ) )
1121                 {
1122                     p_bordel[ 3 ] += 1;
1123                 }
1124                 break;
1125             case 4:
1126                 p_bordel[ 10 ] -= 0x13;
1127                 break;
1128             case 3:
1129                 p_bordel[ 5 ] >>= 2;
1130                 break;
1131         }
1132
1133         if( !( p_bordel[ 2 ] & 1 ) || i_jc == 0 )
1134         {
1135             break;
1136         }
1137
1138         i_jc--;
1139         p_bordel[ 2 ] += 0x13;
1140         p_bordel[ 12 ] += 1;
1141     }
1142
1143     p_bordel[ 2 ] &= 0x10076000;
1144 }
1145
1146 static void ThirdPass( uint32_t * p_bordel )
1147 {
1148     uint32_t i_cmd;
1149
1150     i_cmd = ((p_bordel[ 7 ] + p_bordel[ 14 ] + 10) >> 1) - p_bordel[ 14 ];
1151     i_cmd = i_cmd % 10;
1152
1153     switch( i_cmd )
1154     {
1155         case 0:
1156             p_bordel[ 1 ] <<= 1;
1157             p_bordel[ 2 ] <<= 2;
1158             p_bordel[ 3 ] <<= 3;
1159             break;
1160         case 6:
1161             p_bordel[ i_cmd + 3 ] &= 0x5EDE36B;
1162             p_bordel[ 5 ] += p_bordel[ 8 ];
1163             p_bordel[ 4 ] += p_bordel[ 7 ];
1164             p_bordel[ 3 ] += p_bordel[ 6 ];
1165             p_bordel[ 2 ] += p_bordel[ 5 ];
1166             /* no break */
1167         case 2:
1168             p_bordel[ 1 ] += p_bordel[ 4 ];
1169             p_bordel[ 0 ] += p_bordel[ 3 ];
1170             TinyShuffle6( p_bordel );
1171             return; /* jc = 4 */
1172         case 3:
1173             if( (p_bordel[ 11 ] & p_bordel[ 2 ]) > 0x211B )
1174             {
1175                 p_bordel[ 6 ] += 1;
1176             }
1177             break;
1178         case 4:
1179             p_bordel[ 7 ] += 1;
1180             /* no break */
1181         case 5:
1182             p_bordel[ 9 ] ^= p_bordel[ 2 ];
1183             break;
1184         case 7:
1185             p_bordel[ 2 ] ^= (p_bordel[ 1 ] & p_bordel[ 13 ]);
1186             break;
1187         case 8:
1188             p_bordel[ 0 ] -= p_bordel[ 11 ] & p_bordel[ 15 ];
1189             return; /* jc = 4 */
1190         case 9:
1191             p_bordel[ 6 ] >>= (p_bordel[ 14 ] & 3);
1192             break;
1193     }
1194
1195     SWAP( p_bordel[ 0 ], p_bordel[ 10 ] );
1196
1197     TinyShuffle6( p_bordel );
1198
1199     return; /* jc = 5 */
1200 }
1201
1202 static void FourthPass( uint32_t * p_bordel )
1203 {
1204     uint32_t i, j;
1205
1206     TinyShuffle7( p_bordel );
1207
1208     switch( p_bordel[ 5 ] % 5)
1209     {
1210         case 0:
1211             p_bordel[ 0 ] += 1;
1212             break;
1213         case 2:
1214             p_bordel[ 11 ] ^= (p_bordel[ 3 ] + p_bordel[ 6 ] + p_bordel[ 8 ]);
1215             break;
1216         case 3:
1217             for( i = 4; i < 15 && (p_bordel[ i ] & 5) == 0; i++ )
1218             {
1219                 SWAP( p_bordel[ i ], p_bordel[ 15 - i ] );
1220             }
1221             break;
1222         case 4:
1223             p_bordel[ 12 ] -= 1;
1224             p_bordel[ 13 ] += 1;
1225             p_bordel[ 2 ] -= 0x64;
1226             p_bordel[ 3 ] += 0x64;
1227             TinyShuffle8( p_bordel );
1228             return;
1229     }
1230
1231     for( i = 0, j = 0; i < 16; i++ )
1232     {
1233         if( p_bordel[ i ] > p_bordel[ j ] )
1234         {
1235             j = i;
1236         }
1237     }
1238
1239     switch( p_bordel[ j ] % 100 )
1240     {
1241         case 0:
1242             SWAP( p_bordel[ 0 ], p_bordel[ j ] );
1243             break;
1244         case 8:
1245             p_bordel[ 1 ] >>= 1;
1246             p_bordel[ 2 ] <<= 1;
1247             p_bordel[ 14 ] >>= 3;
1248             p_bordel[ 15 ] <<= 4;
1249             break;
1250         case 57:
1251             p_bordel[ j ] += p_bordel[ 13 ];
1252             break;
1253         case 76:
1254             p_bordel[ 1 ] += 0x20E;
1255             p_bordel[ 5 ] += 0x223D;
1256             p_bordel[ 13 ] -= 0x576;
1257             p_bordel[ 15 ] += 0x576;
1258             return;
1259         case 91:
1260             p_bordel[ 2 ] -= 0x64;
1261             p_bordel[ 3 ] += 0x64;
1262             p_bordel[ 12 ] -= 1;
1263             p_bordel[ 13 ] += 1;
1264             break;
1265         case 99:
1266             p_bordel[ 0 ] += 1;
1267             p_bordel[ j ] += p_bordel[ 13 ];
1268             break;
1269     }
1270
1271     TinyShuffle8( p_bordel );
1272 }
1273
1274 /*****************************************************************************
1275  * TinyShuffle[12345678]: tiny shuffle subroutines
1276  *****************************************************************************
1277  * These standalone functions are little helpers for the shuffling process.
1278  *****************************************************************************/
1279 static void TinyShuffle1( uint32_t * p_bordel )
1280 {
1281     uint32_t i_cmd = (p_bordel[ 5 ] + 10) >> 2;
1282
1283     if( p_bordel[ 5 ] > 0x7D0 )
1284     {
1285         i_cmd -= 0x305;
1286     }
1287
1288     switch( i_cmd & 3 )
1289     {
1290         case 0:
1291             p_bordel[ 5 ] += 5;
1292             break;
1293         case 1:
1294             p_bordel[ 4 ] -= 1;
1295             break;
1296         case 2:
1297             if( p_bordel[ 4 ] & 5 )
1298             {
1299                 p_bordel[ 1 ] ^= 0x4D;
1300             }
1301             /* no break */
1302         case 3:
1303             p_bordel[ 12 ] += 5;
1304             break;
1305     }
1306 }
1307
1308 static void TinyShuffle2( uint32_t * p_bordel )
1309 {
1310     uint32_t i, j;
1311
1312     for( i = 0, j = 0; i < 16; i++ )
1313     {
1314         if( (p_bordel[ i ] & 0x777) > (p_bordel[ j ] & 0x777) )
1315         {
1316             j = i;
1317         }
1318     }
1319
1320     if( j > 5 )
1321     {
1322         for( ; j < 15; j++ )
1323         {
1324             p_bordel[ j ] += p_bordel[ j + 1 ];
1325         }
1326     }
1327     else
1328     {
1329         p_bordel[ 2 ] &= 0xB62FC;
1330     }
1331 }
1332
1333 static void TinyShuffle3( uint32_t * p_bordel )
1334 {
1335     uint32_t i_cmd = p_bordel[ 6 ] + 0x194B;
1336
1337     if( p_bordel[ 6 ] > 0x2710 )
1338     {
1339         i_cmd >>= 1;
1340     }
1341
1342     switch( i_cmd & 3 )
1343     {
1344         case 1:
1345             p_bordel[ 3 ] += 0x19FE;
1346             break;
1347         case 2:
1348             p_bordel[ 7 ] -= p_bordel[ 3 ] >> 2;
1349             /* no break */
1350         case 0:
1351             p_bordel[ 5 ] ^= 0x248A;
1352             break;
1353     }
1354 }
1355
1356 static void TinyShuffle4( uint32_t * p_bordel )
1357 {
1358     uint32_t i, j;
1359
1360     for( i = 0, j = 0; i < 16; i++ )
1361     {
1362         if( p_bordel[ i ] < p_bordel[ j ] )
1363         {
1364             j = i;
1365         }
1366     }
1367
1368     if( (p_bordel[ j ] % (j + 1)) > 10 )
1369     {
1370         p_bordel[ 1 ] -= 1;
1371         p_bordel[ 2 ] += 0x13;
1372         p_bordel[ 12 ] += 1;
1373     }
1374 }
1375
1376 static void TinyShuffle5( uint32_t * p_bordel )
1377 {
1378     uint32_t i;
1379
1380     p_bordel[ 2 ] &= 0x7F3F;
1381
1382     for( i = 0; i < 5; i++ )
1383     {
1384         switch( ( p_bordel[ 2 ] + 10 + i ) % 5 )
1385         {
1386             case 0:
1387                 p_bordel[ 12 ] &= p_bordel[ 2 ];
1388                 /* no break */
1389             case 1:
1390                 p_bordel[ 3 ] ^= p_bordel[ 15 ];
1391                 break;
1392             case 2:
1393                 p_bordel[ 15 ] += 0x576;
1394                 /* no break */
1395             case 3:
1396                 p_bordel[ 7 ] -= 0x2D;
1397                 /* no break */
1398             case 4:
1399                 p_bordel[ 1 ] <<= 1;
1400                 break;
1401         }
1402     }
1403 }
1404
1405 static void TinyShuffle6( uint32_t * p_bordel )
1406 {
1407     uint32_t i, j;
1408
1409     for( i = 0; i < 8; i++ )
1410     {
1411         j = p_bordel[ 3 ] & 0x7514 ? 5 : 7;
1412         SWAP( p_bordel[ i ], p_bordel[ i + j ] );
1413     }
1414 }
1415
1416 static void TinyShuffle7( uint32_t * p_bordel )
1417 {
1418     uint32_t i;
1419
1420     i = (((p_bordel[ 9 ] + p_bordel[ 15 ] + 12) >> 2) - p_bordel[ 4 ]) & 7;
1421
1422     while( i-- )
1423     {
1424         SWAP( p_bordel[ i ], p_bordel[ i + 3 ] );
1425     }
1426
1427     SWAP( p_bordel[ 1 ], p_bordel[ 10 ] );
1428 }
1429
1430 static void TinyShuffle8( uint32_t * p_bordel )
1431 {
1432     uint32_t i;
1433
1434     i = (p_bordel[ 0 ] & p_bordel[ 6 ]) & 0xF;
1435
1436     switch( p_bordel[ i ] % 1000 )
1437     {
1438         case 7:
1439             if( (p_bordel[ i ] & 0x777) > (p_bordel[ 7 ] & 0x5555) )
1440             {
1441                 p_bordel[ i ] ^= p_bordel[ 5 ] & p_bordel[ 3 ];
1442             }
1443             break;
1444         case 19:
1445             p_bordel[ 15 ] &= 0x5555;
1446             break;
1447         case 93:
1448             p_bordel[ i ] ^= p_bordel[ 15 ];
1449             break;
1450         case 100:
1451             SWAP( p_bordel[ 0 ], p_bordel[ 3 ] );
1452             SWAP( p_bordel[ 1 ], p_bordel[ 6 ] );
1453             SWAP( p_bordel[ 3 ], p_bordel[ 6 ] );
1454             SWAP( p_bordel[ 4 ], p_bordel[ 9 ] );
1455             SWAP( p_bordel[ 5 ], p_bordel[ 8 ] );
1456             SWAP( p_bordel[ 6 ], p_bordel[ 7 ] );
1457             SWAP( p_bordel[ 13 ], p_bordel[ 14 ] );
1458             break;
1459         case 329:
1460             p_bordel[ i ] += p_bordel[ 1 ] ^ 0x80080011;
1461             p_bordel[ i ] += p_bordel[ 2 ] ^ 0xBEEFDEAD;
1462             p_bordel[ i ] += p_bordel[ 3 ] ^ 0x8765F444;
1463             p_bordel[ i ] += p_bordel[ 4 ] ^ 0x78145326;
1464             break;
1465         case 567:
1466             p_bordel[ 12 ] -= p_bordel[ i ];
1467             p_bordel[ 13 ] += p_bordel[ i ];
1468             break;
1469         case 612:
1470             p_bordel[ i ] += p_bordel[ 1 ];
1471             p_bordel[ i ] -= p_bordel[ 7 ];
1472             p_bordel[ i ] -= p_bordel[ 8 ];
1473             p_bordel[ i ] += p_bordel[ 9 ];
1474             p_bordel[ i ] += p_bordel[ 13 ];
1475             break;
1476         case 754:
1477             i = __MIN( i, 12 );
1478             p_bordel[ i + 1 ] >>= 1;
1479             p_bordel[ i + 2 ] <<= 4;
1480             p_bordel[ i + 3 ] >>= 3;
1481             break;
1482         case 777:
1483             p_bordel[ 1 ] += 0x20E;
1484             p_bordel[ 5 ] += 0x223D;
1485             p_bordel[ 13 ] -= 0x576;
1486             p_bordel[ 15 ] += 0x576;
1487             break;
1488         case 981:
1489             if( (p_bordel[ i ] ^ 0x8765F441) < 0x2710 )
1490             {
1491                 SWAP( p_bordel[ 0 ], p_bordel[ 1 ] );
1492             }
1493             else
1494             {
1495                 SWAP( p_bordel[ 1 ], p_bordel[ 11 ] );
1496             }
1497             break;
1498     }
1499 }
1500
1501 /*****************************************************************************
1502  * GetSystemKey: get the system key
1503  *****************************************************************************
1504  * Compute the system key from various system information, see HashSystemInfo.
1505  *****************************************************************************/
1506 static int GetSystemKey( uint32_t *p_sys_key, vlc_bool_t b_ipod )
1507 {
1508     static char const p_secret5[ 8 ] = "YuaFlafu";
1509     static char const p_secret6[ 8 ] = "zPif98ga";
1510     struct md5_s md5;
1511     int64_t i_ipod_id;
1512     uint32_t p_system_hash[ 4 ];
1513
1514     /* Compute the MD5 hash of our system info */
1515     if( ( !b_ipod && HashSystemInfo( p_system_hash ) ) ||
1516         (  b_ipod && GetiPodID( &i_ipod_id ) ) )
1517     {
1518         return -1;
1519     }
1520
1521     /* Combine our system info hash with additional secret data. The resulting
1522      * MD5 hash will be our system key. */
1523     InitMD5( &md5 );
1524     AddMD5( &md5, (const uint8_t*)p_secret5, 8 );
1525
1526     if( !b_ipod )
1527     {
1528         AddMD5( &md5, (const uint8_t *)p_system_hash, 6 );
1529         AddMD5( &md5, (const uint8_t *)p_system_hash, 6 );
1530         AddMD5( &md5, (const uint8_t *)p_system_hash, 6 );
1531         AddMD5( &md5, (const uint8_t *)p_secret6, 8 );
1532     }
1533     else
1534     {
1535         i_ipod_id = U64_AT(&i_ipod_id);
1536         AddMD5( &md5, (const uint8_t *)&i_ipod_id, sizeof(i_ipod_id) );
1537         AddMD5( &md5, (const uint8_t *)&i_ipod_id, sizeof(i_ipod_id) );
1538         AddMD5( &md5, (const uint8_t *)&i_ipod_id, sizeof(i_ipod_id) );
1539     }
1540
1541     EndMD5( &md5 );
1542
1543     memcpy( p_sys_key, md5.p_digest, 16 );
1544
1545     return 0;
1546 }
1547
1548 #ifdef WIN32
1549 #   define DRMS_DIRNAME "drms"
1550 #else
1551 #   define DRMS_DIRNAME ".drms"
1552 #endif
1553
1554 /*****************************************************************************
1555  * WriteUserKey: write the user key to hard disk
1556  *****************************************************************************
1557  * Write the user key to the hard disk so that it can be reused later or used
1558  * on operating systems other than Win32.
1559  *****************************************************************************/
1560 static int WriteUserKey( void *_p_drms, uint32_t *p_user_key )
1561 {
1562     struct drms_s *p_drms = (struct drms_s *)_p_drms;
1563     FILE *file;
1564     int i_ret = -1;
1565     char psz_path[ PATH_MAX ];
1566
1567     snprintf( psz_path, PATH_MAX - 1,
1568               "%s/" DRMS_DIRNAME, p_drms->psz_homedir );
1569
1570 #if defined( HAVE_ERRNO_H )
1571 #   if defined( WIN32 )
1572     if( !mkdir( psz_path ) || errno == EEXIST )
1573 #   else
1574     if( !mkdir( psz_path, 0755 ) || errno == EEXIST )
1575 #   endif
1576 #else
1577     if( !mkdir( psz_path ) )
1578 #endif
1579     {
1580         snprintf( psz_path, PATH_MAX - 1, "%s/" DRMS_DIRNAME "/%08X.%03d",
1581                   p_drms->psz_homedir, p_drms->i_user, p_drms->i_key );
1582
1583         file = utf8_fopen( psz_path, "wb" );
1584         if( file != NULL )
1585         {
1586             i_ret = fwrite( p_user_key, sizeof(uint32_t),
1587                             4, file ) == 4 ? 0 : -1;
1588             fclose( file );
1589         }
1590     }
1591
1592     return i_ret;
1593 }
1594
1595 /*****************************************************************************
1596  * ReadUserKey: read the user key from hard disk
1597  *****************************************************************************
1598  * Retrieve the user key from the hard disk if available.
1599  *****************************************************************************/
1600 static int ReadUserKey( void *_p_drms, uint32_t *p_user_key )
1601 {
1602     struct drms_s *p_drms = (struct drms_s *)_p_drms;
1603     FILE *file;
1604     int i_ret = -1;
1605     char psz_path[ PATH_MAX ];
1606
1607     snprintf( psz_path, PATH_MAX - 1,
1608               "%s/" DRMS_DIRNAME "/%08X.%03d", p_drms->psz_homedir,
1609               p_drms->i_user, p_drms->i_key );
1610
1611     file = utf8_fopen( psz_path, "rb" );
1612     if( file != NULL )
1613     {
1614         i_ret = fread( p_user_key, sizeof(uint32_t),
1615                        4, file ) == 4 ? 0 : -1;
1616         fclose( file );
1617     }
1618
1619     return i_ret;
1620 }
1621
1622 /*****************************************************************************
1623  * GetUserKey: get the user key
1624  *****************************************************************************
1625  * Retrieve the user key from the hard disk if available, otherwise generate
1626  * it from the system key. If the key could be successfully generated, write
1627  * it to the hard disk for future use.
1628  *****************************************************************************/
1629 static int GetUserKey( void *_p_drms, uint32_t *p_user_key )
1630 {
1631     static char const p_secret7[] = "mUfnpognadfgf873";
1632     struct drms_s *p_drms = (struct drms_s *)_p_drms;
1633     struct aes_s aes;
1634     struct shuffle_s shuffle;
1635     uint32_t i, y;
1636     uint32_t *p_sci_data = NULL;
1637     uint32_t i_user, i_key;
1638     uint32_t p_sys_key[ 4 ];
1639     uint32_t i_sci_size = 0, i_blocks, i_remaining;
1640     uint32_t *p_sci0, *p_sci1, *p_buffer;
1641     uint32_t p_sci_key[ 4 ];
1642     char *psz_ipod;
1643     int i_ret = -5;
1644
1645     if( ReadUserKey( p_drms, p_user_key ) == 0 )
1646     {
1647         REVERSE( p_user_key, 4 );
1648         return 0;
1649     }
1650
1651     psz_ipod = getenv( "IPOD" );
1652
1653     if( GetSystemKey( p_sys_key, psz_ipod ? VLC_TRUE : VLC_FALSE ) )
1654     {
1655         return -3;
1656     }
1657
1658     if( GetSCIData( psz_ipod, &p_sci_data, &i_sci_size ) )
1659     {
1660         return -4;
1661     }
1662
1663     /* Phase 1: unscramble the SCI data using the system key and shuffle
1664      *          it using DoShuffle(). */
1665
1666     /* Skip the first 4 bytes (some sort of header). Decrypt the rest. */
1667     i_blocks = (i_sci_size - 4) / 16;
1668     i_remaining = (i_sci_size - 4) - (i_blocks * 16);
1669     p_buffer = p_sci_data + 1;
1670
1671     /* Decrypt and shuffle our data at the same time */
1672     InitAES( &aes, p_sys_key );
1673     REVERSE( p_sys_key, 4 );
1674     REVERSE( p_sci_data, 1 );
1675     InitShuffle( &shuffle, p_sys_key, p_sci_data[ 0 ] );
1676
1677     memcpy( p_sci_key, p_secret7, 16 );
1678     REVERSE( p_sci_key, 4 );
1679
1680     while( i_blocks-- )
1681     {
1682         uint32_t p_tmp[ 4 ];
1683
1684         REVERSE( p_buffer, 4 );
1685         DecryptAES( &aes, p_tmp, p_buffer );
1686         BlockXOR( p_tmp, p_sci_key, p_tmp );
1687
1688         /* Use the previous scrambled data as the key for next block */
1689         memcpy( p_sci_key, p_buffer, 16 );
1690
1691         /* Shuffle the decrypted data using a custom routine */
1692         DoShuffle( &shuffle, p_tmp, 4 );
1693
1694         /* Copy this block back to p_buffer */
1695         memcpy( p_buffer, p_tmp, 16 );
1696
1697         p_buffer += 4;
1698     }
1699
1700     if( i_remaining >= 4 )
1701     {
1702         REVERSE( p_buffer, i_remaining / 4 );
1703         DoShuffle( &shuffle, p_buffer, i_remaining / 4 );
1704     }
1705
1706     /* Phase 2: look for the user key in the generated data. I must admit I
1707      *          do not understand what is going on here, because it almost
1708      *          looks like we are browsing data that makes sense, even though
1709      *          the DoShuffle() part made it completely meaningless. */
1710
1711     y = 0;
1712     REVERSE( p_sci_data + 5, 1 );
1713     i = U32_AT( p_sci_data + 5 );
1714     i_sci_size -= 22 * sizeof(uint32_t);
1715     p_sci1 = p_sci_data + 22;
1716     p_sci0 = NULL;
1717
1718     while( i_sci_size >= 20 && i > 0 )
1719     {
1720         if( p_sci0 == NULL )
1721         {
1722             i_sci_size -= 18 * sizeof(uint32_t);
1723             if( i_sci_size < 20 )
1724             {
1725                 break;
1726             }
1727
1728             p_sci0 = p_sci1;
1729             REVERSE( p_sci1 + 17, 1 );
1730             y = U32_AT( p_sci1 + 17 );
1731             p_sci1 += 18;
1732         }
1733
1734         if( !y )
1735         {
1736             i--;
1737             p_sci0 = NULL;
1738             continue;
1739         }
1740
1741         i_user = U32_AT( p_sci0 );
1742         i_key = U32_AT( p_sci1 );
1743         REVERSE( &i_user, 1 );
1744         REVERSE( &i_key, 1 );
1745         if( i_user == p_drms->i_user && ( ( i_key == p_drms->i_key ) ||
1746             ( !p_drms->i_key && ( p_sci1 == (p_sci0 + 18) ) ) ) )
1747         {
1748             memcpy( p_user_key, p_sci1 + 1, 16 );
1749             REVERSE( p_sci1 + 1, 4 );
1750             WriteUserKey( p_drms, p_sci1 + 1 );
1751             i_ret = 0;
1752             break;
1753         }
1754
1755         y--;
1756         p_sci1 += 5;
1757         i_sci_size -= 5 * sizeof(uint32_t);
1758     }
1759
1760     free( p_sci_data );
1761
1762     return i_ret;
1763 }
1764
1765 /*****************************************************************************
1766  * GetSCIData: get SCI data from "SC Info.sidb"
1767  *****************************************************************************
1768  * Read SCI data from "\Apple Computer\iTunes\SC Info\SC Info.sidb"
1769  *****************************************************************************/
1770 static int GetSCIData( char *psz_ipod, uint32_t **pp_sci,
1771                        uint32_t *pi_sci_size )
1772 {
1773     FILE *file;
1774     char *psz_path = NULL;
1775     char p_tmp[ 4 * PATH_MAX ];
1776     int i_ret = -1;
1777
1778     if( psz_ipod == NULL )
1779     {
1780 #ifdef WIN32
1781         const wchar_t *wfile =
1782                 L"\\Apple Computer\\iTunes\\SC Info\\SC Info.sidb";
1783         typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
1784                                                    LPWSTR );
1785         HINSTANCE shfolder_dll = NULL;
1786         SHGETFOLDERPATH dSHGetFolderPath = NULL;
1787         wchar_t wpath[PATH_MAX];
1788
1789         if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
1790         {
1791             dSHGetFolderPath =
1792                 (SHGETFOLDERPATH)GetProcAddress( shfolder_dll,
1793                                                  _T("SHGetFolderPathW") );
1794         }
1795
1796         if( dSHGetFolderPath != NULL &&
1797             SUCCEEDED( dSHGetFolderPath( NULL, CSIDL_COMMON_APPDATA,
1798                                          NULL, 0, wpath ) ) )
1799         {
1800             if (wcslen( wpath ) + wcslen( wfile ) >= PATH_MAX )
1801             {
1802                 return -1;
1803             }
1804             wcscat( wpath, wfile );
1805
1806             psz_path = FromWide( wpath );
1807             strncpy( p_tmp, psz_path, sizeof( p_tmp ) - 1 );
1808             p_tmp[sizeof( p_tmp ) - 1] = '\0';
1809             free( psz_path );
1810             psz_path = p_tmp;
1811         }
1812
1813         if( shfolder_dll != NULL )
1814         {
1815             FreeLibrary( shfolder_dll );
1816         }
1817 #endif
1818     }
1819     else
1820     {
1821 #define ISCINFO "iSCInfo"
1822         if( strstr( psz_ipod, ISCINFO ) == NULL )
1823         {
1824             snprintf( p_tmp, sizeof(p_tmp) - 1,
1825                       "%s/iPod_Control/iTunes/" ISCINFO "2", psz_ipod );
1826             psz_path = p_tmp;
1827         }
1828         else
1829         {
1830             psz_path = psz_ipod;
1831         }
1832     }
1833
1834     if( psz_path == NULL )
1835     {
1836         return -1;
1837     }
1838
1839     file = utf8_fopen( psz_path, "rb" );
1840     if( file != NULL )
1841     {
1842         struct stat st;
1843
1844         if( !fstat( fileno( file ), &st ) && st.st_size >= 4 )
1845         {
1846             *pp_sci = malloc( st.st_size );
1847             if( *pp_sci != NULL )
1848             {
1849                 if( fread( *pp_sci, 1, st.st_size,
1850                            file ) == (size_t)st.st_size )
1851                 {
1852                     *pi_sci_size = st.st_size;
1853                     i_ret = 0;
1854                 }
1855                 else
1856                 {
1857                     free( (void *)*pp_sci );
1858                     *pp_sci = NULL;
1859                 }
1860             }
1861         }
1862
1863         fclose( file );
1864     }
1865
1866     return i_ret;
1867 }
1868
1869 /*****************************************************************************
1870  * HashSystemInfo: hash system information
1871  *****************************************************************************
1872  * This function computes the MD5 hash of the C: hard drive serial number,
1873  * BIOS version, CPU type and Windows version.
1874  *****************************************************************************/
1875 static int HashSystemInfo( uint32_t *p_system_hash )
1876 {
1877     struct md5_s md5;
1878     int i_ret = 0;
1879
1880 #ifdef WIN32
1881     HKEY i_key;
1882     unsigned int i;
1883     DWORD i_size;
1884     DWORD i_serial;
1885     LPBYTE p_reg_buf;
1886
1887     static LPCTSTR p_reg_keys[ 3 ][ 2 ] =
1888     {
1889         {
1890             _T("HARDWARE\\DESCRIPTION\\System"),
1891             _T("SystemBiosVersion")
1892         },
1893
1894         {
1895             _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
1896             _T("ProcessorNameString")
1897         },
1898
1899         {
1900             _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
1901             _T("ProductId")
1902         }
1903     };
1904
1905     InitMD5( &md5 );
1906
1907     AddMD5( &md5, "cache-control", 13 );
1908     AddMD5( &md5, "Ethernet", 8 );
1909
1910     GetVolumeInformation( _T("C:\\"), NULL, 0, &i_serial,
1911                           NULL, NULL, NULL, 0 );
1912     AddMD5( &md5, (const uint8_t *)&i_serial, 4 );
1913
1914     for( i = 0; i < sizeof(p_reg_keys) / sizeof(p_reg_keys[ 0 ]); i++ )
1915     {
1916         if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, p_reg_keys[ i ][ 0 ],
1917                           0, KEY_READ, &i_key ) != ERROR_SUCCESS )
1918         {
1919             continue;
1920         }
1921
1922         if( RegQueryValueEx( i_key, p_reg_keys[ i ][ 1 ],
1923                              NULL, NULL, NULL, &i_size ) != ERROR_SUCCESS )
1924         {
1925             RegCloseKey( i_key );
1926             continue;
1927         }
1928
1929         p_reg_buf = malloc( i_size );
1930
1931         if( p_reg_buf != NULL )
1932         {
1933             if( RegQueryValueEx( i_key, p_reg_keys[ i ][ 1 ],
1934                                  NULL, NULL, p_reg_buf,
1935                                  &i_size ) == ERROR_SUCCESS )
1936             {
1937                 AddMD5( &md5, (const uint8_t *)p_reg_buf, i_size );
1938             }
1939
1940             free( p_reg_buf );
1941         }
1942
1943         RegCloseKey( i_key );
1944     }
1945
1946 #else
1947     InitMD5( &md5 );
1948     i_ret = -1;
1949 #endif
1950
1951     EndMD5( &md5 );
1952     memcpy( p_system_hash, md5.p_digest, 16 );
1953
1954     return i_ret;
1955 }
1956
1957 /*****************************************************************************
1958  * GetiPodID: Get iPod ID
1959  *****************************************************************************
1960  * This function gets the iPod ID.
1961  *****************************************************************************/
1962 static int GetiPodID( int64_t *p_ipod_id )
1963 {
1964     int i_ret = -1;
1965
1966 #define PROD_NAME   "iPod"
1967 #define VENDOR_NAME "Apple Computer, Inc."
1968
1969     char *psz_ipod_id = getenv( "IPODID" );
1970     if( psz_ipod_id != NULL )
1971     {
1972         *p_ipod_id = strtoll( psz_ipod_id, NULL, 16 );
1973         return 0;
1974     }
1975
1976 #ifdef __APPLE__
1977     CFTypeRef value;
1978     mach_port_t port;
1979     io_object_t device;
1980     io_iterator_t iterator;
1981     CFMutableDictionaryRef match_dic;
1982     CFMutableDictionaryRef smatch_dic;
1983
1984     if( IOMasterPort( MACH_PORT_NULL, &port ) == KERN_SUCCESS )
1985     {
1986         smatch_dic = IOServiceMatching( "IOFireWireUnit" );
1987         match_dic = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
1988                                            &kCFTypeDictionaryKeyCallBacks,
1989                                            &kCFTypeDictionaryValueCallBacks );
1990
1991         if( smatch_dic != NULL && match_dic != NULL )
1992         {
1993             CFDictionarySetValue( smatch_dic,
1994                                   CFSTR("FireWire Vendor Name"),
1995                                   CFSTR(VENDOR_NAME) );
1996             CFDictionarySetValue( smatch_dic,
1997                                   CFSTR("FireWire Product Name"),
1998                                   CFSTR(PROD_NAME) );
1999
2000             CFDictionarySetValue( match_dic,
2001                                   CFSTR(kIOPropertyMatchKey),
2002                                   smatch_dic );
2003
2004             if( IOServiceGetMatchingServices( port, match_dic,
2005                                               &iterator ) == KERN_SUCCESS )
2006             {
2007                 while( ( device = IOIteratorNext( iterator ) ) != NULL )
2008                 {
2009                     value = IORegistryEntryCreateCFProperty( device,
2010                         CFSTR("GUID"), kCFAllocatorDefault, kNilOptions );
2011
2012                     if( value != NULL )
2013                     {
2014                         if( CFGetTypeID( value ) == CFNumberGetTypeID() )
2015                         {
2016                             int64_t i_ipod_id;
2017                             CFNumberGetValue( (CFNumberRef)value,
2018                                               kCFNumberLongLongType,
2019                                               &i_ipod_id );
2020                             *p_ipod_id = i_ipod_id;
2021                             i_ret = 0;
2022                         }
2023
2024                         CFRelease( value );
2025                     }
2026
2027                     IOObjectRelease( device );
2028
2029                     if( !i_ret ) break;
2030                 }
2031
2032                 IOObjectRelease( iterator );
2033             }
2034         }
2035
2036         mach_port_deallocate( mach_task_self(), port );
2037     }
2038
2039 #elif defined (HAVE_SYSFS_LIBSYSFS_H)
2040     struct sysfs_bus *bus = NULL;
2041     struct dlist *devlist = NULL;
2042     struct dlist *attributes = NULL;
2043     struct sysfs_device *curdev = NULL;
2044     struct sysfs_attribute *curattr = NULL;
2045
2046     bus = sysfs_open_bus( "ieee1394" );
2047     if( bus != NULL )
2048     {
2049         devlist = sysfs_get_bus_devices( bus );
2050         if( devlist != NULL )
2051         {
2052             dlist_for_each_data( devlist, curdev, struct sysfs_device )
2053             {
2054                 attributes = sysfs_get_device_attributes( curdev );
2055                 if( attributes != NULL )
2056                 {
2057                     dlist_for_each_data( attributes, curattr,
2058                                          struct sysfs_attribute )
2059                     {
2060                         if( ( strcmp( curattr->name, "model_name" ) == 0 ) &&
2061                             ( strncmp( curattr->value, PROD_NAME,
2062                                        sizeof(PROD_NAME) ) == 0 ) )
2063                         {
2064                             *p_ipod_id = strtoll( curdev->name, NULL, 16 );
2065                             i_ret = 0;
2066                             break;
2067                         }
2068                     }
2069                }
2070
2071                 if( !i_ret ) break;
2072             }
2073         }
2074
2075         sysfs_close_bus( bus );
2076     }
2077 #endif
2078
2079     return i_ret;
2080 }
2081
2082 #else /* !defined( UNDER_CE ) */
2083
2084 void *drms_alloc( char *psz_homedir ){ return 0; }
2085 void drms_free( void *a ){}
2086 void drms_decrypt( void *a, uint32_t *b, uint32_t c  ){}
2087 int drms_init( void *a, uint32_t b, uint8_t *c, uint32_t d ){ return -1; }
2088
2089 #endif /* defined( UNDER_CE ) */