aacs.c 19.5 KB
Newer Older
1 2
/*
 * This file is part of libaacs
3
 * Copyright (C) 2009-2010  Obliter0n
npzacs's avatar
npzacs committed
4
 * Copyright (C) 2009-2010  npzacs
5
 *
gates's avatar
gates committed
6 7 8 9
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
10
 *
gates's avatar
gates committed
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
gates's avatar
gates committed
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
15
 *
gates's avatar
gates committed
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see
 * <http://www.gnu.org/licenses/>.
19 20
 */

npzacs's avatar
npzacs committed
21 22 23 24
#if HAVE_CONFIG_H
#include "config.h"
#endif

npzacs's avatar
npzacs committed
25 26
#include <util/attributes.h>

cRTrn13's avatar
cRTrn13 committed
27
#include "aacs.h"
28
#include "crypto.h"
cRTrn13's avatar
cRTrn13 committed
29
#include "mmc.h"
30
#include "mkb.h"
gates's avatar
gates committed
31
#include "file/file.h"
gates's avatar
gates committed
32
#include "file/keydbcfg.h"
33 34
#include "util/macro.h"
#include "util/logging.h"
35
#include "util/strutl.h"
cRTrn13's avatar
cRTrn13 committed
36

37
#include <inttypes.h>
38
#include <string.h>
39
#include <stdio.h>
npzacs's avatar
npzacs committed
40 41 42
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
43
#include <gcrypt.h>
44

npzacs's avatar
npzacs committed
45

npzacs's avatar
npzacs committed
46
struct aacs {
npzacs's avatar
npzacs committed
47
    uint8_t pk[16], mk[16], vuk[16], vid[16], disc_id[20], *uks;
npzacs's avatar
npzacs committed
48 49
    uint32_t num_uks;
    struct config_file_t *cf;
50
    struct title_entry_list_t *ce;
51 52 53 54

    uint32_t num_titles;
    uint16_t current_cps_unit;
    uint16_t *cps_units;  /* [0] = first play ; [1] = top menu ; [2] = title 1 ... */
npzacs's avatar
npzacs committed
55 56
};

57 58 59
static const uint8_t empty_key[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
                                   "\x00\x00\x00\x00\x00\x00\x00\x00";

60 61
static int _validate_pk(const uint8_t *pk,
                        const uint8_t *cvalue, const uint8_t *uv, const uint8_t *vd,
npzacs's avatar
npzacs committed
62
                        uint8_t *mk)
cRTrn13's avatar
cRTrn13 committed
63
{
64 65
    gcry_cipher_hd_t gcry_h;
    int a, ret = 0;
cRTrn13's avatar
cRTrn13 committed
66
    uint8_t dec_vd[16];
67
    char str[40];
cRTrn13's avatar
cRTrn13 committed
68

69
    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
cRTrn13's avatar
cRTrn13 committed
70
    DEBUG(DBG_AACS, " Using:\n");
71 72 73
    DEBUG(DBG_AACS, "   UV: %s\n", print_hex(str, uv, 4));
    DEBUG(DBG_AACS, "   cvalue: %s\n", print_hex(str, cvalue, 16));
    DEBUG(DBG_AACS, "   Verification data: %s\n", print_hex(str, vd, 16));
74

75 76 77
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
    gcry_cipher_setkey(gcry_h, pk, 16);
    gcry_cipher_decrypt(gcry_h, mk, 16, cvalue, 16);
78

cRTrn13's avatar
cRTrn13 committed
79 80 81 82
    for (a = 0; a < 4; a++) {
        mk[a + 12] ^= uv[a];
    }

83 84 85
    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);
    gcry_cipher_close(gcry_h);
86

cRTrn13's avatar
cRTrn13 committed
87
    if (!memcmp(dec_vd, "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8)) {
npzacs's avatar
npzacs committed
88
        DEBUG(DBG_AACS, "Processing key %s is valid!\n", print_hex(str, pk, 16));
89
        ret = 1;
cRTrn13's avatar
cRTrn13 committed
90 91
    }

92
    return ret;
cRTrn13's avatar
cRTrn13 committed
93
}
94

npzacs's avatar
npzacs committed
95
static int _calc_mk(AACS *aacs, const char *path)
cRTrn13's avatar
keyfile  
cRTrn13 committed
96 97 98
{
    int a, num_uvs = 0;
    size_t len;
99
    uint8_t *buf = NULL;
cRTrn13's avatar
keyfile  
cRTrn13 committed
100
    MKB *mkb = NULL;
101
    const uint8_t *rec, *uvs;
cRTrn13's avatar
keyfile  
cRTrn13 committed
102

103 104 105 106
    /* Skip if retrieved from config file */
    if (memcmp(aacs->mk, empty_key, 16))
      return 1;

cRTrn13's avatar
cRTrn13 committed
107 108
    DEBUG(DBG_AACS, "Calculate media key...\n");

109 110 111 112 113 114 115 116 117 118
    if ((mkb = mkb_open(path))) {
        DEBUG(DBG_AACS, "Get UVS...\n");
        uvs = mkb_subdiff_records(mkb, &len);
        rec = uvs;
        while (rec < uvs + len) {
            if (rec[0] & 0xc0)
                break;
            rec += 5;
            num_uvs++;
        }
cRTrn13's avatar
keyfile  
cRTrn13 committed
119

120 121
        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);
122 123 124 125 126
        if (aacs->cf->pkl) {
            pk_list *pkcursor = aacs->cf->pkl;
            while (pkcursor && pkcursor->key) {
                hexstring_to_hex_array(aacs->pk, sizeof(aacs->pk),
                                       pkcursor->key);
127 128 129
                DEBUG(DBG_AACS, "Trying processing key...\n");

                for (a = 0; a < num_uvs; a++) {
gates's avatar
gates committed
130 131
                    if (_validate_pk(aacs->pk, rec + a * 16, uvs + 1 + a * 5,
                      mkb_mk_dv(mkb), aacs->mk)) {
132 133
                        mkb_close(mkb);
                        X_FREE(buf);
134

135 136
                        char str[40];
                        DEBUG(DBG_AACS, "Media key: %s\n", print_hex(str, aacs->mk,
gates's avatar
gates committed
137
                                                                     16));
138 139 140 141
                        return 1;
                    }
                }

142
                pkcursor = pkcursor->next;
cRTrn13's avatar
keyfile  
cRTrn13 committed
143
            }
144
        }
cRTrn13's avatar
keyfile  
cRTrn13 committed
145

146 147
        mkb_close(mkb);
        X_FREE(buf);
cRTrn13's avatar
keyfile  
cRTrn13 committed
148 149
    }

npzacs's avatar
npzacs committed
150 151
    DEBUG(DBG_AACS, "Error calculating media key!\n");

cRTrn13's avatar
keyfile  
cRTrn13 committed
152 153
    return 0;
}
154

npzacs's avatar
npzacs committed
155
static int _calc_vuk(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
156
{
157
    int a;
cRTrn13's avatar
cRTrn13 committed
158
    MMC* mmc = NULL;
cRTrn13's avatar
openssl  
cRTrn13 committed
159

160 161 162 163
    /* Skip if retrieved from config file */
    if (memcmp(aacs->vuk, empty_key, 16))
      return 1;

npzacs's avatar
npzacs committed
164 165 166 167 168 169
    /* get cached vuk */
    if (keycache_find("vuk", aacs->disc_id, aacs->vuk, 16)) {
        DEBUG(DBG_AACS, "Using cached VUK\n");
        return 1;
    }

170 171 172 173 174
    /* make sure we have media key */
    if (!_calc_mk(aacs, path)) {
        return 0;
    }

175 176
    DEBUG(DBG_AACS, "Calculate volume unique key...\n");

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    /* Use VID given in config file if available */
    if (memcmp(aacs->vid, empty_key, 16))
    {
        gcry_cipher_hd_t gcry_h;
        gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
        gcry_cipher_setkey(gcry_h, aacs->mk, 16);
        gcry_cipher_decrypt(gcry_h, aacs->vuk, 16, aacs->vid, 16);
        gcry_cipher_close(gcry_h);

        for (a = 0; a < 16; a++) {
            aacs->vuk[a] ^= aacs->vid[a];
        }

        char str[40];
        DEBUG(DBG_AACS, "Volume unique key: %s\n",
              print_hex(str, aacs->vuk, 16));

npzacs's avatar
npzacs committed
194 195 196
        /* cache vuk */
        keycache_save("vuk", aacs->disc_id, aacs->vuk, 16);

197 198 199
        return 1;
    }

200
    cert_list *hccursor = aacs->cf->host_cert_list;
npzacs's avatar
npzacs committed
201
    while (hccursor && hccursor->host_priv_key && hccursor->host_cert) {
202
        uint8_t priv_key[20], cert[92];
203 204 205 206
        hexstring_to_hex_array(priv_key, sizeof(priv_key),
                               hccursor->host_priv_key);
        hexstring_to_hex_array(cert, sizeof(cert), hccursor->host_cert);

207 208 209 210 211 212 213 214 215 216 217 218 219
        if (!crypto_aacs_verify_host_cert(cert)) {
	    char str[2*92+1];
	    DEBUG(DBG_AACS, "Not using invalid host certificate %s.\n",
		  print_hex(str, cert, 92));

	    hccursor = hccursor->next;
	    continue;
	}

        char id_str[20];
        DEBUG(DBG_AACS, "Trying host certificate (id 0x%s)...\n",
              print_hex(id_str, cert + 4, 6));

npzacs's avatar
npzacs committed
220 221
        if ((mmc = mmc_open(path))) {
            if (mmc_read_vid(mmc, priv_key, cert, aacs->vid)) {
222 223 224 225 226 227
                gcry_cipher_hd_t gcry_h;
                gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES,
                                 GCRY_CIPHER_MODE_ECB, 0);
                gcry_cipher_setkey(gcry_h, aacs->mk, 16);
                gcry_cipher_decrypt(gcry_h, aacs->vuk, 16, aacs->vid, 16);
                gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
228

229 230 231 232 233
                for (a = 0; a < 16; a++) {
                    aacs->vuk[a] ^= aacs->vid[a];
                }

                mmc_close(mmc);
cRTrn13's avatar
openssl  
cRTrn13 committed
234

235 236 237
                char str[40];
                DEBUG(DBG_AACS, "Volume unique key: %s\n", print_hex(str, aacs->vuk,
                                                                    16));
238

npzacs's avatar
npzacs committed
239 240 241
                /* cache vuk */
                keycache_save("vuk", aacs->disc_id, aacs->vuk, 16);

242 243 244 245
                return 1;
            }

            mmc_close(mmc);
cRTrn13's avatar
openssl  
cRTrn13 committed
246 247
        }

248
        hccursor = hccursor->next;
cRTrn13's avatar
cRTrn13 committed
249
    }
cRTrn13's avatar
openssl  
cRTrn13 committed
250

251 252
    DEBUG(DBG_AACS, "Error calculating VUK!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
253 254 255
    return 0;
}

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
static uint16_t _read_u16(AACS_FILE_H *fp)
{
  uint8_t data[2];

  file_read(fp, data, sizeof(uint16_t));

  return MKINT_BE16(data);
}

static void _read_uks_map(AACS *aacs, AACS_FILE_H *fp)
{
    uint16_t first_play, top_menu;
    unsigned i;

    DEBUG(DBG_AACS, "Assigning CPS units to titles ...\n");

    X_FREE(aacs->cps_units);
    aacs->current_cps_unit = 0;

    file_seek(fp, 16 + 4, SEEK_SET);

    first_play = _read_u16(fp);
    top_menu   = _read_u16(fp);

    DEBUG(DBG_AACS, "Title FP : CPS unit %d\n", first_play);
    DEBUG(DBG_AACS, "Title TM : CPS unit %d\n", top_menu);

    aacs->num_titles   = _read_u16(fp);
    aacs->cps_units    = calloc(sizeof(uint16_t), aacs->num_titles + 2);
    aacs->cps_units[0] = first_play;
    aacs->cps_units[1] = top_menu;

    for (i = 2; i < aacs->num_titles + 2; i++) {
        _read_u16(fp); /* reserved */
        aacs->cps_units[i] = _read_u16(fp);
        DEBUG(DBG_AACS, "Title %02d : CPS unit %d\n", i - 1, aacs->cps_units[i]);
    }

    /* validate */
    for (i = 0; i < aacs->num_titles + 2; i++) {
        if (aacs->cps_units[i])
            aacs->cps_units[i]--; /* number [1...N] --> index [0...N-1] */
        if (aacs->cps_units[i] >= aacs->num_uks) {
            DEBUG(DBG_AACS, " *** Invalid CPS unit for title %d: %d !\n", (int) i - 1, aacs->cps_units[i]);
            aacs->cps_units[i] = 0;
        }
    }
}

npzacs's avatar
npzacs committed
305
static int _calc_uks(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
306
{
307
    AACS_FILE_H *fp = NULL;
308 309
    char    *f_name;
    uint8_t  buf[16];
310
    uint64_t f_pos;
311
    unsigned int i;
cRTrn13's avatar
openssl  
cRTrn13 committed
312

313 314
    /* Skip if retrieved from config file */
    if (aacs->uks)
315
        return 1;
316

317 318
    /* Make sure we have VUK */
    if (!_calc_vuk(aacs, path)) {
319
        return 0;
320
    }
321

322 323
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

npzacs's avatar
npzacs committed
324
    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
325 326
    fp = file_open(f_name, "rb");
    X_FREE(f_name);
cRTrn13's avatar
openssl  
cRTrn13 committed
327

328
    if (fp) {
329
        if ((file_read(fp, buf, 4)) == 4) {
npzacs's avatar
npzacs committed
330
            f_pos = MKINT_BE32(buf);
cRTrn13's avatar
openssl  
cRTrn13 committed
331

npzacs's avatar
npzacs committed
332
            // Read number of keys
cRTrn13's avatar
cRTrn13 committed
333
            file_seek(fp, f_pos, SEEK_SET);
npzacs's avatar
npzacs committed
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
            if ((file_read(fp, buf, 2)) == 2) {
                aacs->num_uks = MKINT_BE16(buf);

                X_FREE(aacs->uks);
                aacs->uks = calloc(aacs->num_uks, 16);

                DEBUG(DBG_AACS, "%d CPS unit keys\n", aacs->num_uks);

            } else {
                aacs->num_uks = 0;
                DEBUG(DBG_AACS, "Error reading number of unit keys!\n");
            }

            // Read keys
            for (i = 0; i < aacs->num_uks; i++) {
                f_pos += 48;

                file_seek(fp, f_pos, SEEK_SET);
                if ((file_read(fp, buf, 16)) != 16) {
                    DEBUG(DBG_AACS, "Unit key %d: read error\n", i);
                    aacs->num_uks = i;
                    break;
                }
cRTrn13's avatar
openssl  
cRTrn13 committed
357

358 359 360 361 362 363
                gcry_cipher_hd_t gcry_h;
                gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES,
                                 GCRY_CIPHER_MODE_ECB, 0);
                gcry_cipher_setkey(gcry_h, aacs->vuk, 16);
                gcry_cipher_decrypt(gcry_h, aacs->uks + 16*i, 16, buf, 16);
                gcry_cipher_close(gcry_h);
cRTrn13's avatar
openssl  
cRTrn13 committed
364

365
                char str[40];
gates's avatar
gates committed
366
                DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
367
                      print_hex(str, aacs->uks + 16*i, 16));
npzacs's avatar
npzacs committed
368
            }
cRTrn13's avatar
openssl  
cRTrn13 committed
369

370 371
            _read_uks_map(aacs, fp);

npzacs's avatar
npzacs committed
372
            file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
373

npzacs's avatar
npzacs committed
374
            return aacs->num_uks;
375 376 377
        }

        file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
378 379
    }

380 381
    DEBUG(DBG_AACS, "Could not calculate unit keys!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
382 383 384
    return 0;
}

385 386
static int _calc_title_hash(const char *path, uint8_t *title_hash)
{
387
    AACS_FILE_H *fp = NULL;
388 389 390 391 392
    uint8_t *ukf_buf;
    char     str[48];
    int64_t  f_size;
    char    *f_name;

npzacs's avatar
npzacs committed
393
    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

    if (!(fp = file_open(f_name, "rb"))) {
        DEBUG(DBG_AACS, "Failed to open unit key file: %s!\n", f_name);
        X_FREE(f_name);
        return 0;
    }

    X_FREE(f_name);

    file_seek(fp, 0, SEEK_END);
    f_size = file_tell(fp);
    file_seek(fp, 0, SEEK_SET);

    ukf_buf = malloc(f_size);

    if ((file_read(fp, ukf_buf, f_size)) != f_size) {
cRTrn13's avatar
cRTrn13 committed
410

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
        DEBUG(DBG_AACS, "Failed to read %"PRIu64" bytes from unit key file!\n", f_size);

        file_close(fp);
        X_FREE(ukf_buf);

        return 0;
    }

    crypto_aacs_title_hash(ukf_buf, f_size, title_hash);
    DEBUG(DBG_AACS, "Disc ID: %s\n", print_hex(str, title_hash, 20));

    file_close(fp);
    X_FREE(ukf_buf);

    return 1;
}
cRTrn13's avatar
cRTrn13 committed
427

npzacs's avatar
npzacs committed
428
static int _verify_ts(uint8_t *buf, size_t size)
429
{
430 431
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
432 433 434 435 436 437 438
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
439 440 441 442
            uint8_t *ptr2;

            for (ptr2=ptr; ptr2 < buf + size; ptr2 += 192) {
                if (*ptr2 != 0x47) {
cRTrn13's avatar
cRTrn13 committed
443 444
                    failed = 1;
                    break;
445 446
                }
            }
cRTrn13's avatar
cRTrn13 committed
447 448 449
            if (!failed) {
                return 1;
            }
450 451 452 453
        }
        ptr++;
    }

cRTrn13's avatar
cRTrn13 committed
454
    DEBUG(DBG_AACS, "Failed to verify TS!\n");
455

cRTrn13's avatar
cRTrn13 committed
456
    return 0;
457 458
}

459
/* Function that collects keys from keydb config entry */
npzacs's avatar
npzacs committed
460
static uint32_t _find_config_entry(AACS *aacs, const char *path)
461
{
npzacs's avatar
npzacs committed
462
    uint8_t discid[20];
463
    char str[48];
464 465 466
    uint32_t retval = 0;
    aacs->uks = NULL;
    aacs->num_uks = 0;
cRTrn13's avatar
cRTrn13 committed
467

npzacs's avatar
npzacs committed
468
    if (!_calc_title_hash(path, aacs->disc_id)) {
cRTrn13's avatar
cRTrn13 committed
469 470 471
        return 0;
    }

npzacs's avatar
npzacs committed
472
    if (aacs->cf && aacs->cf->list) {
473 474 475 476 477
        aacs->ce = aacs->cf->list;
        while (aacs->ce && aacs->ce->entry.discid) {
            memset(discid, 0, sizeof(discid));
            hexstring_to_hex_array(discid, sizeof(discid),
                                   aacs->ce->entry.discid);
npzacs's avatar
npzacs committed
478
            if (!memcmp(aacs->disc_id, discid, 20)) {
479 480 481
                DEBUG(DBG_AACS, "Found config entry for discid %s\n",
                      aacs->ce->entry.discid);
                break;
482 483
            }

484
            aacs->ce = aacs->ce->next;
485
        }
486

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
        if (aacs->ce->entry.mek) {
            hexstring_to_hex_array(aacs->mk, sizeof(aacs->mk),
                                    aacs->ce->entry.mek);

            DEBUG(DBG_AACS, "Found media key for %s: %s\n",
                  aacs->ce->entry.discid, print_hex(str, aacs->mk, 16));

            retval = 1;
        }

        if (aacs->ce->entry.vid) {
            hexstring_to_hex_array(aacs->vid, sizeof(aacs->vid),
                                    aacs->ce->entry.vid);

            DEBUG(DBG_AACS, "Found volume id for %s: %s\n",
                  aacs->ce->entry.discid, print_hex(str, aacs->vid, 16));

            retval = 1;
        }

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
        if (aacs->ce->entry.vuk) {
            hexstring_to_hex_array(aacs->vuk, sizeof(aacs->vuk),
                                    aacs->ce->entry.vuk);

            DEBUG(DBG_AACS, "Found volume unique key for %s: %s\n",
                  aacs->ce->entry.discid, print_hex(str, aacs->vuk, 16));

            retval = 1;
        }

        if (aacs->ce && aacs->ce->entry.uk) {
            DEBUG(DBG_AACS, "Acquire CPS unit keys from keydb config file...\n");

            digit_key_pair_list *ukcursor = aacs->ce->entry.uk;
            while (ukcursor && ukcursor->key_pair.key) {
                aacs->num_uks++;

                aacs->uks = (uint8_t*)realloc(aacs->uks, 16 * aacs->num_uks);
                hexstring_to_hex_array(aacs->uks + (16 * (aacs->num_uks - 1)), 16,
                                      ukcursor->key_pair.key);

                char str[40];
                DEBUG(DBG_AACS, "Unit key %d from keydb entry: %s\n",
                      aacs->num_uks,
                      print_hex(str, aacs->uks + (16 * (aacs->num_uks - 1)), 16));

                ukcursor = ukcursor->next;
            }
        }
536 537
    }

538
    if (aacs->num_uks)
539
        retval = aacs->num_uks;
540 541

    return retval;
542 543
}

544
#define ALIGNED_UNIT_LEN 6144
545
static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
546
{
547 548 549 550 551 552 553
    gcry_cipher_hd_t gcry_h;
    int a;
    uint8_t key[16], iv[] = "\x0b\xa0\xf8\xdd\xfe\xa6\x1f\xb3"
                            "\xd8\xdf\x9f\x56\x6a\x05\x0f\x78";

    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
    gcry_cipher_setkey(gcry_h, aacs->uks + curr_uk * 16, 16);
554
    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
555
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
556

cRTrn13's avatar
cRTrn13 committed
557
    for (a = 0; a < 16; a++) {
558
        key[a] ^= in_buf[a];
cRTrn13's avatar
cRTrn13 committed
559 560
    }

561 562
    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */

563 564 565
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(gcry_h, key, 16);
    gcry_cipher_setiv(gcry_h, iv, 16);
566
    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 16, ALIGNED_UNIT_LEN - 16);
567
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
568

569
    if (_verify_ts(out_buf, ALIGNED_UNIT_LEN)) {
cRTrn13's avatar
cRTrn13 committed
570 571 572
        return 1;
    }

573
    if (curr_uk < aacs->num_uks - 1) {
574
        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
npzacs's avatar
npzacs committed
575 576
    }

cRTrn13's avatar
cRTrn13 committed
577 578 579
    return 0;
}

npzacs's avatar
npzacs committed
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
static int _load_config(AACS *aacs, const char *configfile_path)
{
    int config_ok = 0;

    aacs->cf = keydbcfg_new_config_file();

    /* try to load KEYDB.cfg */

    if (configfile_path) {
        config_ok = keydbcfg_parse_config(aacs->cf, configfile_path);

    } else {
        /* If no configfile path given, check for config files in user's home or
         * under /etc.
         */
        char *cfgfile = keydbcfg_find_config_file();
        config_ok = keydbcfg_parse_config(aacs->cf, cfgfile);
        X_FREE(cfgfile);
    }

    /* Try to load simple (aacskeys) config files */

    config_ok = keydbcfg_load_pk_file(aacs->cf)   || config_ok;
    config_ok = keydbcfg_load_cert_file(aacs->cf) || config_ok;

    if (!config_ok) {
        DEBUG(DBG_AACS, "No valid configuration files found!\n");
    }

    return config_ok;
}

cRTrn13's avatar
cRTrn13 committed
612
AACS *aacs_open(const char *path, const char *configfile_path)
cRTrn13's avatar
cRTrn13 committed
613
{
npzacs's avatar
npzacs committed
614
    DEBUG(DBG_AACS, "libaacs [%zd]\n", sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
615

616 617 618 619 620 621
    DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
    if (!crypto_init())
    {
        DEBUG(DBG_AACS, "Failed to initialize libgcrypt\n");
        return NULL;
    }
622

cRTrn13's avatar
cRTrn13 committed
623
    AACS *aacs = calloc(1, sizeof(AACS));
624

npzacs's avatar
npzacs committed
625
    if (_load_config(aacs, configfile_path)) {
626
        DEBUG(DBG_AACS, "Searching for keydb config entry...\n");
npzacs's avatar
npzacs committed
627
        _find_config_entry(aacs, path);
628

629
        DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
630
        if (_calc_uks(aacs, path)) {
npzacs's avatar
npzacs committed
631 632 633
            keydbcfg_config_file_close(aacs->cf);
            aacs->cf = NULL;

634 635
            DEBUG(DBG_AACS, "AACS initialized! (%p)\n", aacs);
            return aacs;
636
        }
637 638 639

        keydbcfg_config_file_close(aacs->cf);
        aacs->cf = NULL;
cRTrn13's avatar
cRTrn13 committed
640
    }
cRTrn13's avatar
cRTrn13 committed
641

npzacs's avatar
npzacs committed
642
    DEBUG(DBG_AACS, "Failed to initialize AACS! (%p)\n", aacs);
cRTrn13's avatar
cRTrn13 committed
643

644 645
    aacs_close(aacs);

cRTrn13's avatar
cRTrn13 committed
646
    return NULL;
cRTrn13's avatar
cRTrn13 committed
647 648
}

cRTrn13's avatar
cRTrn13 committed
649
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
650
{
651
    X_FREE(aacs->uks);
652
    X_FREE(aacs->cps_units);
653

npzacs's avatar
npzacs committed
654
    DEBUG(DBG_AACS, "AACS destroyed! (%p)\n", aacs);
cRTrn13's avatar
cRTrn13 committed
655

cRTrn13's avatar
cRTrn13 committed
656 657 658
    X_FREE(aacs);
}

659
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
660
{
661 662
    uint8_t out_buf[ALIGNED_UNIT_LEN];

663 664 665 666 667
    if (!(buf[0] & 0xc0)) {
        // TP_extra_header Copy_permission_indicator == 0, unit is not encrypted
        return 1;
    }

668
    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
669
        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
670 671 672 673 674 675 676

        // Clear copy_permission_indicator bits
        int i;
        for (i = 0; i < 6144; i += 192) {
            buf[i] &= ~0xc0;
        }

677 678 679
        return 1;
    }

680
    DEBUG(DBG_AACS, "Failed decrypting unit [6144 bytes] (%p)\n", aacs);
681

682
    return 0;
683
}
cRTrn13's avatar
cRTrn13 committed
684

npzacs's avatar
npzacs committed
685 686 687 688 689
const uint8_t *aacs_get_disc_id(AACS *aacs)
{
    return aacs->disc_id;
}

690
const uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
691 692 693
{
    return aacs->vid;
}
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720

void aacs_select_title(AACS *aacs, uint32_t title)
{
    if (!aacs) {
        return;
    }

    if (!aacs->cps_units) {
        DEBUG(DBG_AACS|DBG_CRIT, "aacs_select_title(): CPS units not read ! (%p)\n", aacs);
        return;
    }

    if (title == 0xffff) {
        /* first play */
        aacs->current_cps_unit = aacs->cps_units[0];
        DEBUG(DBG_AACS, "aacs_set_title(first_play): CPS unit %d (%p)\n", aacs->current_cps_unit, aacs);
        return;
    }

    if (title <= aacs->num_titles) {
        aacs->current_cps_unit = aacs->cps_units[title + 1];
        DEBUG(DBG_AACS, "aacs_set_title(%d): CPS unit %d (%p)\n", title, aacs->current_cps_unit, aacs);
        return;
    }

    DEBUG(DBG_AACS|DBG_CRIT, "aacs_set_title(%d): invalid title ! (%p)\n", title, aacs);
}