aacs.c 19.2 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>

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

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

npzacs's avatar
npzacs committed
46

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

    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
56 57
};

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

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

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

76 77 78
    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);
79

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

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

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

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

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

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

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

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

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

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

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

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

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

npzacs's avatar
npzacs committed
150 151 152
        DEBUG(DBG_AACS | DBG_CRIT, "Error calculating media key. Missing right processing key ?\n");
        return 0;
    }
npzacs's avatar
npzacs committed
153

npzacs's avatar
npzacs committed
154
    DEBUG(DBG_AACS | DBG_CRIT, "Error opening %s/AACS/MKB_RO.inf\n", path);
cRTrn13's avatar
keyfile  
cRTrn13 committed
155 156
    return 0;
}
157

158
static int _read_vid(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
159
{
160 161 162 163 164
    /* Use VID given in config file if available */
    if (memcmp(aacs->vid, empty_key, 16)) {
        return 1;
    }

cRTrn13's avatar
cRTrn13 committed
165
    MMC* mmc = NULL;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    if (!(mmc = mmc_open(path))) {
        return 0;
    }

    cert_list *hccursor = aacs->cf->host_cert_list;
    while (hccursor && hccursor->host_priv_key && hccursor->host_cert) {

        char tmp_str[2*92+1];
        uint8_t priv_key[20], cert[92];
        hexstring_to_hex_array(priv_key, sizeof(priv_key), hccursor->host_priv_key);
        hexstring_to_hex_array(cert,     sizeof(cert),     hccursor->host_cert);

        if (!crypto_aacs_verify_host_cert(cert)) {
	    DEBUG(DBG_AACS, "Not using invalid host certificate %s.\n",
		  print_hex(tmp_str, cert, 92));

	    hccursor = hccursor->next;
	    continue;
	}

        DEBUG(DBG_AACS, "Trying host certificate (id 0x%s)...\n",
              print_hex(tmp_str, cert + 4, 6));

npzacs's avatar
npzacs committed
189 190
        int mmc_result = mmc_read_vid(mmc, priv_key, cert, aacs->vid);
        if (mmc_result == MMC_SUCCESS) {
191 192 193 194 195 196 197 198 199 200 201 202
            mmc_close(mmc);
            return 1;
        }

        hccursor = hccursor->next;
    }

    mmc_close(mmc);

    DEBUG(DBG_AACS, "Error reading VID!\n");
    return 0;
}
cRTrn13's avatar
openssl  
cRTrn13 committed
203

204 205
static int _calc_vuk(AACS *aacs, const char *path)
{
206 207 208 209
    /* Skip if retrieved from config file */
    if (memcmp(aacs->vuk, empty_key, 16))
      return 1;

npzacs's avatar
npzacs committed
210 211 212 213 214 215
    /* get cached vuk */
    if (keycache_find("vuk", aacs->disc_id, aacs->vuk, 16)) {
        DEBUG(DBG_AACS, "Using cached VUK\n");
        return 1;
    }

216 217 218 219 220
    /* make sure we have media key */
    if (!_calc_mk(aacs, path)) {
        return 0;
    }

221 222
    DEBUG(DBG_AACS, "Calculate volume unique key...\n");

223 224 225
    if (_read_vid(aacs, path)) {

        int a;
226
        gcry_cipher_hd_t gcry_h;
227

228 229 230 231 232 233 234 235 236 237
        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];
238
        DEBUG(DBG_AACS, "Volume unique key: %s\n", print_hex(str, aacs->vuk, 16));
239

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

243 244 245
        return 1;
    }

246 247
    DEBUG(DBG_AACS, "Error calculating VUK!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
248 249 250
    return 0;
}

251 252
static uint16_t _read_u16(AACS_FILE_H *fp)
{
npzacs's avatar
npzacs committed
253
  uint8_t data[2] = {0, 0};
254 255 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

  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
300
static int _calc_uks(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
301
{
302
    AACS_FILE_H *fp = NULL;
303 304
    char    *f_name;
    uint8_t  buf[16];
305
    uint64_t f_pos;
306
    unsigned int i;
cRTrn13's avatar
openssl  
cRTrn13 committed
307

308 309
    /* Skip if retrieved from config file */
    if (aacs->uks)
310
        return 1;
311

312 313
    /* Make sure we have VUK */
    if (!_calc_vuk(aacs, path)) {
314
        return 0;
315
    }
316

317 318
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

npzacs's avatar
npzacs committed
319
    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
320 321
    fp = file_open(f_name, "rb");
    X_FREE(f_name);
cRTrn13's avatar
openssl  
cRTrn13 committed
322

323
    if (fp) {
324
        if ((file_read(fp, buf, 4)) == 4) {
npzacs's avatar
npzacs committed
325
            f_pos = MKINT_BE32(buf);
cRTrn13's avatar
openssl  
cRTrn13 committed
326

npzacs's avatar
npzacs committed
327
            // Read number of keys
cRTrn13's avatar
cRTrn13 committed
328
            file_seek(fp, f_pos, SEEK_SET);
npzacs's avatar
npzacs committed
329 330 331 332 333 334 335 336 337 338
            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;
npzacs's avatar
npzacs committed
339
                DEBUG(DBG_AACS | DBG_CRIT, "Error reading number of unit keys\n");
npzacs's avatar
npzacs committed
340 341 342 343 344 345 346 347
            }

            // 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) {
npzacs's avatar
npzacs committed
348
                    DEBUG(DBG_AACS | DBG_CRIT, "Unit key %d: read error\n", i);
npzacs's avatar
npzacs committed
349 350 351
                    aacs->num_uks = i;
                    break;
                }
cRTrn13's avatar
openssl  
cRTrn13 committed
352

353 354 355 356 357 358
                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
359

360
                char str[40];
gates's avatar
gates committed
361
                DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
362
                      print_hex(str, aacs->uks + 16*i, 16));
npzacs's avatar
npzacs committed
363
            }
cRTrn13's avatar
openssl  
cRTrn13 committed
364

365 366
            _read_uks_map(aacs, fp);

npzacs's avatar
npzacs committed
367
            file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
368

npzacs's avatar
npzacs committed
369
            return aacs->num_uks;
370 371 372
        }

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

npzacs's avatar
npzacs committed
374 375 376
        DEBUG(DBG_AACS | DBG_CRIT, "Error reading unit keys\n");
        return 0;
    }
377

npzacs's avatar
npzacs committed
378
    DEBUG(DBG_AACS | DBG_CRIT, "Error opening %s/AACS/Unit_Key_RO.inf\n", path);
cRTrn13's avatar
openssl  
cRTrn13 committed
379 380 381
    return 0;
}

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

npzacs's avatar
npzacs committed
390
    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
391 392

    if (!(fp = file_open(f_name, "rb"))) {
npzacs's avatar
npzacs committed
393
        DEBUG(DBG_AACS | DBG_CRIT, "Error opening unit key file %s\n", f_name);
394 395 396 397 398 399 400 401 402 403 404 405 406
        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
407

npzacs's avatar
npzacs committed
408
        DEBUG(DBG_AACS | DBG_CRIT, "Failed to read %"PRIu64" bytes from unit key file %s\n", f_size, f_name);
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423

        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
424

npzacs's avatar
npzacs committed
425
static int _verify_ts(uint8_t *buf, size_t size)
426
{
427 428
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
429 430 431 432 433 434 435
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
436 437 438 439
            uint8_t *ptr2;

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

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

cRTrn13's avatar
cRTrn13 committed
453
    return 0;
454 455
}

456
/* Function that collects keys from keydb config entry */
457
static void _find_config_entry(AACS *aacs)
458
{
npzacs's avatar
npzacs committed
459
    uint8_t discid[20];
460
    char str[48];
npzacs's avatar
npzacs committed
461

462 463
    aacs->uks = NULL;
    aacs->num_uks = 0;
cRTrn13's avatar
cRTrn13 committed
464

npzacs's avatar
npzacs committed
465
    if (aacs->cf && aacs->cf->list) {
466 467 468 469 470
        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
471
            if (!memcmp(aacs->disc_id, discid, 20)) {
472 473 474
                DEBUG(DBG_AACS, "Found config entry for discid %s\n",
                      aacs->ce->entry.discid);
                break;
475 476
            }

477
            aacs->ce = aacs->ce->next;
478
        }
479

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
        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));
        }

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

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

        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;
            }
        }
523
    }
524 525
}

526
#define ALIGNED_UNIT_LEN 6144
527
static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
528
{
529 530 531 532 533 534 535
    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);
536
    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
537
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
538

cRTrn13's avatar
cRTrn13 committed
539
    for (a = 0; a < 16; a++) {
540
        key[a] ^= in_buf[a];
cRTrn13's avatar
cRTrn13 committed
541 542
    }

543 544
    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */

545 546 547
    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);
548
    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 16, ALIGNED_UNIT_LEN - 16);
549
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
550

551
    if (_verify_ts(out_buf, ALIGNED_UNIT_LEN)) {
cRTrn13's avatar
cRTrn13 committed
552 553 554
        return 1;
    }

555
    if (curr_uk < aacs->num_uks - 1) {
556
        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
npzacs's avatar
npzacs committed
557 558
    }

cRTrn13's avatar
cRTrn13 committed
559 560 561
    return 0;
}

npzacs's avatar
npzacs committed
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
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) {
npzacs's avatar
npzacs committed
588
        DEBUG(DBG_AACS | DBG_CRIT, "No valid AACS configuration files found\n");
npzacs's avatar
npzacs committed
589 590 591 592 593
    }

    return config_ok;
}

npzacs's avatar
npzacs committed
594 595
void aacs_get_version(int *major, int *minor, int *micro)
{
npzacs's avatar
npzacs committed
596 597 598
    *major = AACS_VERSION_MAJOR;
    *minor = AACS_VERSION_MINOR;
    *micro = AACS_VERSION_MICRO;
npzacs's avatar
npzacs committed
599 600
}

cRTrn13's avatar
cRTrn13 committed
601
AACS *aacs_open(const char *path, const char *configfile_path)
cRTrn13's avatar
cRTrn13 committed
602
{
npzacs's avatar
npzacs committed
603
    DEBUG(DBG_AACS, "libaacs [%zd]\n", sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
604

605 606 607
    DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
    if (!crypto_init())
    {
npzacs's avatar
npzacs committed
608
        DEBUG(DBG_AACS | DBG_CRIT, "Failed to initialize libgcrypt\n");
609 610
        return NULL;
    }
611

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

614 615 616 617 618
    if (!_calc_title_hash(path, aacs->disc_id)) {
        aacs_close(aacs);
        return NULL;
    }

npzacs's avatar
npzacs committed
619
    if (_load_config(aacs, configfile_path)) {
620
        DEBUG(DBG_AACS, "Searching for keydb config entry...\n");
621
        _find_config_entry(aacs);
622

623
        DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
624
        if (_calc_uks(aacs, path)) {
npzacs's avatar
npzacs committed
625 626 627
            keydbcfg_config_file_close(aacs->cf);
            aacs->cf = NULL;

628 629
            DEBUG(DBG_AACS, "AACS initialized! (%p)\n", aacs);
            return aacs;
630
        }
631 632 633

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

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

638 639
    aacs_close(aacs);

cRTrn13's avatar
cRTrn13 committed
640
    return NULL;
cRTrn13's avatar
cRTrn13 committed
641 642
}

cRTrn13's avatar
cRTrn13 committed
643
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
644
{
645
    X_FREE(aacs->uks);
646
    X_FREE(aacs->cps_units);
647

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

cRTrn13's avatar
cRTrn13 committed
650 651 652
    X_FREE(aacs);
}

653
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
654
{
655 656
    uint8_t out_buf[ALIGNED_UNIT_LEN];

657 658 659 660 661
    if (!(buf[0] & 0xc0)) {
        // TP_extra_header Copy_permission_indicator == 0, unit is not encrypted
        return 1;
    }

662
    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
663
        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
664 665 666 667 668 669 670

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

671 672 673
        return 1;
    }

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

676
    return 0;
677
}
cRTrn13's avatar
cRTrn13 committed
678

npzacs's avatar
npzacs committed
679 680 681 682 683
const uint8_t *aacs_get_disc_id(AACS *aacs)
{
    return aacs->disc_id;
}

684
const uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
685 686 687
{
    return aacs->vid;
}
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714

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