<commit_before>/*
 * This file is part of libaacs
 * Copyright (C) 2009-2010  Obliter0n
 * Copyright (C) 2009-2010  npzacs
 *
 * 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.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * 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/>.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <util/attributes.h>

#include "aacs-version.h"
#include "aacs.h"
#include "crypto.h"
#include "mmc.h"
#include "mkb.h"
#include "file/file.h"
#include "file/keydbcfg.h"
#include "util/macro.h"
#include "util/logging.h"
#include "util/strutl.h"

#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <gcrypt.h>


struct aacs {
    /* current disc */
    char     *path;
    int       mkb_version;
    uint8_t   disc_id[20];

    /* VID is cached for BD-J */
    uint8_t   vid[16];

    /* unit key for each CPS unit */
    uint32_t  num_uks;
    uint8_t  *uks;

    /* CPS unit of currently selected title */
    uint16_t  current_cps_unit;

    /* title -> CPS unit mappings */
    uint32_t  num_titles;
    uint16_t *cps_units;  /* [0] = first play ; [1] = top menu ; [2] = title 1 ... */
};

static const uint8_t empty_key[] = <KEY>"
                                   <KEY>";

static int _validate_pk(const uint8_t *pk,
                        const uint8_t *cvalue, const uint8_t *uv, const uint8_t *vd,
                        uint8_t *mk)
{
    gcry_cipher_hd_t gcry_h;
    int a;
    uint8_t dec_vd[16];
    char str[40];

    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
    DEBUG(DBG_AACS, " Using:\n");
    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));

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

    for (a = 0; a < 4; a++) {
        mk[a + 12] ^= uv[a];
    }

    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);
    gcry_cipher_close(gcry_h);

    if (!memcmp(dec_vd, "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8)) {
        DEBUG(DBG_AACS, "Processing key %s is valid!\n", print_hex(str, pk, 16));
        return AACS_SUCCESS;
    }

    return AACS_ERROR_NO_PK;
}

static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
{
    int a, num_uvs = 0;
    size_t len;
    uint8_t *buf = NULL;
    MKB *mkb = NULL;
    const uint8_t *rec, *uvs;

    /* Skip if retrieved from config file */
    if (memcmp(mk, empty_key, 16)) {
        return AACS_SUCCESS;
    }

    DEBUG(DBG_AACS, "Calculate media key...\n");

    if ((mkb = mkb_open(aacs->path))) {
        DEBUG(DBG_AACS, "Get UVS...\n");
        aacs->mkb_version = mkb_version(mkb);
        uvs = mkb_subdiff_records(mkb, &len);
        rec = uvs;
        while (rec < uvs + len) {
            if (rec[0] & 0xc0)
                break;
            rec += 5;
            num_uvs++;
        }

        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);

        for (; pkl && pkl->key; pkl = pkl->next) {<commit_msg>Update cached drive revocation list when mkb is opened<commit_after>/*
 * This file is part of libaacs
 * Copyright (C) 2009-2010  Obliter0n
 * Copyright (C) 2009-2010  npzacs
 *
 * 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.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * 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/>.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <util/attributes.h>

#include "aacs-version.h"
#include "aacs.h"
#include "crypto.h"
#include "mmc.h"
#include "mkb.h"
#include "file/file.h"
#include "file/keydbcfg.h"
#include "util/macro.h"
#include "util/logging.h"
#include "util/strutl.h"

#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <gcrypt.h>


struct aacs {
    /* current disc */
    char     *path;
    int       mkb_version;
    uint8_t   disc_id[20];

    /* VID is cached for BD-J */
    uint8_t   vid[16];

    /* unit key for each CPS unit */
    uint32_t  num_uks;
    uint8_t  *uks;

    /* CPS unit of currently selected title */
    uint16_t  current_cps_unit;

    /* title -> CPS unit mappings */
    uint32_t  num_titles;
    uint16_t *cps_units;  /* [0] = first play ; [1] = top menu ; [2] = title 1 ... */
};

static const uint8_t empty_key[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
                                   "\x00\x00\x00\x00\x00\x00\x00\x00";

static int _validate_pk(const uint8_t *pk,
                        const uint8_t *cvalue, const uint8_t *uv, const uint8_t *vd,
                        uint8_t *mk)
{
    gcry_cipher_hd_t gcry_h;
    int a;
    uint8_t dec_vd[16];
    char str[40];

    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
    DEBUG(DBG_AACS, " Using:\n");
    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));

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

    for (a = 0; a < 4; a++) {
        mk[a + 12] ^= uv[a];
    }

    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);
    gcry_cipher_close(gcry_h);

    if (!memcmp(dec_vd, "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8)) {
        DEBUG(DBG_AACS, "Processing key %s is valid!\n", print_hex(str, pk, 16));
        return AACS_SUCCESS;
    }

    return AACS_ERROR_NO_PK;
}

static int _rl_verify_signature(const uint8_t *rl, size_t size)
{
    int    entries = MKINT_BE32(rl + 12 + 8);
    size_t len     = 12 + 12 + 8 * entries; /* type_and_version_rec=12, rl_header=12, rl=entries*8 */

    if (len + 40 > size) {
        DEBUG(DBG_AACS, "revocation list size mismatch\n");
        return 0;
    }

    return crypto_aacs_verify_aacsla(rl + len, rl, len);
}

static void _update_drl(MKB *mkb)
{
    uint32_t version = mkb_version(mkb);
    uint32_t cache_version;

    if (!cache_get("drl", &cache_version, NULL, NULL) || cache_version < version) {
        size_t drl_len;
        const uint8_t *drl_rec = mkb_drive_revokation_entries(mkb, &drl_len);
        const uint8_t *v_rec   = mkb_type_and_version_record(mkb);

        if (drl_rec && v_rec) {
            drl_rec -= 4;
            drl_len += 4;

            uint8_t *data = malloc(12 + drl_len);
            memcpy(data,      v_rec,   12);
            memcpy(data + 12, drl_rec, drl_len);
            if (!_rl_verify_signature(data, drl_len + 12)) {
                DEBUG(DBG_AACS | DBG_CRIT, "invalid drive revocation list signature, not using it\n");
            } else {
                cache_save("drl", version, data, drl_len + 12);
            }
            X_FREE(data);
        }
    }
}

static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
{
    int a, num_uvs = 0;
    size_t len;
    uint8_t *buf = NULL;
    MKB *mkb = NULL;
    const uint8_t *rec, *uvs;

    /* Skip if retrieved from config file */
    if (memcmp(mk, empty_key, 16)) {
        return AACS_SUCCESS;
    }

    DEBUG(DBG_AACS, "Calculate media key...\n");

    if ((mkb = mkb_open(aacs->path))) {
        DEBUG(DBG_AACS, "Get UVS...\n");
        _update_drl(mkb);
        aacs->mkb_version = mkb_version(mkb);
        uvs = mkb_subdiff_records(mkb, &len);
        rec = uvs;
        while (rec < uvs + len) {
            if (rec[0] & 0xc0)
                break;
            rec += 5;
            num_uvs++;
        }

        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);

        for (; pkl && pkl->key; pkl = pkl->next) {
{'fraction_non_alphanumeric': 0.13052208835341367, 'fraction_numerical': 0.02922802320392682, 'mean_word_length': 2.542078229948637, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1503570', 'n_tokens_mistral': 3655, 'n_tokens_neox': 3345, 'n_words': 894}