dvd_css.c 24.9 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * dvd_css.c: Functions for DVD authentification and unscrambling
 *****************************************************************************
 * Copyright (C) 1999-2001 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
5
 * $Id: dvd_css.c,v 1.30 2001/05/31 01:37:08 sam 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>
Sam Hocevar's avatar
 
Sam Hocevar committed
39 40

#ifdef HAVE_UNISTD_H
41
#include <unistd.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
42 43 44 45
#elif defined( _MSC_VER ) && defined( _WIN32 )
#include <io.h>
#endif

46 47 48
#include <string.h>

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

50
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
51

52
#include "dvd_css.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
53 54 55
#ifdef HAVE_CSS
#include "dvd_csstables.h"
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
56 57
#include "dvd_ioctl.h"

58
#include "input_dvd.h"
59 60

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
61
 * Local prototypes
62
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
63
#ifdef HAVE_CSS
Sam Hocevar's avatar
 
Sam Hocevar committed
64
static int  CSSGetASF    ( int i_fd );
Sam Hocevar's avatar
 
Sam Hocevar committed
65 66 67 68 69 70
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 */
71 72

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
73
 * CSSTest : check if the disc is encrypted or not
74
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
75
int CSSTest( int i_fd )
76
{
Sam Hocevar's avatar
 
Sam Hocevar committed
77
    int i_ret, i_copyright;
78

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

Sam Hocevar's avatar
 
Sam Hocevar committed
81
    if( i_ret < 0 )
82
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
83 84 85 86
        /* 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
87
        return i_ret;
88
    }
89

Sam Hocevar's avatar
 
Sam Hocevar committed
90
    return i_copyright;
91 92 93
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
94 95 96 97 98
 * 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.
99
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
100
int CSSInit( int i_fd, css_t * p_css )
101
{
Sam Hocevar's avatar
 
Sam Hocevar committed
102 103
#ifdef HAVE_CSS
    /* structures defined in cdrom.h or dvdio.h */
Sam Hocevar's avatar
 
Sam Hocevar committed
104
    char p_buffer[2048 + 4 + 1];
Sam Hocevar's avatar
 
Sam Hocevar committed
105
    int  i_agid = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
106 107
    int  i_ret = -1;
    int  i;
108

Sam Hocevar's avatar
 
Sam Hocevar committed
109
    /* Test authentication success */
Sam Hocevar's avatar
 
Sam Hocevar committed
110
    switch( CSSGetASF( i_fd ) )
111
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
112 113
        case -1:
            return -1;
114

Sam Hocevar's avatar
 
Sam Hocevar committed
115
        case 1:
116
            intf_WarnMsg( 2, "css info: already authenticated" );
Sam Hocevar's avatar
 
Sam Hocevar committed
117
            return 0;
118

Sam Hocevar's avatar
 
Sam Hocevar committed
119
        case 0:
120
            intf_WarnMsg( 2, "css info: need to authenticate" );
121 122
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
123 124
    /* Init sequence, request AGID */
    for( i = 1; i < 4 ; ++i )
125
    {
126
        intf_WarnMsg( 2, "css info: requesting AGID %d", i );
Sam Hocevar's avatar
 
Sam Hocevar committed
127

Sam Hocevar's avatar
 
Sam Hocevar committed
128
        i_ret = ioctl_ReportAgid( i_fd, &i_agid );
Sam Hocevar's avatar
 
Sam Hocevar committed
129 130

        if( i_ret != -1 )
131
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
132
            /* No error during ioctl: we know the device is authenticated */
Sam Hocevar's avatar
 
Sam Hocevar committed
133
            break;
134
        }
135

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

Sam Hocevar's avatar
 
Sam Hocevar committed
138 139
        i_agid = 0;
        ioctl_InvalidateAgid( i_fd, &i_agid );
Sam Hocevar's avatar
 
Sam Hocevar committed
140
    }
141

Sam Hocevar's avatar
 
Sam Hocevar committed
142
    /* Unable to authenticate without AGID */
Sam Hocevar's avatar
 
Sam Hocevar committed
143
    if( i_ret == -1 )
144
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
145
        intf_ErrMsg( "css error: ioctl_ReportAgid failed, fatal" );
Sam Hocevar's avatar
 
Sam Hocevar committed
146
        return -1;
147
    }
148

Sam Hocevar's avatar
 
Sam Hocevar committed
149
    for( i = 0 ; i < 10; ++i )
150
    {
151
        p_css->disc.pi_challenge[i] = i;
152
    }
153

Sam Hocevar's avatar
 
Sam Hocevar committed
154 155 156
    /* Get challenge from host */
    for( i = 0 ; i < 10 ; ++i )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
157
        p_buffer[9-i] = p_css->disc.pi_challenge[i];
158
    }
159

Sam Hocevar's avatar
 
Sam Hocevar committed
160
    /* Send challenge to LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
161
    if( ioctl_SendChallenge( i_fd, &i_agid, p_buffer ) < 0 )
162
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
163
        intf_ErrMsg( "css error: ioctl_SendChallenge failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
164
        return -1;
165
    }
166

Sam Hocevar's avatar
 
Sam Hocevar committed
167
    /* Get key1 from LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
168
    if( ioctl_ReportKey1( i_fd, &i_agid, p_buffer ) < 0)
169
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
170
        intf_ErrMsg( "css error: ioctl_ReportKey1 failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
171
        return -1;
172
    }
173

Sam Hocevar's avatar
 
Sam Hocevar committed
174 175
    /* Send key1 to host */
    for( i = 0 ; i < KEY_SIZE ; i++ )
176
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
177
        p_css->disc.pi_key1[i] = p_buffer[4-i];
178 179 180 181
    }

    for( i = 0 ; i < 32 ; ++i )
    {
182 183
        CSSCryptKey( 0, i, p_css->disc.pi_challenge,
                           p_css->disc.pi_key_check );
184

185 186
        if( memcmp( p_css->disc.pi_key_check,
                    p_css->disc.pi_key1, KEY_SIZE ) == 0 )
187
        {
188
            intf_WarnMsg( 2, "css info: drive authentic, using variant %d", i);
189
            p_css->disc.i_varient = i;
190 191 192 193 194 195
            break;
        }
    }

    if( i == 32 )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
196
        intf_ErrMsg( "css error: drive would not authenticate" );
Sam Hocevar's avatar
 
Sam Hocevar committed
197
        return -1;
198
    }
199 200

    /* Get challenge from LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
201
    if( ioctl_ReportChallenge( i_fd, &i_agid, p_buffer ) < 0 )
202
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
203
        intf_ErrMsg( "css error: ioctl_ReportKeyChallenge failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
204
        return -1;
205 206
    }

207
    /* Send challenge to host */
208
    for( i = 0 ; i < 10 ; ++i )
209
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
210
        p_css->disc.pi_challenge[i] = p_buffer[9-i];
211 212
    }

213
    CSSCryptKey( 1, p_css->disc.i_varient, p_css->disc.pi_challenge,
Sam Hocevar's avatar
 
Sam Hocevar committed
214
                                               p_css->disc.pi_key2 );
215

216
    /* Get key2 from host */
217
    for( i = 0 ; i < KEY_SIZE ; ++i )
218
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
219
        p_buffer[4-i] = p_css->disc.pi_key2[i];
220
    }
221

222
    /* Send key2 to LU */
Sam Hocevar's avatar
 
Sam Hocevar committed
223
    if( ioctl_SendKey2( i_fd, &i_agid, p_buffer ) < 0 )
224
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
225
        intf_ErrMsg( "css error: ioctl_SendKey2 failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
226
        return -1;
227
    }
228

229
    intf_WarnMsg( 2, "css info: authentication established" );
230

231 232
    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
233

Sam Hocevar's avatar
 
Sam Hocevar committed
234
    CSSCryptKey( 2, p_css->disc.i_varient, p_css->disc.pi_challenge,
Sam Hocevar's avatar
 
Sam Hocevar committed
235
                                           p_css->disc.pi_key_check );
236

237
    intf_WarnMsg( 2, "css info: received session key" );
238

Sam Hocevar's avatar
 
Sam Hocevar committed
239
    if( i_agid < 0 )
240
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
241
        return -1;
242
    }
243

244
    /* Test authentication success */
Sam Hocevar's avatar
 
Sam Hocevar committed
245
    switch( CSSGetASF( i_fd ) )
246
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
247 248 249 250
        case -1:
            return -1;

        case 1:
251
            intf_WarnMsg( 2, "css info: already authenticated" );
Sam Hocevar's avatar
 
Sam Hocevar committed
252 253 254
            return 0;

        case 0:
255
            intf_WarnMsg( 2, "css info: need to get disc key" );
256
    }
257

258
    /* Get encrypted disc key */
Sam Hocevar's avatar
 
Sam Hocevar committed
259
    if( ioctl_ReadKey( i_fd, &i_agid, p_buffer ) < 0 )
260
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
261
        intf_ErrMsg( "css error: ioctl_ReadKey failed" );
Sam Hocevar's avatar
 
Sam Hocevar committed
262
        return -1;
263
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
264

265
    /* Unencrypt disc key using bus key */
Sam Hocevar's avatar
 
Sam Hocevar committed
266
    for( i = 0 ; i < 2048 ; i++ )
267
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
268
        p_buffer[ i ] ^= p_css->disc.pi_key_check[ 4 - (i % KEY_SIZE) ];
269
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
270 271
    memcpy( p_css->disc.pi_key_check, p_buffer, 2048 );

272 273 274 275 276 277
    /* initialize title key to know it empty */
    for( i = 0 ; i < KEY_SIZE ; i++ )
    {
        p_css->pi_title_key[i] = 0;
    }

278
    /* Test authentication success */
Sam Hocevar's avatar
 
Sam Hocevar committed
279
    switch( CSSGetASF( i_fd ) )
280
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
281 282 283 284
        case -1:
            return -1;

        case 1:
285
            intf_WarnMsg( 2, "css info: successfully authenticated" );
Sam Hocevar's avatar
 
Sam Hocevar committed
286
            return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
287

Sam Hocevar's avatar
 
Sam Hocevar committed
288
        case 0:
289 290
            intf_ErrMsg( "css error: no way to authenticate" );
            return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
291
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
292

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

Sam Hocevar's avatar
 
Sam Hocevar committed
296
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
297 298
    return -1;

299 300
}

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
329 330 331 332 333
    b_encrypted = 0;
    b_stop_scanning = 0;

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

Stéphane Borel's avatar
 
Stéphane Borel committed
335
    do {
Sam Hocevar's avatar
 
Sam Hocevar committed
336 337
    i_pos = lseek( i_fd, i_pos, SEEK_SET );
    i_bytes_read = read( i_fd, pi_buf, 0x800 );
338

Stéphane Borel's avatar
 
Stéphane Borel committed
339 340 341 342 343 344
    /* PES_scrambling_control */
    if( pi_buf[0x14] & 0x30 )
    {
        b_encrypted = 1;
        i_best_plen = 0;
        i_best_p = 0;
345

Stéphane Borel's avatar
 
Stéphane Borel committed
346 347 348 349
        for( i = 2 ; i < 0x30 ; i++ )
        {
            for( j = i ; ( j < 0x80 ) &&
                   ( pi_buf[0x7F - (j%i)] == pi_buf[0x7F-j] ) ; j++ );
350
            {
Stéphane Borel's avatar
 
Stéphane Borel committed
351
                if( ( j > i_best_plen ) && ( j > i ) )
352
                {
Stéphane Borel's avatar
 
Stéphane Borel committed
353 354
                    i_best_plen = j;
                    i_best_p = i;
355
                }
356
            }
Stéphane Borel's avatar
 
Stéphane Borel committed
357
        }
358

Stéphane Borel's avatar
 
Stéphane Borel committed
359 360 361 362 363 364
        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 );
365
            b_stop_scanning = ( i >= 0 );
Sam Hocevar's avatar
 
Sam Hocevar committed
366 367 368 369 370 371 372 373
        }
    }

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

    if( b_stop_scanning)
    {
374 375 376 377
            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
378 379 380 381
    }

    if( !b_encrypted )
    {
382
        intf_WarnMsg( 2, "css warning: this file was _NOT_ encrypted!" );
383
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
384 385
    }

386
    return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
387

Sam Hocevar's avatar
 
Sam Hocevar committed
388
#else /* HAVE_CSS */
389 390
    intf_ErrMsg( "css error: css decryption unavailable" );
    return -1;
Sam Hocevar's avatar
 
Sam Hocevar committed
391

Sam Hocevar's avatar
 
Sam Hocevar committed
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 425 426 427 428 429 430
#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
431 432
            *pi_sec = pi_css_tab1[*pi_sec] ^( i_t5 & 0xff );
            pi_sec++;
Sam Hocevar's avatar
 
Sam Hocevar committed
433 434 435 436 437
            i_t5 >>= 8;
        }
    }

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

Sam Hocevar's avatar
 
Sam Hocevar committed
439 440
#else /* HAVE_CSS */
    return 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
441

Sam Hocevar's avatar
 
Sam Hocevar committed
442 443 444 445
#endif /* HAVE_CSS */
}

#ifdef HAVE_CSS
Sam Hocevar's avatar
 
Sam Hocevar committed
446 447

/* Following functions are local */
Sam Hocevar's avatar
 
Sam Hocevar committed
448 449 450 451 452 453 454 455 456

/*****************************************************************************
 * 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
457
static int CSSGetASF( int i_fd )
Sam Hocevar's avatar
 
Sam Hocevar committed
458
{
Sam Hocevar's avatar
 
Sam Hocevar committed
459 460
    int i_agid;
    int i_asf = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
461

Sam Hocevar's avatar
 
Sam Hocevar committed
462
    for( i_agid = 0 ; i_agid < 4 ; i_agid++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
463
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
464
        if( ioctl_ReportASF( i_fd, &i_agid, &i_asf ) == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
465
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
466 467
            intf_WarnMsg( 3, "css info: GetASF %sauthenticated",
                          i_asf ? "":"not " );
Sam Hocevar's avatar
 
Sam Hocevar committed
468 469

            return i_asf;
Sam Hocevar's avatar
 
Sam Hocevar committed
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 596 597 598 599 600 601
        }
    }

    /* 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
602

Sam Hocevar's avatar
 
Sam Hocevar committed
603 604 605 606 607 608 609
            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;
610
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
611 612 613
    
        pi_bits[--i_index] = i_val;
    } while( i_index > 0 );
614

Sam Hocevar's avatar
 
Sam Hocevar committed
615 616 617 618 619
    /* 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];
620

Sam Hocevar's avatar
 
Sam Hocevar committed
621 622 623 624 625 626
    /* 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
627
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
628 629 630 631
        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
632
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
633
    pi_tmp1[4] ^= pi_tmp1[0];
634

Sam Hocevar's avatar
 
Sam Hocevar committed
635
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
636
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
637 638 639 640
        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
641
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
642
    pi_tmp2[4] ^= pi_tmp2[0];
643

Sam Hocevar's avatar
 
Sam Hocevar committed
644
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
645
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
646 647 648 649 650
        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
651
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
652
    pi_tmp1[4] ^= pi_tmp1[0];
653

Sam Hocevar's avatar
 
Sam Hocevar committed
654
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp1[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
655
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
656 657
        i_index = pi_bits[10 + i] ^ pi_tmp1[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;
658

Sam Hocevar's avatar
 
Sam Hocevar committed
659
        i_index = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
660

Sam Hocevar's avatar
 
Sam Hocevar committed
661
        pi_tmp2[i] = pi_crypt_tab0[i_index] ^ pi_crypt_tab2[i_index];
Stéphane Borel's avatar
 
Stéphane Borel committed
662
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
663
    pi_tmp2[4] ^= pi_tmp2[0];
664

Sam Hocevar's avatar
 
Sam Hocevar committed
665
    for( i = 5, i_term = 0 ; --i >= 0 ; i_term = pi_tmp2[i] )
Stéphane Borel's avatar
 
Stéphane Borel committed
666
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
667 668
        i_index = pi_bits[5 + i] ^ pi_tmp2[i];
        i_index = pi_crypt_tab1[i_index] ^ ~pi_crypt_tab2[i_index] ^ i_cse;
669

Sam Hocevar's avatar
 
Sam Hocevar committed
670 671 672
        pi_tmp1[i] = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
    }
    pi_tmp1[4] ^= pi_tmp1[0];
673

Sam Hocevar's avatar
 
Sam Hocevar committed
674 675 676 677
    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
678

Sam Hocevar's avatar
 
Sam Hocevar committed
679 680
        pi_key[i] = pi_crypt_tab2[i_index] ^ pi_crypt_tab3[i_index] ^ i_term;
    }
681

Sam Hocevar's avatar
 
Sam Hocevar committed
682
    return;
683 684 685
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
686 687 688
 * CSSCracker : title key decryption by cracking
 *****************************************************************************
 * This function is called by CSSGetKeys to find a key
689
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
690 691 692 693 694
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 )
695
{
Sam Hocevar's avatar
 
Sam Hocevar committed
696 697 698 699 700 701
    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;
702

Sam Hocevar's avatar
 
Sam Hocevar committed
703 704

    for( i = 0 ; i < 10 ; i++ )
705
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
706 707 708 709 710 711 712 713
        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 */
714 715
        i_t5 = 0;

Sam Hocevar's avatar
 
Sam Hocevar committed
716 717
        /* iterate cipher 4 times to reconstruct LFSR2 */
        for( i = 0 ; i < 4 ; i++ )
718
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
719
            /* advance LFSR1 normaly */
720
            i_t4 = pi_css_tab2[i_t2] ^ pi_css_tab3[i_t1];
Sam Hocevar's avatar
 
Sam Hocevar committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
            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;
749 750 751
            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
752 753
                                         i_t3 ) >> 8 ) ^ i_t3 ) >> 5 ) & 0xff;
            i_t3 = ( i_t3 << 8 ) | i_t6;
754 755
            i_t6 = pi_css_tab4[i_t6];
            i_t5 += i_t6 + i_t4;
Sam Hocevar's avatar
 
Sam Hocevar committed
756 757 758 759 760
            if( ( i_t5 & 0xff ) != pi_buffer[i] )
            {
                break;
            }

761
            i_t5 >>= 8;
762
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
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 804 805 806 807 808 809

        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];
810 811
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
812
    return i_exit;
813
}
Sam Hocevar's avatar
 
Sam Hocevar committed
814

Sam Hocevar's avatar
 
Sam Hocevar committed
815
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
816