aacs.c 18.8 KB
Newer Older
1 2
/*
 * This file is part of libaacs
3
 * Copyright (C) 2009-2010  Obliter0n
4
 *
gates's avatar
gates committed
5 6 7 8
 * 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.
9
 *
gates's avatar
gates committed
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
gates's avatar
gates committed
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
14
 *
gates's avatar
gates committed
15 16 17
 * 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/>.
18 19
 */

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

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

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

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

npzacs's avatar
npzacs committed
44

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

    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
54 55
};

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

59 60
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
61
                        uint8_t *mk)
cRTrn13's avatar
cRTrn13 committed
62
{
63 64
    gcry_cipher_hd_t gcry_h;
    int a, ret = 0;
cRTrn13's avatar
cRTrn13 committed
65
    uint8_t dec_vd[16];
66
    char str[40];
cRTrn13's avatar
cRTrn13 committed
67

68
    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
cRTrn13's avatar
cRTrn13 committed
69
    DEBUG(DBG_AACS, " Using:\n");
70 71 72
    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));
73

74 75 76
    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);
77

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

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

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

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

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

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

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

108 109 110 111 112 113 114 115 116 117
    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
118

119 120
        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);
121 122 123 124 125
        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);
126 127 128
                DEBUG(DBG_AACS, "Trying processing key...\n");

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

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

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

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

    return 0;
}
151

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

157 158 159 160
    /* Skip if retrieved from config file */
    if (memcmp(aacs->vuk, empty_key, 16))
      return 1;

161 162
    DEBUG(DBG_AACS, "Calculate volume unique key...\n");

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
    /* 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));

        return 1;
    }

183
    cert_list *hccursor = aacs->cf->host_cert_list;
npzacs's avatar
npzacs committed
184
    while (hccursor && hccursor->host_priv_key && hccursor->host_cert) {
185
        uint8_t priv_key[20], cert[92];
186 187 188 189
        hexstring_to_hex_array(priv_key, sizeof(priv_key),
                               hccursor->host_priv_key);
        hexstring_to_hex_array(cert, sizeof(cert), hccursor->host_cert);

190
        if ((mmc = mmc_open(path, priv_key, cert))) {
191
            if (mmc_read_vid(mmc, aacs->vid)) {
192 193 194 195 196 197
                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
198

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

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

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

209 210 211 212
                return 1;
            }

            mmc_close(mmc);
cRTrn13's avatar
openssl  
cRTrn13 committed
213 214
        }

215
        hccursor = hccursor->next;
cRTrn13's avatar
cRTrn13 committed
216
    }
cRTrn13's avatar
openssl  
cRTrn13 committed
217

218 219
    DEBUG(DBG_AACS, "Error calculating VUK!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
220 221 222
    return 0;
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
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
272
static int _calc_uks(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
273
{
274
    AACS_FILE_H *fp = NULL;
275 276
    char    *f_name;
    uint8_t  buf[16];
277
    uint64_t f_pos;
278
    unsigned int i;
cRTrn13's avatar
openssl  
cRTrn13 committed
279

280 281
    /* Skip if retrieved from config file */
    if (aacs->uks)
282
        return 1;
283 284 285

    /* Fail if we don't have a volume unique key */
    if (!memcmp(aacs->vuk, empty_key, 16))
286
        return 0;
287

288 289
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

npzacs's avatar
npzacs committed
290
    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
291 292
    fp = file_open(f_name, "rb");
    X_FREE(f_name);
cRTrn13's avatar
openssl  
cRTrn13 committed
293

294
    if (fp) {
295
        if ((file_read(fp, buf, 4)) == 4) {
npzacs's avatar
npzacs committed
296
            f_pos = MKINT_BE32(buf);
cRTrn13's avatar
openssl  
cRTrn13 committed
297

npzacs's avatar
npzacs committed
298
            // Read number of keys
cRTrn13's avatar
cRTrn13 committed
299
            file_seek(fp, f_pos, SEEK_SET);
npzacs's avatar
npzacs committed
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
            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
323

324 325 326 327 328 329
                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
330

331
                char str[40];
gates's avatar
gates committed
332
                DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
333
                      print_hex(str, aacs->uks + 16*i, 16));
npzacs's avatar
npzacs committed
334
            }
cRTrn13's avatar
openssl  
cRTrn13 committed
335

336 337
            _read_uks_map(aacs, fp);

npzacs's avatar
npzacs committed
338
            file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
339

npzacs's avatar
npzacs committed
340
            return aacs->num_uks;
341 342 343
        }

        file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
344 345
    }

346 347
    DEBUG(DBG_AACS, "Could not calculate unit keys!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
348 349 350
    return 0;
}

351 352
static int _calc_title_hash(const char *path, uint8_t *title_hash)
{
353
    AACS_FILE_H *fp = NULL;
354 355 356 357 358
    uint8_t *ukf_buf;
    char     str[48];
    int64_t  f_size;
    char    *f_name;

npzacs's avatar
npzacs committed
359
    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375

    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
376

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
        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
393

npzacs's avatar
npzacs committed
394
static int _verify_ts(uint8_t *buf, size_t size)
395
{
396 397
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
398 399 400 401 402 403 404
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
405 406 407 408
            uint8_t *ptr2;

            for (ptr2=ptr; ptr2 < buf + size; ptr2 += 192) {
                if (*ptr2 != 0x47) {
cRTrn13's avatar
cRTrn13 committed
409 410
                    failed = 1;
                    break;
411 412
                }
            }
cRTrn13's avatar
cRTrn13 committed
413 414 415
            if (!failed) {
                return 1;
            }
416 417 418 419
        }
        ptr++;
    }

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

cRTrn13's avatar
cRTrn13 committed
422
    return 0;
423 424
}

425
/* Function that collects keys from keydb config entry */
npzacs's avatar
npzacs committed
426
static uint32_t _find_config_entry(AACS *aacs, const char *path)
427
{
428
    uint8_t hash[20], discid[20];
429
    char str[48];
430 431 432
    uint32_t retval = 0;
    aacs->uks = NULL;
    aacs->num_uks = 0;
cRTrn13's avatar
cRTrn13 committed
433

434
    if (!_calc_title_hash(path, hash)) {
cRTrn13's avatar
cRTrn13 committed
435 436 437
        return 0;
    }

npzacs's avatar
npzacs committed
438
    if (aacs->cf && aacs->cf->list) {
439 440 441 442 443 444
        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);
            if (!memcmp(hash, discid, 20)) {
445 446 447
                DEBUG(DBG_AACS, "Found config entry for discid %s\n",
                      aacs->ce->entry.discid);
                break;
448 449
            }

450
            aacs->ce = aacs->ce->next;
451
        }
452

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
        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;
        }

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
        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;
            }
        }
502 503
    }

504
    if (aacs->num_uks)
505
        retval = aacs->num_uks;
506 507

    return retval;
508 509
}

510
#define ALIGNED_UNIT_LEN 6144
511
static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
512
{
513 514 515 516 517 518 519
    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);
520
    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
521
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
522

cRTrn13's avatar
cRTrn13 committed
523
    for (a = 0; a < 16; a++) {
524
        key[a] ^= in_buf[a];
cRTrn13's avatar
cRTrn13 committed
525 526
    }

527 528
    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */

529 530 531
    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);
532
    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 16, ALIGNED_UNIT_LEN - 16);
533
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
534

535
    if (_verify_ts(out_buf, ALIGNED_UNIT_LEN)) {
cRTrn13's avatar
cRTrn13 committed
536 537 538
        return 1;
    }

539
    if (curr_uk < aacs->num_uks - 1) {
540
        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
npzacs's avatar
npzacs committed
541 542
    }

cRTrn13's avatar
cRTrn13 committed
543 544 545
    return 0;
}

npzacs's avatar
npzacs committed
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
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
578
AACS *aacs_open(const char *path, const char *configfile_path)
cRTrn13's avatar
cRTrn13 committed
579
{
npzacs's avatar
npzacs committed
580
    DEBUG(DBG_AACS, "libaacs [%zd]\n", sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
581

582 583 584 585 586 587
    DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
    if (!crypto_init())
    {
        DEBUG(DBG_AACS, "Failed to initialize libgcrypt\n");
        return NULL;
    }
588

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

npzacs's avatar
npzacs committed
591
    if (_load_config(aacs, configfile_path)) {
592 593
        DEBUG(DBG_AACS, "Searching for keydb config entry...\n");
        if(_find_config_entry(aacs, path)) {
594
            if (_calc_uks(aacs, path)) {
595 596 597
                keydbcfg_config_file_close(aacs->cf);
                aacs->cf = NULL;

npzacs's avatar
npzacs committed
598
                DEBUG(DBG_AACS, "AACS initialized! (%p)\n", aacs);
599 600 601 602
                return aacs;
            }
        }

603 604 605
        DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
        //_calc_pk(aacs);
        if (_calc_mk(aacs, path)) {
606
           if (_calc_vuk(aacs, path)) {
607
                if (_calc_uks(aacs, path)) {
npzacs's avatar
npzacs committed
608
                    DEBUG(DBG_AACS, "AACS initialized! (%p)\n", aacs);
609 610 611 612
                    return aacs;
                }
            }
        }
613 614 615

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

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

620 621
    aacs_close(aacs);

cRTrn13's avatar
cRTrn13 committed
622
    return NULL;
cRTrn13's avatar
cRTrn13 committed
623 624
}

cRTrn13's avatar
cRTrn13 committed
625
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
626
{
627
    X_FREE(aacs->uks);
628
    X_FREE(aacs->cps_units);
629

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

cRTrn13's avatar
cRTrn13 committed
632 633 634
    X_FREE(aacs);
}

635
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
636
{
637 638
    uint8_t out_buf[ALIGNED_UNIT_LEN];

639 640 641 642 643
    if (!(buf[0] & 0xc0)) {
        // TP_extra_header Copy_permission_indicator == 0, unit is not encrypted
        return 1;
    }

644
    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
645
        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
646 647 648 649 650 651 652

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

653 654 655
        return 1;
    }

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

658
    return 0;
659
}
cRTrn13's avatar
cRTrn13 committed
660

661
const uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
662 663 664
{
    return aacs->vid;
}
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691

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);
}