dvd_css.c 24.8 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * dvd_css.c: Functions for DVD authentification and unscrambling
 *****************************************************************************
 * Copyright (C) 1999-2001 VideoLAN
5
 * $Id: dvd_css.c,v 1.29 2001/05/19 00:39:29 stef Exp $
6 7 8
 *
 * Author: Stphane Borel <stef@via.ecp.fr>
 *
9 10 11
 * based on:
 *  - css-auth by Derek Fawcus <derek@spider.com>
 *  - DVD CSS ioctls example program by Andrew T. Veliath <andrewtv@usa.net>
Sam Hocevar's avatar
 
Sam Hocevar committed
12
 *  - The Divide and conquer attack by Frank A. Stevenson <frank@funcom.com>
13 14 15 16
 *  - DeCSSPlus by Ethan Hawke
 *  - DecVOB
 *  see http://www.lemuria.org/DeCSS/ by Tom Vogt for more information.
 * 
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
35 36
#include "defs.h"

37
#include <stdio.h>
38
#include <stdlib.h>
39 40 41 42
#include <unistd.h>
#include <string.h>

#include "common.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
43

44
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
45

46
#include "dvd_css.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
47 48 49
#ifdef HAVE_CSS
#include "dvd_csstables.h"
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
50 51
#include "dvd_ioctl.h"

52
#include "input_dvd.h"
53 54

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
55
 * Local prototypes
56
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
57
#ifdef HAVE_CSS
Sam Hocevar's avatar
 
Sam Hocevar committed
58
static int  CSSGetASF    ( int i_fd );
Sam Hocevar's avatar
 
Sam Hocevar committed
59 60 61 62 63 64
static void CSSCryptKey  ( int i_key_type, int i_varient,
                           u8 const * pi_challenge, u8* pi_key );
static int  CSSCracker   ( int i_start, unsigned char * p_crypted,
                           unsigned char * p_decrypted,
                           dvd_key_t * p_sector_key, dvd_key_t * p_key );
#endif /* HAVE_CSS */
65 66

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
67
 * CSSTest : check if the disc is encrypted or not
68
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
69
int CSSTest( int i_fd )
70
{
Sam Hocevar's avatar
 
Sam Hocevar committed
71
    int i_ret, i_copyright;
72

Sam Hocevar's avatar
 
Sam Hocevar committed
73
    i_ret = ioctl_ReadCopyright( i_fd, 0 /* i_layer */, &i_copyright );
74

Sam Hocevar's avatar
 
Sam Hocevar committed
75
    if( i_ret < 0 )
76
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
77 78 79 80
        /* Since it's the first ioctl we try to issue, we add a notice */
        intf_ErrMsg( "css error: ioctl_ReadCopyright failed, "
                     "make sure DVD ioctls were compiled in" );

Sam Hocevar's avatar
 
Sam Hocevar committed
81
        return i_ret;
82
    }
83

Sam Hocevar's avatar
 
Sam Hocevar committed
84
    return i_copyright;
85 86 87
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
88 89 90 91 92
 * CSSInit : CSS Structure initialisation and DVD authentication.
 *****************************************************************************
 * It simulates the mutual authentication between logical unit and host.
 * Since we don't need the disc key to find the title key, we just run the
 * basic unavoidable commands to authenticate device and disc.
93
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
94
int CSSInit( int i_fd, css_t * p_css )
95
{
Sam Hocevar's avatar
 
Sam Hocevar committed
96 97
#ifdef HAVE_CSS
    /* structures defined in cdrom.h or dvdio.h */
Sam Hocevar's avatar
 
Sam Hocevar committed
98
    char p_buffer[2048 + 4 + 1];
Sam Hocevar's avatar
 
Sam Hocevar committed
99
    int  i_agid = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
100 101
    int  i_ret = -1;
    int  i;
102

Sam Hocevar's avatar
 
Sam Hocevar committed
103
    /* Test authentication success */
Sam Hocevar's avatar
 
Sam Hocevar committed
104
    switch( CSSGetASF( i_fd ) )
105
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
106 107
        case -1:
            return -1;
108

Sam Hocevar's avatar
 
Sam Hocevar committed
109
        case 1:
110
            intf_WarnMsg( 2, "css info: already authenticated" );
Sam Hocevar's avatar
 
Sam Hocevar committed
111
            return 0;
112

Sam Hocevar's avatar
 
Sam Hocevar committed
113
        case 0:
114
            intf_WarnMsg( 2, "css info: need to authenticate" );
115 116
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
117 118
    /* Init sequence, request AGID */
    for( i = 1; i < 4 ; ++i )
119
    {
120
        intf_WarnMsg( 2, "css info: requesting AGID %d", i );
Sam Hocevar's avatar
 
Sam Hocevar committed
121

Sam Hocevar's avatar
 
Sam Hocevar committed
122
        i_ret = ioctl_ReportAgid( i_fd, &i_agid );
Sam Hocevar's avatar
 
Sam Hocevar committed
123 124

        if( i_ret != -1 )
125
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
126
            /* No error during ioctl: we know the device is authenticated */
Sam Hocevar's avatar
 
Sam Hocevar committed
127
            break;
128
        }
129

Sam Hocevar's avatar
 
Sam Hocevar committed
130
        intf_ErrMsg( "css error: ioctl_ReportAgid failed, invalidating" );
Sam Hocevar's avatar
 
Sam Hocevar committed
131

Sam Hocevar's avatar
 
Sam Hocevar committed
132 133
        i_agid = 0;
        ioctl_InvalidateAgid( i_fd, &i_agid );
Sam Hocevar's avatar
 
Sam Hocevar committed
134
    }
135

Sam Hocevar's avatar
 
Sam Hocevar committed
136
    /* Unable to authenticate without AGID */
Sam Hocevar's avatar
 
Sam Hocevar committed
137
    if( i_ret == -1 )
138
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
139
        intf_ErrMsg( "css error: ioctl_ReportAgid failed, fatal" );
Sam Hocevar's avatar
 
Sam Hocevar committed
140
        return -1;
141
    }
142

Sam Hocevar's avatar
 
Sam Hocevar committed
143
    for( i = 0 ; i < 10; ++i )
144
    {
145
        p_css->disc.pi_challenge[i] = i;
146
    }
147

Sam Hocevar's avatar
 
Sam Hocevar committed
148 149 150
    /* Get challenge from host */
    for( i = 0 ; i < 10 ; ++i )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
151
        p_buffer[9-i] = p_css->disc.pi_challenge[i];
152
    }
153

Sam Hocevar's avatar
 
Sam Hocevar committed
154
    /* Send challenge to LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
155
    if( ioctl_SendChallenge( i_fd, &i_agid, p_buffer ) < 0 )
156
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
157
        intf_ErrMsg( "css error: ioctl_SendChallenge failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
158
        return -1;
159
    }
160

Sam Hocevar's avatar
 
Sam Hocevar committed
161
    /* Get key1 from LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
162
    if( ioctl_ReportKey1( i_fd, &i_agid, p_buffer ) < 0)
163
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
164
        intf_ErrMsg( "css error: ioctl_ReportKey1 failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
165
        return -1;
166
    }
167

Sam Hocevar's avatar
 
Sam Hocevar committed
168 169
    /* Send key1 to host */
    for( i = 0 ; i < KEY_SIZE ; i++ )
170
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
171
        p_css->disc.pi_key1[i] = p_buffer[4-i];
172 173 174 175
    }

    for( i = 0 ; i < 32 ; ++i )
    {
176 177
        CSSCryptKey( 0, i, p_css->disc.pi_challenge,
                           p_css->disc.pi_key_check );
178

179 180
        if( memcmp( p_css->disc.pi_key_check,
                    p_css->disc.pi_key1, KEY_SIZE ) == 0 )
181
        {
182
            intf_WarnMsg( 2, "css info: drive authentic, using variant %d", i);
183
            p_css->disc.i_varient = i;
184 185 186 187 188 189
            break;
        }
    }

    if( i == 32 )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
190
        intf_ErrMsg( "css error: drive would not authenticate" );
Sam Hocevar's avatar
 
Sam Hocevar committed
191
        return -1;
192
    }
193 194

    /* Get challenge from LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
195
    if( ioctl_ReportChallenge( i_fd, &i_agid, p_buffer ) < 0 )
196
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
197
        intf_ErrMsg( "css error: ioctl_ReportKeyChallenge failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
198
        return -1;
199 200
    }

201
    /* Send challenge to host */
202
    for( i = 0 ; i < 10 ; ++i )
203
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
204
        p_css->disc.pi_challenge[i] = p_buffer[9-i];
205 206
    }

207
    CSSCryptKey( 1, p_css->disc.i_varient, p_css->disc.pi_challenge,
Sam Hocevar's avatar
 
Sam Hocevar committed
208
                                               p_css->disc.pi_key2 );
209

210
    /* Get key2 from host */
211
    for( i = 0 ; i < KEY_SIZE ; ++i )
212
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
213
        p_buffer[4-i] = p_css->disc.pi_key2[i];
214
    }
215

216
    /* Send key2 to LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
217
    if( ioctl_SendKey2( i_fd, &i_agid, p_buffer ) < 0 )
218
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
219
        intf_ErrMsg( "css error: ioctl_SendKey2 failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
220
        return -1;
221
    }
222

223
    intf_WarnMsg( 2, "css info: authentication established" );
224

225 226
    memcpy( p_css->disc.pi_challenge, p_css->disc.pi_key1, KEY_SIZE );
    memcpy( p_css->disc.pi_challenge+KEY_SIZE, p_css->disc.pi_key2, KEY_SIZE );
Sam Hocevar's avatar
 
Sam Hocevar committed
227

Sam Hocevar's avatar
 
Sam Hocevar committed
228
    CSSCryptKey( 2, p_css->disc.i_varient, p_css->disc.pi_challenge,
Sam Hocevar's avatar
 
Sam Hocevar committed
229
                                           p_css->disc.pi_key_check );
230

231
    intf_WarnMsg( 2, "css info: received session key" );
232

Sam Hocevar's avatar
 
Sam Hocevar committed
233
    if( i_agid < 0 )
234
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
235
        return -1;
236
    }
237

238
    /* Test authentication success */
Sam Hocevar's avatar
 
Sam Hocevar committed
239
    switch( CSSGetASF( i_fd ) )
240
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
241 242 243 244
        case -1:
            return -1;

        case 1:
245
            intf_WarnMsg( 2, "css info: already authenticated" );
Sam Hocevar's avatar
 
Sam Hocevar committed
246 247 248
            return 0;

        case 0:
249
            intf_WarnMsg( 2, "css info: need to get disc key" );
250
    }
251

252
    /* Get encrypted disc key */
Sam Hocevar's avatar
 
Sam Hocevar committed
253
    if( ioctl_ReadKey( i_fd, &i_agid, p_buffer ) < 0 )
254
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
255
        intf_ErrMsg( "css error: ioctl_ReadKey failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
256
        return -1;
257
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
258

259
    /* Unencrypt disc key using bus key */
Sam Hocevar's avatar
 
Sam Hocevar committed
260
    for( i = 0 ; i < 2048 ; i++ )
261
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
262
        p_buffer[ i ] ^= p_css->disc.pi_key_check[ 4 - (i % KEY_SIZE) ];
263
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
264 265
    memcpy( p_css->disc.pi_key_check, p_buffer, 2048 );

266 267 268 269 270 271
    /* initialize title key to know it empty */
    for( i = 0 ; i < KEY_SIZE ; i++ )
    {
        p_css->pi_title_key[i] = 0;
    }

272
    /* Test authentication success */
Sam Hocevar's avatar
 
Sam Hocevar committed
273
    switch( CSSGetASF( i_fd ) )
274
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
275 276 277 278
        case -1:
            return -1;

        case 1:
279
            intf_WarnMsg( 2, "css info: successfully authenticated" );
Sam Hocevar's avatar
 
Sam Hocevar committed
280
            return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
281

Sam Hocevar's avatar
 
Sam Hocevar committed
282
        case 0:
283 284
            intf_ErrMsg( "css error: no way to authenticate" );
            return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
285
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
286

Sam Hocevar's avatar
 
Sam Hocevar committed
287 288 289
#else /* HAVE_CSS */
    intf_ErrMsg( "css error: CSS decryption is disabled in this module" );

Sam Hocevar's avatar
 
Sam Hocevar committed
290
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
291 292
    return -1;

293 294
}

295
/*****************************************************************************
Stéphane Borel's avatar
 
Stéphane Borel committed
296
 * CSSGetKey : get title key.
Sam Hocevar's avatar
 
Sam Hocevar committed
297
 *****************************************************************************
298
 * The DVD should have been opened and authenticated before.
299
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
300
int CSSGetKey( int i_fd, css_t * p_css )
301
{
Sam Hocevar's avatar
 
Sam Hocevar committed
302
#ifdef HAVE_CSS
303 304 305 306
    /*
     * Title key cracking method from Ethan Hawke,
     * with Frank A. Stevenson algorithm.
     * Does not use any player key table and ioctls.
307
     */
Stéphane Borel's avatar
 
Stéphane Borel committed
308 309
    u8          pi_buf[0x800];
    dvd_key_t   pi_key;
310 311 312
    off_t       i_pos;
    boolean_t   b_encrypted;
    boolean_t   b_stop_scanning;
313 314 315
    int         i_bytes_read;
    int         i_best_plen;
    int         i_best_p;
316 317 318 319 320 321
    int         i,j;

    for( i = 0 ; i < KEY_SIZE ; i++ )
    {
        pi_key[i] = 0;
    }
322

Stéphane Borel's avatar
 
Stéphane Borel committed
323 324 325 326 327
    b_encrypted = 0;
    b_stop_scanning = 0;

    /* Position of the title on the disc */
    i_pos = p_css->i_title_pos;
328

Stéphane Borel's avatar
 
Stéphane Borel committed
329
    do {
Sam Hocevar's avatar
 
Sam Hocevar committed
330 331
    i_pos = lseek( i_fd, i_pos, SEEK_SET );
    i_bytes_read = read( i_fd, pi_buf, 0x800 );
332

Stéphane Borel's avatar
 
Stéphane Borel committed
333 334 335 336 337 338
    /* PES_scrambling_control */
    if( pi_buf[0x14] & 0x30 )
    {
        b_encrypted = 1;
        i_best_plen = 0;
        i_best_p = 0;
339

Stéphane Borel's avatar
 
Stéphane Borel committed
340 341 342 343
        for( i = 2 ; i < 0x30 ; i++ )
        {
            for( j = i ; ( j < 0x80 ) &&
                   ( pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j] ) ; j++ );
344
            {
Stéphane Borel's avatar
 
Stéphane Borel committed
345
                if( ( j > i_best_plen ) && ( j > i ) )
346
                {
Stéphane Borel's avatar
 
Stéphane Borel committed
347 348
                    i_best_plen = j;
                    i_best_p = i;
349
                }
350
            }
Stéphane Borel's avatar
 
Stéphane Borel committed
351
        }
352

Stéphane Borel's avatar
 
Stéphane Borel committed
353 354 355 356 357 358
        if( ( i_best_plen > 20 ) && ( i_best_plen / i_best_p >= 2) )
        {
            i = CSSCracker( 0,  &pi_buf[0x80],
                    &pi_buf[0x80 - ( i_best_plen / i_best_p) *i_best_p],
                    (dvd_key_t*)&pi_buf[0x54],
                    &pi_key );
359
            b_stop_scanning = ( i >= 0 );
Sam Hocevar's avatar
 
Sam Hocevar committed
360 361 362 363 364 365 366 367
        }
    }

    i_pos += i_bytes_read;
    } while( i_bytes_read == 0x800 && !b_stop_scanning);

    if( b_stop_scanning)
    {
368 369 370 371
            memcpy( p_css->pi_title_key,
                    &pi_key, sizeof(dvd_key_t) );
        intf_WarnMsg( 2, "css info: vts key initialized" );
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
372 373 374 375
    }

    if( !b_encrypted )
    {
376
        intf_WarnMsg( 2, "css warning: this file was _NOT_ encrypted!" );
377
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
378 379
    }

380
    return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
381

Sam Hocevar's avatar
 
Sam Hocevar committed
382
#else /* HAVE_CSS */
383 384
    intf_ErrMsg( "css error: css decryption unavailable" );
    return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
385

Sam Hocevar's avatar
 
Sam Hocevar committed
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
#endif /* HAVE_CSS */
}

/*****************************************************************************
 * CSSDescrambleSector
 *****************************************************************************
 * sec : sector to descramble
 * key : title key for this sector
 *****************************************************************************/
int CSSDescrambleSector( dvd_key_t pi_key, u8* pi_sec )
{
#ifdef HAVE_CSS
    unsigned int    i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
    u8*             pi_end = pi_sec + 0x800;

    /* PES_scrambling_control */
    if( pi_sec[0x14] & 0x30)
    {
        i_t1 = ((pi_key)[0] ^ pi_sec[0x54]) | 0x100;
        i_t2 = (pi_key)[1] ^ pi_sec[0x55];
        i_t3 = (((pi_key)[2]) | ((pi_key)[3] << 8) |
               ((pi_key)[4] << 16)) ^ ((pi_sec[0x56]) |
               (pi_sec[0x57] << 8) | (pi_sec[0x58] << 16));
        i_t4 = i_t3 & 7;
        i_t3 = i_t3 * 2 + 8 - i_t4;
        pi_sec += 0x80;
        i_t5 = 0;

        while( pi_sec != pi_end )
        {
            i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
            i_t2 = i_t1>>1;
            i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
            i_t4 = pi_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 = pi_css_tab4[i_t6];
            i_t5 += i_t6 + i_t4;
Sam Hocevar's avatar
 
Sam Hocevar committed
425 426
            *pi_sec = pi_css_tab1[*pi_sec] ^( i_t5 & 0xff );
            pi_sec++;
Sam Hocevar's avatar
 
Sam Hocevar committed
427 428 429 430 431
            i_t5 >>= 8;
        }
    }

    return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
432

Sam Hocevar's avatar
 
Sam Hocevar committed
433 434
#else /* HAVE_CSS */
    return 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
435

Sam Hocevar's avatar
 
Sam Hocevar committed
436 437 438 439
#endif /* HAVE_CSS */
}

#ifdef HAVE_CSS
Sam Hocevar's avatar
 
Sam Hocevar committed
440 441

/* Following functions are local */
Sam Hocevar's avatar
 
Sam Hocevar committed
442 443 444 445 446 447 448 449 450

/*****************************************************************************
 * CSSGetASF : Get Authentification success flag
 *****************************************************************************
 * Returns :
 *  -1 on ioctl error,
 *  0 if the device needs to be authenticated,
 *  1 either.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
451
static int CSSGetASF( int i_fd )
Sam Hocevar's avatar
 
Sam Hocevar committed
452
{
Sam Hocevar's avatar
 
Sam Hocevar committed
453 454
    int i_agid;
    int i_asf = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
455

Sam Hocevar's avatar
 
Sam Hocevar committed
456
    for( i_agid = 0 ; i_agid < 4 ; i_agid++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
457
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
458
        if( ioctl_ReportASF( i_fd, &i_agid, &i_asf ) == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
459
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
460 461
            intf_WarnMsg( 3, "css info: GetASF %sauthenticated",
                          i_asf ? "":"not " );
Sam Hocevar's avatar
 
Sam Hocevar committed
462 463

            return i_asf;
Sam Hocevar's avatar
 
Sam Hocevar committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 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 589 590 591 592 593 594 595
        }
    }

    /* The ioctl process has failed */
    intf_ErrMsg( "css error: GetASF fatal error" );
    return -1;
}

/*****************************************************************************
 * CSSCryptKey : shuffles bits and unencrypt keys.
 *****************************************************************************
 * Used during authentication and disc key negociation in CSSInit.
 * i_key_type : 0->key1, 1->key2, 2->buskey.
 * i_varient : between 0 and 31.
 *****************************************************************************/
static void CSSCryptKey( int i_key_type, int i_varient,
                         u8 const * pi_challenge, u8* pi_key )
{
    /* Permutation table for challenge */
    u8      ppi_perm_challenge[3][10] =
            { { 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 } };

    /* Permutation table for varient table for key2 and buskey */
    u8      ppi_perm_varient[2][32] =
            { { 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 } };

    u8      pi_varients[32] =
            {   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 */
    u8      pi_secret[5] = { 0x55, 0xD6, 0xC4, 0xC5, 0x28 };

    u8      pi_bits[30];
    u8      pi_scratch[10];
    u8      pi_tmp1[5];
    u8      pi_tmp2[5];
    u8      i_lfsr0_o;  /* 1 bit used */
    u8      i_lfsr1_o;  /* 1 bit used */
    u32     i_lfsr0;
    u32     i_lfsr1;
    u8      i_css_varient;
    u8      i_cse;
    u8      i_index;
    u8      i_combined;
    u8      i_carry;
    u8      i_val = 0;
    int     i_term = 0;
    int     i_bit;
    int     i;

    for (i = 9; i >= 0; --i)
        pi_scratch[i] = pi_challenge[ppi_perm_challenge[i_key_type][i]];

    i_css_varient = ( i_key_type == 0 ) ? i_varient :
                    ppi_perm_varient[i_key_type-1][i_varient];

    /*
     * This encryption engine implements one of 32 variations
     * one the same theme depending upon the choice in the
     * varient parameter (0 - 31).
     *
     * 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 ; )
    {
        pi_tmp1[i] = pi_scratch[5 + i] ^ pi_secret[i] ^ pi_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
     *
     * The second LSFR is of degree 17,  and has a (primitive) polynomial of:
     * 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.
     *
     */
    
    /* In order to ensure that the LFSR works we need to ensure that the
     * initial values are non-zero.  Thus when we initialise them from
     * the seed,  we ensure that a bit is set.
     */
    i_lfsr0 = ( pi_tmp1[0] << 17 ) | ( pi_tmp1[1] << 9 ) |
              (( pi_tmp1[2] & ~7 ) << 1 ) | 8 | ( pi_tmp1[2] & 7 );
    i_lfsr1 = ( pi_tmp1[3] << 9 ) | 0x100 | pi_tmp1[4];

    i_index = sizeof(pi_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;
Stéphane Borel's avatar
 
Stéphane Borel committed
596

Sam Hocevar's avatar
 
Sam Hocevar committed
597 598 599 600 601 602 603
            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;
604
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
605 606 607
    
        pi_bits[--i_index] = i_val;
    } while( i_index > 0 );
608

Sam Hocevar's avatar
 
Sam Hocevar committed
609 610 611 612 613
    /* This term is used throughout the following to
     * select one of 32 different variations on the
     * algorithm.
     */
    i_cse = pi_varients[i_css_varient] ^ pi_crypt_tab2[i_css_varient];
614

Sam Hocevar's avatar
 
Sam Hocevar committed
615 616 617 618 619 620
    /* 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 = pi_scratch[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
621
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
622 623 624 625
        i_index = pi_bits[25 + i] ^ pi_scratch[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;

        pi_tmp1[i] = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
Stéphane Borel's avatar
 
Stéphane Borel committed
626
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
627
    pi_tmp1[4] ^= pi_tmp1[0];
628

Sam Hocevar's avatar
 
Sam Hocevar committed
629
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
630
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
631 632 633 634
        i_index = pi_bits[20 + i] ^ pi_tmp1[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;

        pi_tmp2[i] = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
Stéphane Borel's avatar
 
Stéphane Borel committed
635
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
636
    pi_tmp2[4] ^= pi_tmp2[0];
637

Sam Hocevar's avatar
 
Sam Hocevar committed
638
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
639
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
640 641 642 643 644
        i_index = pi_bits[15 + i] ^ pi_tmp2[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;
        i_index = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;

        pi_tmp1[i] = pi_crypt_tab0[i_index] ^ pi_crypt_tab2[i_index];
Stéphane Borel's avatar
 
Stéphane Borel committed
645
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
646
    pi_tmp1[4] ^= pi_tmp1[0];
647

Sam Hocevar's avatar
 
Sam Hocevar committed
648
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
649
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
650 651
        i_index = pi_bits[10 + i] ^ pi_tmp1[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;
652

Sam Hocevar's avatar
 
Sam Hocevar committed
653
        i_index = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
654

Sam Hocevar's avatar
 
Sam Hocevar committed
655
        pi_tmp2[i] = pi_crypt_tab0[i_index] ^ pi_crypt_tab2[i_index];
Stéphane Borel's avatar
 
Stéphane Borel committed
656
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
657
    pi_tmp2[4] ^= pi_tmp2[0];
658

Sam Hocevar's avatar
 
Sam Hocevar committed
659
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
660
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
661 662
        i_index = pi_bits[5 + i] ^ pi_tmp2[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;
663

Sam Hocevar's avatar
 
Sam Hocevar committed
664 665 666
        pi_tmp1[i] = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
    }
    pi_tmp1[4] ^= pi_tmp1[0];
667

Sam Hocevar's avatar
 
Sam Hocevar committed
668 669 670 671
    for(i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
    {
        i_index = pi_bits[i] ^ pi_tmp1[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;
Stéphane Borel's avatar
 
Stéphane Borel committed
672

Sam Hocevar's avatar
 
Sam Hocevar committed
673 674
        pi_key[i] = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
    }
675

Sam Hocevar's avatar
 
Sam Hocevar committed
676
    return;
677 678 679
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
680 681 682
 * CSSCracker : title key decryption by cracking
 *****************************************************************************
 * This function is called by CSSGetKeys to find a key
683
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
684 685 686 687 688
static int CSSCracker( int i_start,
                       unsigned char * p_crypted,
                       unsigned char * p_decrypted,
                       dvd_key_t * p_sector_key,
                       dvd_key_t * p_key )
689
{
Sam Hocevar's avatar
 
Sam Hocevar committed
690 691 692 693 694 695
    unsigned char pi_buffer[10];
    unsigned int i_t1, i_t2, i_t3, i_t4, i_t5, i_t6;
    unsigned int i_try;
    unsigned int i_candidate;
    unsigned int i, j;
    int i_exit = -1;
696

Sam Hocevar's avatar
 
Sam Hocevar committed
697 698

    for( i = 0 ; i < 10 ; i++ )
699
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
700 701 702 703 704 705 706 707
        pi_buffer[i] = pi_css_tab1[p_crypted[i]] ^ p_decrypted[i];
    }

    for( i_try = i_start ; i_try < 0x10000 ; i_try++ )
    {
        i_t1 = i_try >> 8 | 0x100;
        i_t2 = i_try & 0xff;
        i_t3 = 0;               /* not needed */
708 709
        i_t5 = 0;

Sam Hocevar's avatar
 
Sam Hocevar committed
710 711
        /* iterate cipher 4 times to reconstruct LFSR2 */
        for( i = 0 ; i < 4 ; i++ )
712
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
713
            /* advance LFSR1 normaly */
714
            i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
Sam Hocevar's avatar
 
Sam Hocevar committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
            i_t2 = i_t1 >> 1;
            i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
            i_t4 = pi_css_tab5[i_t4];
            /* deduce i_t6 & i_t5 */
            i_t6 = pi_buffer[i];
            if( i_t5 )
            {
                i_t6 = ( i_t6 + 0xff ) & 0x0ff;
            }
            if( i_t6 < i_t4 )
            {
                i_t6 += 0x100;
            }
            i_t6 -= i_t4;
            i_t5 += i_t6 + i_t4;
            i_t6 = pi_css_tab4[ i_t6 ];
            /* feed / advance i_t3 / i_t5 */
            i_t3 = ( i_t3 << 8 ) | i_t6;
            i_t5 >>= 8;
        }

        i_candidate = i_t3;

        /* iterate 6 more times to validate candidate key */
        for( ; i < 10 ; i++ )
        {
            i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
            i_t2 = i_t1 >> 1;
743 744 745
            i_t1 = ( ( i_t1 & 1 ) << 8 ) ^ i_t4;
            i_t4 = pi_css_tab5[i_t4];
            i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
Sam Hocevar's avatar
 
Sam Hocevar committed
746 747
                                         i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
            i_t3 = ( i_t3 << 8 ) | i_t6;
748 749
            i_t6 = pi_css_tab4[i_t6];
            i_t5 += i_t6 + i_t4;
Sam Hocevar's avatar
 
Sam Hocevar committed
750 751 752 753 754
            if( ( i_t5 & 0xff ) != pi_buffer[i] )
            {
                break;
            }

755
            i_t5 >>= 8;
756
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803

        if( i == 10 )
        {
            /* Do 4 backwards steps of iterating t3 to deduce initial state */
            i_t3 = i_candidate;
            for( i = 0 ; i < 4 ; i++ )
            {
                i_t1 = i_t3 & 0xff;
                i_t3 = ( i_t3 >> 8 );
                /* easy to code, and fast enough bruteforce
                 * search for byte shifted in */
                for( j = 0 ; j < 256 ; j++ )
                {
                    i_t3 = ( i_t3 & 0x1ffff) | ( j << 17 );
                    i_t6 = ((((((( i_t3 >> 3 ) ^ i_t3 ) >> 1 ) ^
                                   i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
                    if( i_t6 == i_t1 )
                    {
                        break;
                    }
                }
            }

            i_t4 = ( i_t3 >> 1 ) - 4;
            for( i_t5 = 0 ; i_t5 < 8; i_t5++ )
            {
                if( ( ( i_t4 + i_t5 ) * 2 + 8 - ( (i_t4 + i_t5 ) & 7 ) )
                                                                      == i_t3 )
                {
                    (*p_key)[0] = i_try>>8;
                    (*p_key)[1] = i_try & 0xFF;
                    (*p_key)[2] = ( ( i_t4 + i_t5 ) >> 0) & 0xFF;
                    (*p_key)[3] = ( ( i_t4 + i_t5 ) >> 8) & 0xFF;
                    (*p_key)[4] = ( ( i_t4 + i_t5 ) >> 16) & 0xFF;
                    i_exit = i_try + 1;
                }
            }
        }
    }

    if( i_exit >= 0 )
    {
        (*p_key)[0] ^= (*p_sector_key)[0];
        (*p_key)[1] ^= (*p_sector_key)[1];
        (*p_key)[2] ^= (*p_sector_key)[2];
        (*p_key)[3] ^= (*p_sector_key)[3];
        (*p_key)[4] ^= (*p_sector_key)[4];
804 805
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
806
    return i_exit;
807
}
Sam Hocevar's avatar
 
Sam Hocevar committed
808

Sam Hocevar's avatar
 
Sam Hocevar committed
809
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
810