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