css.c 60.2 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1
/*****************************************************************************
2
 * css.c: Functions for DVD authentication and descrambling
Sam Hocevar's avatar
 
Sam Hocevar committed
3
 *****************************************************************************
4
 * Copyright (C) 1999-2008 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
5
 *
6
7
 * Authors: Stéphane Borel <stef@via.ecp.fr>
 *          Håkan Hjort <d95hjort@dtek.chalmers.se>
Sam Hocevar's avatar
 
Sam Hocevar committed
8
9
10
11
12
 *
 * based on:
 *  - css-auth by Derek Fawcus <derek@spider.com>
 *  - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net>
 *  - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com>
13
 *     (see http://www-2.cs.cmu.edu/~dst/DeCSS/FrankStevenson/index.html)
Sam Hocevar's avatar
 
Sam Hocevar committed
14
15
16
 *  - DeCSSPlus by Ethan Hawke
 *  - DecVOB
 *  see http://www.lemuria.org/DeCSS/ by Tom Vogt for more information.
17
 *
18
 * libdvdcss is free software; you can redistribute it and/or modify
Sam Hocevar's avatar
 
Sam Hocevar committed
19
20
21
22
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
23
 * libdvdcss is distributed in the hope that it will be useful,
Sam Hocevar's avatar
 
Sam Hocevar committed
24
25
26
27
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
Diego Biurrun's avatar
Diego Biurrun committed
28
 * You should have received a copy of the GNU General Public License along
29
 * with libdvdcss; if not, write to the Free Software Foundation, Inc.,
Diego Biurrun's avatar
Diego Biurrun committed
30
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Sam Hocevar's avatar
 
Sam Hocevar committed
31
32
33
34
35
36
37
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include "config.h"

Diego Biurrun's avatar
Diego Biurrun committed
38
#include <limits.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
39
40
41
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
42
#include <sys/types.h>
43
44
45
#ifdef HAVE_SYS_PARAM_H
#   include <sys/param.h>
#endif
46
47
48
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
49
#include <fcntl.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
50

Sam Hocevar's avatar
   
Sam Hocevar committed
51
#include "dvdcss/dvdcss.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
52
53
54
55
56
57

#include "common.h"
#include "css.h"
#include "libdvdcss.h"
#include "csstables.h"
#include "ioctl.h"
58
#include "device.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
59

60
#define PSZ_KEY_SIZE (DVD_KEY_SIZE * 3)
61

Sam Hocevar's avatar
 
Sam Hocevar committed
62
63
64
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
65
static void PrintKey        ( dvdcss_t, const char *, const uint8_t * );
66

67
68
static int  GetBusKey       ( dvdcss_t );
static int  GetASF          ( dvdcss_t );
69

70
static void CryptKey        ( int, int, const uint8_t *, uint8_t * );
71
static void DecryptKey      ( uint8_t,
72
                              const uint8_t *, const uint8_t *, uint8_t * );
73

74
static int  DecryptDiscKey  ( dvdcss_t, const uint8_t *, dvd_key );
75
static int  CrackDiscKey    ( uint8_t * );
76

77
static void DecryptTitleKey ( dvd_key, dvd_key );
78
79
static int  RecoverTitleKey ( int, const uint8_t *,
                              const uint8_t *, const uint8_t *, uint8_t * );
80
static int  CrackTitleKey   ( dvdcss_t, int, int, dvd_key );
81

82
static int  AttackPattern   ( const uint8_t[], uint8_t * );
83
#if 0
84
static int  AttackPadding   ( const uint8_t[] );
85
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
86

87
static int  dvdcss_titlekey ( dvdcss_t, int, dvd_key );
88

Sam Hocevar's avatar
 
Sam Hocevar committed
89
/*****************************************************************************
90
 * dvdcss_test: check if the disc is encrypted or not
91
92
93
94
95
 *****************************************************************************
 * Return values:
 *   1: DVD is scrambled but can be read
 *   0: DVD is not scrambled and can be read
 *  -1: could not get "copyright" information
96
97
 *  -2: could not get RPC (Regional Playback Control) information
 *      (reading the disc might be possible)
98
99
 *  -3: drive is RPC-II, region is not set, and DVD is scrambled: the RPC
 *      scheme will prevent us from reading the scrambled data
Sam Hocevar's avatar
 
Sam Hocevar committed
100
 *****************************************************************************/
101
int dvdcss_test( dvdcss_t dvdcss )
Sam Hocevar's avatar
 
Sam Hocevar committed
102
{
103
    const char *psz_type, *psz_rpc;
104
    char psz_region[17];
105
106
    char *p_region = psz_region;
    int i_ret, i_copyright, i_type, i_mask, i_rpc, i_region;
Sam Hocevar's avatar
 
Sam Hocevar committed
107
108
109

    i_ret = ioctl_ReadCopyright( dvdcss->i_fd, 0 /* i_layer */, &i_copyright );

gbazin's avatar
   
gbazin committed
110
111
    if( i_ret < 0 )
    {
112
#ifdef _WIN32
113
        /* Maybe we didn't have enough privileges to read the copyright
gbazin's avatar
   
gbazin committed
114
         * (see ioctl_ReadCopyright comments).
115
         * Apparently, on unencrypted DVDs dvdcss_disckey() always fails, so
116
         * we can check this as a workaround. */
117
        if( dvdcss_disckey( dvdcss ) < 0 )
118
        {
gbazin's avatar
   
gbazin committed
119
            i_copyright = 0;
120
        }
121
122
123
124
125
        else
        {
            i_copyright = 1;
        }
#else
Sam Hocevar's avatar
 
Sam Hocevar committed
126
        /* Since it's the first ioctl we try to issue, we add a notice */
127
        print_error( dvdcss, "CSS error: could not get \"copyright\""
128
129
130
131
                     " information, make sure there is a DVD in the drive,"
                     " and that you have used the correct device node." );

        return -1;
132
#endif /* _WIN32 */
133
134
    }

135
136
137
    print_debug( dvdcss, "disc reports copyright information 0x%x",
                         i_copyright );

138
139
140
141
    i_ret = ioctl_ReportRPC( dvdcss->i_fd, &i_type, &i_mask, &i_rpc);

    if( i_ret < 0 )
    {
142
        print_error( dvdcss, "CSS error: could not get RPC (Regional Playback "
143
                     "Control) status. Assuming RPC-I drive." );
144
        i_type = i_mask = i_rpc = 0;
145
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
146

147
148
149
150
    switch( i_rpc )
    {
        case 0: psz_rpc = "RPC-I"; break;
        case 1: psz_rpc = "RPC-II"; break;
151
        default: psz_rpc = "unknown RPC (Regional Playback Control) scheme"; break;
152
153
154
155
156
157
158
159
160
161
162
    }

    switch( i_type )
    {
        case 0: psz_type = "no region code set"; break;
        case 1: psz_type = "region code set"; break;
        case 2: psz_type = "one region change remaining"; break;
        case 3: psz_type = "region code set permanently"; break;
        default: psz_type = "unknown status"; break;
    }

163
    *p_region = '\0';
164
165
166
167
168
169
170
171
172
173
174
    for( i_region = 0; i_region < 8; i_region++ )
    {
        if( !( i_mask & ( 1 << i_region ) ) )
        {
            sprintf(p_region, " %d", i_region + 1);
            p_region += 2;
        }
    }

    print_debug( dvdcss, "drive region(s)%s, region mask 0x%x, %s, %s",
                 psz_region, i_mask, psz_rpc, psz_type );
175
176
177

    if( i_copyright && i_rpc == 1 && i_type == 0 )
    {
178
        print_error( dvdcss, "CSS error: drive will prevent access to "
179
180
                             "scrambled data" );
        return -3;
Sam Hocevar's avatar
 
Sam Hocevar committed
181
182
    }

183
    return i_copyright ? 1 : 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
184
185
186
}

/*****************************************************************************
187
 * dvdcss_title: crack or decrypt the current title key if needed
188
 *****************************************************************************
189
 * This function should only be called by dvdcss->pf_seek and should eventually
190
191
 * not be external if possible.
 *****************************************************************************/
192
int dvdcss_title ( dvdcss_t dvdcss, int i_block )
193
{
194
195
196
197
    struct dvd_title *p_title;
    struct dvd_title *p_newtitle;
    dvd_key p_title_key;
    int i_fd, i_ret = -1, b_cache = 0;
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

    if( ! dvdcss->b_scrambled )
    {
        return 0;
    }

    /* Check if we've already cracked this key */
    p_title = dvdcss->p_titles;
    while( p_title != NULL
            && p_title->p_next != NULL
            && p_title->p_next->i_startlb <= i_block )
    {
        p_title = p_title->p_next;
    }

    if( p_title != NULL
         && p_title->i_startlb == i_block )
    {
        /* We've already cracked this key, nothing to do */
217
        memcpy( dvdcss->css.p_title_key, p_title->p_key, sizeof(p_title->p_key) );
218
219
220
        return 0;
    }

221
222
223
224
    /* Check whether the key is in our disk cache */
    if( dvdcss->psz_cachefile[0] )
    {
        /* XXX: be careful, we use sprintf and not snprintf */
225
226
        sprintf( dvdcss->psz_block, "%." CACHE_FILENAME_LENGTH_STRING "x",
                 i_block );
227
228
        i_fd = open( dvdcss->psz_cachefile, O_RDONLY );
        b_cache = 1;
229

230
231
        if( i_fd >= 0 )
        {
232
            char psz_key[PSZ_KEY_SIZE];
Sam Hocevar's avatar
Sam Hocevar committed
233
234
            unsigned int k0, k1, k2, k3, k4;

235
            psz_key[PSZ_KEY_SIZE - 1] = '\0';
Sam Hocevar's avatar
Sam Hocevar committed
236

237
            if( read( i_fd, psz_key, PSZ_KEY_SIZE - 1 ) == PSZ_KEY_SIZE - 1
Sam Hocevar's avatar
Sam Hocevar committed
238
239
                 && sscanf( psz_key, "%x:%x:%x:%x:%x",
                            &k0, &k1, &k2, &k3, &k4 ) == 5 )
240
            {
Sam Hocevar's avatar
Sam Hocevar committed
241
242
243
244
245
246
247
                p_title_key[0] = k0;
                p_title_key[1] = k1;
                p_title_key[2] = k2;
                p_title_key[3] = k3;
                p_title_key[4] = k4;
                PrintKey( dvdcss, "title key found in cache ", p_title_key );

248
249
250
251
                /* Don't try to save it again */
                b_cache = 0;
                i_ret = 1;
            }
Sam Hocevar's avatar
Sam Hocevar committed
252

253
254
255
256
            close( i_fd );
        }
    }

257
258
    /* Crack or decrypt Content Scrambling System (CSS) title key
     * for current Video Title Set (VTS). */
259
260
    if( i_ret < 0 )
    {
261
        i_ret = dvdcss_titlekey( dvdcss, i_block, p_title_key );
262
263
264

        if( i_ret < 0 )
        {
265
266
            print_error( dvdcss, "fatal error in Video Title Set (VTS) "
                                 "Content Scrambling System (CSS) key" );
267
268
269
270
271
            return i_ret;
        }

        if( i_ret == 0 )
        {
272
            print_debug( dvdcss, "unencrypted title" );
273
274
            /* We cache this anyway, so we don't need to check again. */
        }
275
    }
276
277

    /* Key is valid, we store it on disk. */
Sam Hocevar's avatar
Sam Hocevar committed
278
    if( dvdcss->psz_cachefile[0] && b_cache )
279
    {
Sam Hocevar's avatar
Sam Hocevar committed
280
        i_fd = open( dvdcss->psz_cachefile, O_RDWR|O_CREAT, 0644 );
281
282
        if( i_fd >= 0 )
        {
283
            char psz_key[PSZ_KEY_SIZE + 2];
Sam Hocevar's avatar
Sam Hocevar committed
284
285
286
287
288

            sprintf( psz_key, "%02x:%02x:%02x:%02x:%02x\r\n",
                              p_title_key[0], p_title_key[1], p_title_key[2],
                              p_title_key[3], p_title_key[4] );

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
289
            if( write( i_fd, psz_key, PSZ_KEY_SIZE + 1 ) < PSZ_KEY_SIZE + 1 )
290
291
292
293
            {
                print_error( dvdcss,
                             "Error caching key on disk, continuing..\n" );
            }
294
295
            close( i_fd );
        }
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
    }

    /* Find our spot in the list */
    p_newtitle = NULL;
    p_title = dvdcss->p_titles;
    while( ( p_title != NULL ) && ( p_title->i_startlb < i_block ) )
    {
        p_newtitle = p_title;
        p_title = p_title->p_next;
    }

    /* Save the found title */
    p_title = p_newtitle;

    /* Write in the new title and its key */
311
    p_newtitle = malloc( sizeof( *p_newtitle ) );
312
313
314
315
    if( p_newtitle == NULL )
    {
        return -1;
    }
316
    p_newtitle->i_startlb = i_block;
317
    memcpy( p_newtitle->p_key, p_title_key, DVD_KEY_SIZE );
318
319
320
321
322
323
324
325
326
327
328
329
330
331

    /* Link it at the head of the (possibly empty) list */
    if( p_title == NULL )
    {
        p_newtitle->p_next = dvdcss->p_titles;
        dvdcss->p_titles = p_newtitle;
    }
    /* Link the new title inside the list */
    else
    {
        p_newtitle->p_next = p_title->p_next;
        p_title->p_next = p_newtitle;
    }

332
    memcpy( dvdcss->css.p_title_key, p_title_key, DVD_KEY_SIZE );
333
334
335
336
    return 0;
}

/*****************************************************************************
337
 * dvdcss_disckey: get disc key.
Sam Hocevar's avatar
 
Sam Hocevar committed
338
339
 *****************************************************************************
 * This function should only be called if DVD ioctls are present.
340
 * It will set dvdcss->i_method = DVDCSS_METHOD_TITLE if it fails to find
341
342
 * a valid disc key.
 * Two decryption methods are offered:
Sam Hocevar's avatar
 
Sam Hocevar committed
343
344
345
 *  -disc key hash crack,
 *  -decryption with player keys if they are available.
 *****************************************************************************/
346
int dvdcss_disckey( dvdcss_t dvdcss )
Sam Hocevar's avatar
 
Sam Hocevar committed
347
{
Sam Hocevar's avatar
Sam Hocevar committed
348
    unsigned char p_buffer[ DVD_DISCKEY_SIZE ];
349
    dvd_key p_disc_key;
Sam Hocevar's avatar
 
Sam Hocevar committed
350
351
    int i;

352
    if( GetBusKey( dvdcss ) < 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
353
354
355
356
357
358
359
    {
        return -1;
    }

    /* Get encrypted disc key */
    if( ioctl_ReadDiscKey( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
360
        print_error( dvdcss, "ioctl ReadDiscKey failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
361
362
363
        return -1;
    }

364
    /* This should have invalidated the AGID and got us ASF=1. */
365
    if( GetASF( dvdcss ) != 1 )
366
    {
367
        /* Region mismatch (or region not set) is the most likely source. */
368
369
        print_error( dvdcss, "authentication success flag (ASF) not 1 after "
                             "reading disc key (region mismatch?)" );
370
371
372
373
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

Sam Hocevar's avatar
Sam Hocevar committed
374
    /* Shuffle disc key using bus key */
Sam Hocevar's avatar
Sam Hocevar committed
375
    for( i = 0 ; i < DVD_DISCKEY_SIZE ; i++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
376
    {
377
        p_buffer[i] ^= dvdcss->css.p_bus_key[4 - (i % DVD_KEY_SIZE)];
Sam Hocevar's avatar
 
Sam Hocevar committed
378
379
    }

Sam Hocevar's avatar
Sam Hocevar committed
380
    /* Decrypt disc key */
Sam Hocevar's avatar
 
Sam Hocevar committed
381
382
383
    switch( dvdcss->i_method )
    {
        case DVDCSS_METHOD_KEY:
384

385
            /* Decrypt disc key with player key. */
386
            PrintKey( dvdcss, "decrypting disc key ", p_buffer );
387
            if( ! DecryptDiscKey( dvdcss, p_buffer, p_disc_key ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
388
            {
389
                PrintKey( dvdcss, "decrypted disc key is ", p_disc_key );
390
391
                break;
            }
392
393
394
            print_debug( dvdcss, "failed to decrypt the disc key, "
                                 "faulty drive/kernel? "
                                 "cracking title keys instead" );
395

396
            /* Fallback, but not to DISC as the disc key might be faulty */
397
            memset( p_disc_key, 0, DVD_KEY_SIZE );
398
399
            dvdcss->i_method = DVDCSS_METHOD_TITLE;
            break;
Sam Hocevar's avatar
   
Sam Hocevar committed
400

Sam Hocevar's avatar
 
Sam Hocevar committed
401
        case DVDCSS_METHOD_DISC:
402

Sam Hocevar's avatar
 
Sam Hocevar committed
403
            /* Crack Disc key to be able to use it */
404
            memcpy( p_disc_key, p_buffer, DVD_KEY_SIZE );
405
            PrintKey( dvdcss, "cracking disc key ", p_disc_key );
406
            if( ! CrackDiscKey( p_disc_key ) )
407
            {
408
409
                PrintKey( dvdcss, "cracked disc key is ", p_disc_key );
                break;
410
            }
411
            print_debug( dvdcss, "failed to crack the disc key" );
412
            memset( p_disc_key, 0, DVD_KEY_SIZE );
413
            dvdcss->i_method = DVDCSS_METHOD_TITLE;
Sam Hocevar's avatar
 
Sam Hocevar committed
414
415
416
            break;

        default:
417

418
            print_debug( dvdcss, "disc key does not need to be decrypted" );
419
            memset( p_disc_key, 0, DVD_KEY_SIZE );
Sam Hocevar's avatar
   
Sam Hocevar committed
420
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
421
422
    }

423
    memcpy( dvdcss->css.p_disc_key, p_disc_key, DVD_KEY_SIZE );
424

Sam Hocevar's avatar
 
Sam Hocevar committed
425
426
427
428
429
    return 0;
}


/*****************************************************************************
430
 * dvdcss_titlekey: get title key.
Sam Hocevar's avatar
 
Sam Hocevar committed
431
 *****************************************************************************/
432
static int dvdcss_titlekey( dvdcss_t dvdcss, int i_pos, dvd_key p_title_key )
Sam Hocevar's avatar
 
Sam Hocevar committed
433
{
Sam Hocevar's avatar
Sam Hocevar committed
434
    static uint8_t p_garbage[ DVDCSS_BLOCK_SIZE ];  /* we never read it back */
435
    uint8_t p_key[DVD_KEY_SIZE];
436
    int i, i_ret = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
437

438
    if( dvdcss->b_ioctls && ( dvdcss->i_method == DVDCSS_METHOD_KEY ||
439
                              dvdcss->i_method == DVDCSS_METHOD_DISC ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
440
    {
441
442
        /* We have a decrypted Disc key and the ioctls are available,
         * read the title key and decrypt it.
Sam Hocevar's avatar
 
Sam Hocevar committed
443
444
         */

445
446
        print_debug( dvdcss, "getting title key at block %i the classic way",
                             i_pos );
447

448
        /* We need to authenticate again every time to get a new session key */
449
        if( GetBusKey( dvdcss ) < 0 )
450
        {
451
            i_ret = -1;
452
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
453
454
455
456
457

        /* Get encrypted title key */
        if( ioctl_ReadTitleKey( dvdcss->i_fd, &dvdcss->css.i_agid,
                                i_pos, p_key ) < 0 )
        {
458
459
            print_debug( dvdcss,
                         "ioctl ReadTitleKey failed (region mismatch?)" );
460
461
462
463
            i_ret = -1;
        }

        /* Test ASF, it will be reset to 0 if we got a Region error */
464
        switch( GetASF( dvdcss ) )
465
466
467
        {
            case -1:
                /* An error getting the ASF status, something must be wrong. */
468
                print_debug( dvdcss, "lost authentication success flag (ASF), requesting title key" );
469
                ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
470
                i_ret = -1;
471
                break;
472
473

            case 0:
474
                /* This might either be a title that has no key,
475
                 * or we encountered a region error. */
476
                print_debug( dvdcss, "lost authentication success flag (ASF), requesting title key" );
477
                break;
478
479

            case 1:
480
                /* Drive status is OK. */
481
                /* If the title key request failed, but we did not lose ASF,
482
                 * we might still have the AGID.  Other code assumes that we
483
484
485
486
487
                 * will not after this so invalidate it(?). */
                if( i_ret < 0 )
                {
                    ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
                }
488
                break;
Sam Hocevar's avatar
 
Sam Hocevar committed
489
        }
490
491
492
493

        if( !( i_ret < 0 ) )
        {
            /* Decrypt title key using the bus key */
494
            for( i = 0 ; i < DVD_KEY_SIZE ; i++ )
495
            {
496
                p_key[i] ^= dvdcss->css.p_bus_key[4 - (i % DVD_KEY_SIZE)];
497
498
            }

Sam Hocevar's avatar
Sam Hocevar committed
499
            /* If p_key is all zero then there really wasn't any key present
500
501
502
503
504
505
506
             * even though we got to read it without an error. */
            if( !( p_key[0] | p_key[1] | p_key[2] | p_key[3] | p_key[4] ) )
            {
                i_ret = 0;
            }
            else
            {
507
                PrintKey( dvdcss, "initial disc key ", dvdcss->css.p_disc_key );
508
                DecryptTitleKey( dvdcss->css.p_disc_key, p_key );
509
                PrintKey( dvdcss, "decrypted title key ", p_key );
510
511
512
513
                i_ret = 1;
            }

            /* All went well either there wasn't a key or we have it now. */
514
            memcpy( p_title_key, p_key, DVD_KEY_SIZE );
515
516
517
518
519
520
            PrintKey( dvdcss, "title key is ", p_title_key );

            return i_ret;
        }

        /* The title key request failed */
521
        print_debug( dvdcss, "resetting drive and cracking title key" );
522

523
        /* Read an unscrambled sector and reset the drive */
524
525
526
        dvdcss->pf_seek( dvdcss, 0 );
        dvdcss->pf_read( dvdcss, p_garbage, 1 );
        dvdcss->pf_seek( dvdcss, 0 );
527
        dvdcss_disckey( dvdcss );
528
529

        /* Fallback */
530
    }
531

532
533
    /* METHOD is TITLE, we can't use the ioctls or requesting the title key
     * failed above.  For these cases we try to crack the key instead. */
534

535
    /* For now, the read limit is 9GB / 2048 =  4718592 sectors. */
536
    i_ret = CrackTitleKey( dvdcss, i_pos, 4718592, p_key );
Sam Hocevar's avatar
 
Sam Hocevar committed
537

538
    memcpy( p_title_key, p_key, DVD_KEY_SIZE );
539
    PrintKey( dvdcss, "title key is ", p_title_key );
Sam Hocevar's avatar
 
Sam Hocevar committed
540

541
    return i_ret;
Sam Hocevar's avatar
 
Sam Hocevar committed
542
543
544
}

/*****************************************************************************
545
 * dvdcss_unscramble: does the actual descrambling of data
Sam Hocevar's avatar
 
Sam Hocevar committed
546
 *****************************************************************************
547
548
 * sec: sector to unscramble
 * key: title key for this sector
Sam Hocevar's avatar
 
Sam Hocevar committed
549
 *****************************************************************************/
550
int dvdcss_unscramble( dvd_key p_key, uint8_t *p_sec )
Sam Hocevar's avatar
 
Sam Hocevar committed
551
552
{
    unsigned int    i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
Sam Hocevar's avatar
Sam Hocevar committed
553
    uint8_t        *p_end = p_sec + DVDCSS_BLOCK_SIZE;
Sam Hocevar's avatar
 
Sam Hocevar committed
554
555

    /* PES_scrambling_control */
556
    if( !(p_sec[0x14] & 0x30) )
Sam Hocevar's avatar
 
Sam Hocevar committed
557
    {
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
        return 0;
    }

    i_t1 = (p_key[0] ^ p_sec[0x54]) | 0x100;
    i_t2 = p_key[1] ^ p_sec[0x55];
    i_t3 = (p_key[2] | (p_key[3] << 8) |
           (p_key[4] << 16)) ^ (p_sec[0x56] |
           (p_sec[0x57] << 8) | (p_sec[0x58] << 16));
    i_t4 = i_t3 & 7;
    i_t3 = i_t3 * 2 + 8 - i_t4;
    p_sec += 0x80;
    i_t5 = 0;

    while( p_sec != p_end )
    {
        i_t4 = p_css_tab2[i_t2] ^ p_css_tab3[i_t1];
        i_t2 = i_t1>>1;
        i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
        i_t4 = p_css_tab5[i_t4];
        i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
                                     i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
        i_t3 = (i_t3 << 8 ) | i_t6;
        i_t6 = p_css_tab4[i_t6];
        i_t5 += i_t6 + i_t4;
        *p_sec = p_css_tab1[*p_sec] ^ ( i_t5 & 0xff );
        p_sec++;
        i_t5 >>= 8;
    }

    return 0;
}
Sam Hocevar's avatar
 
Sam Hocevar committed
589

590
591
592
/* Following functions are local */

/*****************************************************************************
593
 * GetBusKey: Go through the Content Scrambling System (CSS) authentication process
594
595
596
597
 *****************************************************************************
 * It simulates the mutual authentication between logical unit and host,
 * and stops when a session key (called bus key) has been established.
 * Always do the full auth sequence. Some drives seem to lie and always
598
 * respond with ASF=1. For instance the old DVD-ROMs on Compaq Armada say
599
600
601
602
603
604
 * that ASF=1 from the start and then later fail with a 'read of scrambled
 * block without authentication' error.
 *****************************************************************************/
static int GetBusKey( dvdcss_t dvdcss )
{
    uint8_t   p_buffer[10];
605
    uint8_t   p_challenge[2 * DVD_KEY_SIZE];
606
607
608
    dvd_key   p_key1;
    dvd_key   p_key2;
    dvd_key   p_key_check;
609
610
611
612
    uint8_t   i_variant = 0;
    int       i_ret = -1;
    int       i;

613
    print_debug( dvdcss, "requesting authentication grant ID (AGID)" );
614
615
616
    i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );

    /* We might have to reset hung authentication processes in the drive
617
618
619
     * by invalidating the corresponding authentication grant ID (AGID)'.
     * As long as we haven't got an AGID, invalidate one (in sequence)
     * and try again. */
620
621
    for( i = 0; i_ret == -1 && i < 4 ; ++i )
    {
622
623
        print_debug( dvdcss, "ioctl ReportAgid failed, invalidating "
                             "authentication grant ID (AGID) %d", i );
624
625
626
627
628
629
630

        /* This is really _not good_, should be handled by the OS.
         * Invalidating an AGID could make another process fail somewhere
         * in its authentication process. */
        dvdcss->css.i_agid = i;
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );

631
        print_debug( dvdcss, "requesting authentication grant ID (AGID)" );
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
        i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
    }

    /* Unable to authenticate without AGID */
    if( i_ret == -1 )
    {
        print_error( dvdcss, "ioctl ReportAgid failed, fatal" );
        return -1;
    }

    /* Setup a challenge, any values should work */
    for( i = 0 ; i < 10; ++i )
    {
        p_challenge[i] = i;
    }

    /* Get challenge from host */
    for( i = 0 ; i < 10 ; ++i )
    {
        p_buffer[9-i] = p_challenge[i];
    }

    /* Send challenge to LU */
    if( ioctl_SendChallenge( dvdcss->i_fd,
                             &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
        print_error( dvdcss, "ioctl SendChallenge failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Get key1 from LU */
    if( ioctl_ReportKey1( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0)
    {
        print_error( dvdcss, "ioctl ReportKey1 failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Send key1 to host */
672
    for( i = 0 ; i < DVD_KEY_SIZE ; i++ )
673
674
675
676
677
678
679
680
    {
        p_key1[i] = p_buffer[4-i];
    }

    for( i = 0 ; i < 32 ; ++i )
    {
        CryptKey( 0, i, p_challenge, p_key_check );

681
        if( memcmp( p_key_check, p_key1, DVD_KEY_SIZE ) == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
682
        {
683
684
685
            print_debug( dvdcss, "drive authenticated, using variant %d", i );
            i_variant = i;
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
686
687
688
        }
    }

689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
    if( i == 32 )
    {
        print_error( dvdcss, "drive would not authenticate" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Get challenge from LU */
    if( ioctl_ReportChallenge( dvdcss->i_fd,
                               &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
        print_error( dvdcss, "ioctl ReportKeyChallenge failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* Send challenge to host */
    for( i = 0 ; i < 10 ; ++i )
    {
        p_challenge[i] = p_buffer[9-i];
    }

    CryptKey( 1, i_variant, p_challenge, p_key2 );

    /* Get key2 from host */
714
    for( i = 0 ; i < DVD_KEY_SIZE ; ++i )
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
    {
        p_buffer[4-i] = p_key2[i];
    }

    /* Send key2 to LU */
    if( ioctl_SendKey2( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer ) < 0 )
    {
        print_error( dvdcss, "ioctl SendKey2 failed" );
        ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid );
        return -1;
    }

    /* The drive has accepted us as authentic. */
    print_debug( dvdcss, "authentication established" );

730
731
    memcpy( p_challenge, p_key1, DVD_KEY_SIZE );
    memcpy( p_challenge + DVD_KEY_SIZE, p_key2, DVD_KEY_SIZE );
732
733
734

    CryptKey( 2, i_variant, p_challenge, dvdcss->css.p_bus_key );

Sam Hocevar's avatar
 
Sam Hocevar committed
735
736
737
    return 0;
}

738
/*****************************************************************************
739
 * PrintKey: debug function that dumps a key value
740
 *****************************************************************************/
741
static void PrintKey( dvdcss_t dvdcss, const char *prefix, const uint8_t *data )
742
743
744
745
{
    print_debug( dvdcss, "%s%02x:%02x:%02x:%02x:%02x", prefix,
                 data[0], data[1], data[2], data[3], data[4] );
}
Sam Hocevar's avatar
 
Sam Hocevar committed
746
747

/*****************************************************************************
748
 * GetASF: Get authentication success flag (ASF)
Sam Hocevar's avatar
 
Sam Hocevar committed
749
 *****************************************************************************
750
 * Returns:
Sam Hocevar's avatar
 
Sam Hocevar committed
751
752
753
754
 *  -1 on ioctl error,
 *  0 if the device needs to be authenticated,
 *  1 either.
 *****************************************************************************/
755
static int GetASF( dvdcss_t dvdcss )
Sam Hocevar's avatar
 
Sam Hocevar committed
756
757
758
{
    int i_asf = 0;

759
    if( ioctl_ReportASF( dvdcss->i_fd, &i_asf ) != 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
760
    {
761
        /* The ioctl process has failed */
762
        print_error( dvdcss, "GetASF fatal error" );
763
764
        return -1;
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
765

766
767
    if( i_asf )
    {
768
        print_debug( dvdcss, "authentication success flag set, ASF=1" );
769
770
771
    }
    else
    {
772
        print_debug( dvdcss, "authentication success flag not set, ASF=0" );
Sam Hocevar's avatar
 
Sam Hocevar committed
773
774
    }

775
    return i_asf;
Sam Hocevar's avatar
 
Sam Hocevar committed
776
777
778
}

/*****************************************************************************
779
 * CryptKey: shuffle bits and decrypt keys.
Sam Hocevar's avatar
 
Sam Hocevar committed
780
 *****************************************************************************
781
 * Used during authentication and disc key negotiation in GetBusKey.
782
783
 * i_key_type: 0->key1, 1->key2, 2->buskey.
 * i_variant: between 0 and 31.
Sam Hocevar's avatar
 
Sam Hocevar committed
784
 *****************************************************************************/
785
static void CryptKey( int i_key_type, int i_variant,
786
                      const uint8_t *p_challenge, uint8_t *p_key )
Sam Hocevar's avatar
 
Sam Hocevar committed
787
788
{
    /* Permutation table for challenge */
789
    static const uint8_t pp_perm_challenge[3][10] =
Sam Hocevar's avatar
 
Sam Hocevar committed
790
791
792
793
            { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 },
              { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 },
              { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } };

794
    /* Permutation table for variant table for key2 and buskey */
795
    static const uint8_t pp_perm_variant[2][32] =
Sam Hocevar's avatar
 
Sam Hocevar committed
796
797
798
799
800
801
802
803
804
            { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d,
                0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d,
                0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05,
                0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 },
              { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e,
                0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c,
                0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f,
                0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } };

805
    static const uint8_t p_variants[32] =
Sam Hocevar's avatar
 
Sam Hocevar committed
806
807
808
809
810
811
            {   0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73,
                0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42,
                0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B,
                0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 };

    /* The "secret" key */
812
    static const uint8_t p_secret[5] = { 0x55, 0xD6, 0xC4, 0xC5, 0x28 };
813
814
815
816
817
818
819
820
821
822

    uint8_t p_bits[30], p_scratch[10], p_tmp1[5], p_tmp2[5];
    uint8_t i_lfsr0_o;  /* 1 bit used */
    uint8_t i_lfsr1_o;  /* 1 bit used */
    uint8_t i_css_variant, i_cse, i_index, i_combined, i_carry;
    uint8_t i_val = 0;
    uint32_t i_lfsr0, i_lfsr1;
    int i_term = 0;
    int i_bit;
    int i;
Sam Hocevar's avatar
 
Sam Hocevar committed
823
824
825
826

    for (i = 9; i >= 0; --i)
        p_scratch[i] = p_challenge[pp_perm_challenge[i_key_type][i]];

827
828
    i_css_variant = ( i_key_type == 0 ) ? i_variant :
                    pp_perm_variant[i_key_type-1][i_variant];
Sam Hocevar's avatar
 
Sam Hocevar committed
829
830
831
832

    /*
     * This encryption engine implements one of 32 variations
     * one the same theme depending upon the choice in the
833
     * variant parameter (0 - 31).
Sam Hocevar's avatar
 
Sam Hocevar committed
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
     *
     * The algorithm itself manipulates a 40 bit input into
     * a 40 bit output.
     * The parameter 'input' is 80 bits.  It consists of
     * the 40 bit input value that is to be encrypted followed
     * by a 40 bit seed value for the pseudo random number
     * generators.
     */

    /* Feed the secret into the input values such that
     * we alter the seed to the LFSR's used above,  then
     * generate the bits to play with.
     */
    for( i = 5 ; --i >= 0 ; )
    {
        p_tmp1[i] = p_scratch[5 + i] ^ p_secret[i] ^ p_crypt_tab2[i];
    }

    /*
     * We use two LFSR's (seeded from some of the input data bytes) to
     * generate two streams of pseudo-random bits.  These two bit streams
     * are then combined by simply adding with carry to generate a final
     * sequence of pseudo-random bits which is stored in the buffer that
     * 'output' points to the end of - len is the size of this buffer.
     *
     * The first LFSR is of degree 25,  and has a polynomial of:
     * x^13 + x^5 + x^4 + x^1 + 1
     *
862
     * The second LFSR is of degree 17,  and has a (primitive) polynomial of:
Sam Hocevar's avatar
 
Sam Hocevar committed
863
864
865
866
867
868
869
870
871
872
873
     * x^15 + x^1 + 1
     *
     * I don't know if these polynomials are primitive modulo 2,  and thus
     * represent maximal-period LFSR's.
     *
     *
     * Note that we take the output of each LFSR from the new shifted in
     * bit,  not the old shifted out bit.  Thus for ease of use the LFSR's
     * are implemented in bit reversed order.
     *
     */
874

Sam Hocevar's avatar
 
Sam Hocevar committed
875
    /* In order to ensure that the LFSR works we need to ensure that the
876
     * initial values are non-zero.  Thus when we initialize them from
Sam Hocevar's avatar
 
Sam Hocevar committed
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
     * the seed,  we ensure that a bit is set.
     */
    i_lfsr0 = ( p_tmp1[0] << 17 ) | ( p_tmp1[1] << 9 ) |
              (( p_tmp1[2] & ~7 ) << 1 ) | 8 | ( p_tmp1[2] & 7 );
    i_lfsr1 = ( p_tmp1[3] << 9 ) | 0x100 | p_tmp1[4];

    i_index = sizeof(p_bits);
    i_carry = 0;

    do
    {
        for( i_bit = 0, i_val = 0 ; i_bit < 8 ; ++i_bit )
        {

            i_lfsr0_o = ( ( i_lfsr0 >> 24 ) ^ ( i_lfsr0 >> 21 ) ^
                        ( i_lfsr0 >> 20 ) ^ ( i_lfsr0 >> 12 ) ) & 1;
            i_lfsr0 = ( i_lfsr0 << 1 ) | i_lfsr0_o;

            i_lfsr1_o = ( ( i_lfsr1 >> 16 ) ^ ( i_lfsr1 >> 2 ) ) & 1;
            i_lfsr1 = ( i_lfsr1 << 1 ) | i_lfsr1_o;

            i_combined = !i_lfsr1_o + i_carry + !i_lfsr0_o;
            /* taking bit 1 */
            i_carry = ( i_combined >> 1 ) & 1;
            i_val |= ( i_combined & 1 ) << i_bit;
        }
903

Sam Hocevar's avatar
 
Sam Hocevar committed
904
905
906
907
908
909
910
        p_bits[--i_index] = i_val;
    } while( i_index > 0 );

    /* This term is used throughout the following to
     * select one of 32 different variations on the
     * algorithm.
     */
911
    i_cse = p_variants[i_css_variant] ^ p_crypt_tab2[i_css_variant];
Sam Hocevar's avatar
 
Sam Hocevar committed
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977

    /* Now the actual blocks doing the encryption.  Each
     * of these works on 40 bits at a time and are quite
     * similar.
     */
    i_index = 0;
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_scratch[i] )
    {
        i_index = p_bits[25 + i] ^ p_scratch[i];
        i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;

        p_tmp1[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
    }
    p_tmp1[4] ^= p_tmp1[0];

    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
    {
        i_index = p_bits[20 + i] ^ p_tmp1[i];
        i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;

        p_tmp2[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
    }
    p_tmp2[4] ^= p_tmp2[0];

    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] )
    {
        i_index = p_bits[15 + i] ^ p_tmp2[i];
        i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;
        i_index = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;

        p_tmp1[i] = p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index];
    }
    p_tmp1[4] ^= p_tmp1[0];

    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
    {
        i_index = p_bits[10 + i] ^ p_tmp1[i];
        i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;

        i_index = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;

        p_tmp2[i] = p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index];
    }
    p_tmp2[4] ^= p_tmp2[0];

    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] )
    {
        i_index = p_bits[5 + i] ^ p_tmp2[i];
        i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;

        p_tmp1[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
    }
    p_tmp1[4] ^= p_tmp1[0];

    for(i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] )
    {
        i_index = p_bits[i] ^ p_tmp1[i];
        i_index = p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse;

        p_key[i] = p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term;
    }

    return;
}

/*****************************************************************************
978
 * DecryptKey: decrypt p_crypted with p_key.
Sam Hocevar's avatar
 
Sam Hocevar committed
979
 *****************************************************************************
980
 * Used to decrypt the disc key, with a player key, after requesting it
981
982
 * in dvdcss_disckey and to decrypt title keys, with a disc key, requested
 * in dvdcss_titlekey.
983
 * The player keys and the resulting disc key are only used as KEKs
984
 * (key encryption keys).
985
 * Decryption is slightly dependent on the type of key:
Sam Hocevar's avatar
 
Sam Hocevar committed
986
 *  -for disc key, invert is 0x00,
987
 *  -for title key, invert if 0xff.
Sam Hocevar's avatar
 
Sam Hocevar committed
988
 *****************************************************************************/
989
990
static void DecryptKey( uint8_t invert, const uint8_t *p_key,
                        const uint8_t *p_crypted, uint8_t *p_result )
Sam Hocevar's avatar
 
Sam Hocevar committed
991
992
993
994
995
{
    unsigned int    i_lfsr1_lo;
    unsigned int    i_lfsr1_hi;
    unsigned int    i_lfsr0;
    unsigned int    i_combined;
996
997
998
    uint8_t         o_lfsr0;
    uint8_t         o_lfsr1;
    uint8_t         k[5];
Sam Hocevar's avatar
 
Sam Hocevar committed
999
1000
    int             i;