aacs.c 9.65 KB
Newer Older
Accident's avatar
 
Accident committed
1 2 3
#if HAVE_CONFIG_H
#include "config.h"
#endif
cRTrn13's avatar
cRTrn13 committed
4

Accident's avatar
 
Accident committed
5
#if HAVE_MALLOC_H
cRTrn13's avatar
cRTrn13 committed
6
#include <malloc.h>
Accident's avatar
 
Accident committed
7 8 9 10 11 12 13
#endif

#if HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <stdio.h>
cRTrn13's avatar
openssl  
cRTrn13 committed
14
#include <string.h>
cRTrn13's avatar
cRTrn13 committed
15
#include <gcrypt.h>
cRTrn13's avatar
cRTrn13 committed
16 17

#include "aacs.h"
18
#include "crypto.h"
cRTrn13's avatar
cRTrn13 committed
19
#include "mmc.h"
cRTrn13's avatar
cRTrn13 committed
20
#include "../util/macro.h"
21
#include "../util/logging.h"
22
#include "../file/file.h"
cRTrn13's avatar
cRTrn13 committed
23

cRTrn13's avatar
cRTrn13 committed
24 25
int _validate_pk(uint8_t *pk, uint8_t *cvalue, uint8_t *uv, uint8_t *vd, uint8_t *mk)
{
26 27
    int a, ret = 0;
    gcry_cipher_hd_t gcry_h;
cRTrn13's avatar
cRTrn13 committed
28 29 30 31 32 33 34
    uint8_t dec_vd[16];

    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(pk, 16));
    DEBUG(DBG_AACS, " Using:\n");
    DEBUG(DBG_AACS, "   UV: %s\n", print_hex(uv, 4));
    DEBUG(DBG_AACS, "   cvalue: %s\n", print_hex(cvalue, 16));
    DEBUG(DBG_AACS, "   Verification data: %s\n", print_hex(vd, 16));
35

cRTrn13's avatar
cRTrn13 committed
36
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
37 38 39 40

    gcry_cipher_setkey(gcry_h, pk, 16);
    gcry_cipher_decrypt (gcry_h, mk, 16, cvalue, 16);

cRTrn13's avatar
cRTrn13 committed
41 42 43 44
    for (a = 0; a < 4; a++) {
        mk[a + 12] ^= uv[a];
    }

45 46 47
    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);

cRTrn13's avatar
cRTrn13 committed
48 49
    if (!memcmp(dec_vd, "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8)) {
        DEBUG(DBG_AACS, "Processing key is valid!\n");
50
        ret = 1;
cRTrn13's avatar
cRTrn13 committed
51 52
    }

53 54 55
    gcry_cipher_close(gcry_h);

    return ret;
cRTrn13's avatar
cRTrn13 committed
56
}
57

cRTrn13's avatar
cRTrn13 committed
58
int _calc_mk(AACS *aacs, const char *path)
cRTrn13's avatar
keyfile  
cRTrn13 committed
59 60 61
{
    int a, num_uvs = 0;
    size_t len;
cRTrn13's avatar
cRTrn13 committed
62
    uint8_t *buf = NULL, *rec, *uvs, *key_pos, *pks;
cRTrn13's avatar
cRTrn13 committed
63
    uint16_t num_pks;
cRTrn13's avatar
keyfile  
cRTrn13 committed
64 65
    MKB *mkb = NULL;

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

68 69 70 71 72 73 74 75 76 77
    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
78

79 80 81 82 83 84 85 86 87 88 89 90
        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);
        if ((pks = configfile_record(aacs->kf, KF_PK_ARRAY, &num_pks, NULL))) {
            key_pos = pks;
            while (key_pos < pks + num_pks * 16) {
                memcpy(aacs->pk, key_pos, 16);
                DEBUG(DBG_AACS, "Trying processing key...\n");

                for (a = 0; a < num_uvs; a++) {
                    if (_validate_pk(aacs->pk, rec + a * 16, uvs + 1 + a * 5, mkb_mk_dv(mkb), aacs->mk)) {
                        mkb_close(mkb);
                        X_FREE(buf);
91 92

                        DEBUG(DBG_AACS, "Media key: %s\n", print_hex(aacs->mk, 16));
93 94 95 96 97
                        return 1;
                    }
                }

                key_pos += 16;
cRTrn13's avatar
keyfile  
cRTrn13 committed
98
            }
99
        }
cRTrn13's avatar
keyfile  
cRTrn13 committed
100

101 102
        mkb_close(mkb);
        X_FREE(buf);
cRTrn13's avatar
keyfile  
cRTrn13 committed
103 104 105 106
    }

    return 0;
}
107

cRTrn13's avatar
cRTrn13 committed
108
int _calc_vuk(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
109 110
{
    int a;
cRTrn13's avatar
cRTrn13 committed
111
    MMC* mmc = NULL;
cRTrn13's avatar
cRTrn13 committed
112
    gcry_cipher_hd_t gcry_h;
cRTrn13's avatar
openssl  
cRTrn13 committed
113

114 115
    DEBUG(DBG_AACS, "Calculate volume unique key...\n");

cRTrn13's avatar
cRTrn13 committed
116
    if ((mmc = mmc_open(path,
cRTrn13's avatar
cRTrn13 committed
117 118 119 120
            configfile_record(aacs->kf, KF_HOST_PRIV_KEY, NULL, NULL),
            configfile_record(aacs->kf, KF_HOST_CERT, NULL, NULL),
            configfile_record(aacs->kf, KF_HOST_NONCE, NULL, NULL),
            configfile_record(aacs->kf, KF_HOST_KEY_POINT, NULL, NULL)))) {
121
        if (mmc_read_vid(mmc, aacs->vid)) {
cRTrn13's avatar
cRTrn13 committed
122 123 124 125 126 127
            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
openssl  
cRTrn13 committed
128 129

            for (a = 0; a < 16; a++) {
130
                aacs->vuk[a] ^= aacs->vid[a];
cRTrn13's avatar
openssl  
cRTrn13 committed
131
            }
cRTrn13's avatar
cRTrn13 committed
132 133

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

135 136
            DEBUG(DBG_AACS, "Volume unique key: %s\n", print_hex(aacs->vuk, 16));

cRTrn13's avatar
openssl  
cRTrn13 committed
137 138 139
            return 1;
        }

cRTrn13's avatar
cRTrn13 committed
140 141
        mmc_close(mmc);
    }
cRTrn13's avatar
openssl  
cRTrn13 committed
142

143 144
    DEBUG(DBG_AACS, "Error calculating VUK!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
145 146 147
    return 0;
}

cRTrn13's avatar
cRTrn13 committed
148
int _calc_uks(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
149
{
150
    FILE_H *fp = NULL;
151
    uint8_t buf[16];
cRTrn13's avatar
openssl  
cRTrn13 committed
152
    char f_name[100];
153
    uint64_t f_pos;
cRTrn13's avatar
cRTrn13 committed
154
    gcry_cipher_hd_t gcry_h;
cRTrn13's avatar
openssl  
cRTrn13 committed
155

156 157 158
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

    snprintf(f_name , 100, "/%s/AACS/Unit_Key_RO.inf", path);
cRTrn13's avatar
openssl  
cRTrn13 committed
159

160
    if ((fp = file_open(f_name, "rb"))) {
161 162
        if ((file_read(fp, buf, 4)) == 4) {
            f_pos = MKINT_BE32(buf) + 48;
cRTrn13's avatar
openssl  
cRTrn13 committed
163

cRTrn13's avatar
cRTrn13 committed
164
            file_seek(fp, f_pos, SEEK_SET);
165 166 167
            if ((file_read(fp, buf, 16)) == 16) {
                // TODO: support more than a single UK!!!
                aacs->uks = malloc(16);
cRTrn13's avatar
openssl  
cRTrn13 committed
168

cRTrn13's avatar
cRTrn13 committed
169 170 171 172 173 174
                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, buf, 16);

                gcry_cipher_close(gcry_h);
cRTrn13's avatar
openssl  
cRTrn13 committed
175

176
                file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
177

178
                DEBUG(DBG_AACS, "Unit key 1: %s\n", print_hex(aacs->uks, 16));
cRTrn13's avatar
openssl  
cRTrn13 committed
179

180 181 182 183 184
                return 1;
            }
        }

        file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
185 186
    }

187 188
    DEBUG(DBG_AACS, "Could not calculate unit keys!\n");

cRTrn13's avatar
openssl  
cRTrn13 committed
189 190 191
    return 0;
}

cRTrn13's avatar
cRTrn13 committed
192 193


194 195
int _verify_ts(uint8_t *buf, size_t size)
{
196 197
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
198 199 200 201 202 203 204
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
205 206 207 208
            uint8_t *ptr2;

            for (ptr2=ptr; ptr2 < buf + size; ptr2 += 192) {
                if (*ptr2 != 0x47) {
cRTrn13's avatar
cRTrn13 committed
209 210
                    failed = 1;
                    break;
211 212
                }
            }
cRTrn13's avatar
cRTrn13 committed
213 214 215
            if (!failed) {
                return 1;
            }
216 217 218 219
        }
        ptr++;
    }

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

cRTrn13's avatar
cRTrn13 committed
222
    return 0;
223 224
}

cRTrn13's avatar
cRTrn13 committed
225
int _find_vuk(AACS *aacs, const char *path)
226
{
cRTrn13's avatar
cRTrn13 committed
227
    uint8_t *vuks, *key_pos, hash[20], *ukf_buf;
cRTrn13's avatar
cRTrn13 committed
228
    FILE_H *fp = NULL;
cRTrn13's avatar
cRTrn13 committed
229
    uint64_t f_size;
230
    uint16_t num_vuks;
cRTrn13's avatar
cRTrn13 committed
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
    char f_name[100];

    snprintf(f_name , 100, "/%s/AACS/Unit_Key_RO.inf", path);

    if ((fp = file_open(f_name, "rb"))) {
        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) {

        } else {
            DEBUG(DBG_AACS, "Failed to read %d bytes from unit key file!\n", f_size);
            file_close(fp);
            X_FREE(ukf_buf);
            return 0;
        }
    } else {
        DEBUG(DBG_AACS, "Failed to open unit key file: %s!\n", f_name);
        return 0;
    }

    file_close(fp);
256

257
    crypto_aacs_title_hash(ukf_buf, f_size, hash);
cRTrn13's avatar
cRTrn13 committed
258 259
    DEBUG(DBG_AACS, "Disc ID: %s\n", print_hex(hash, 20));

cRTrn13's avatar
cRTrn13 committed
260 261
    X_FREE(ukf_buf);

262 263 264
    if ((vuks = configfile_record(aacs->kf, KF_VUK_ARRAY, &num_vuks, NULL))) {
        key_pos = vuks;
        while (key_pos < vuks + num_vuks * 46) {
cRTrn13's avatar
cRTrn13 committed
265
            if (!memcmp(hash, key_pos, 20)) {
266 267
                uint8_t desc[11];

cRTrn13's avatar
cRTrn13 committed
268
                memcpy(desc, key_pos + 20, 10);
269 270
                desc[10] = 0;

cRTrn13's avatar
cRTrn13 committed
271
                memcpy(aacs->vuk, key_pos + 30, 16);
272 273

                DEBUG(DBG_AACS, "Found volume unique key for %s: %s\n", desc, print_hex(aacs->vuk, 16));
274 275

                return 1;
276 277 278 279 280 281
            }

            key_pos += 46;
        }
    }

282
    return 0;
283 284
}

cRTrn13's avatar
cRTrn13 committed
285
int _decrypt_unit(AACS *aacs, uint8_t *buf, uint32_t len, uint64_t offset, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
286
{
cRTrn13's avatar
cRTrn13 committed
287
    gcry_cipher_hd_t gcry_h;
cRTrn13's avatar
cRTrn13 committed
288 289 290 291
    uint8_t *tmp_buf = malloc(len);

    memcpy(tmp_buf, buf, len);

cRTrn13's avatar
cRTrn13 committed
292 293
    int a;
    uint8_t key[16], iv[] = { 0x0b, 0xa0, 0xf8, 0xdd, 0xfe, 0xa6, 0x1f, 0xb3, 0xd8, 0xdf, 0x9f, 0x56, 0x6a, 0x05, 0x0f, 0x78 };
cRTrn13's avatar
cRTrn13 committed
294

cRTrn13's avatar
cRTrn13 committed
295
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
cRTrn13's avatar
cRTrn13 committed
296

cRTrn13's avatar
cRTrn13 committed
297 298
    gcry_cipher_setkey(gcry_h, aacs->uks + curr_uk * 16, 16);
    gcry_cipher_encrypt(gcry_h, key, 16, tmp_buf, 16);
cRTrn13's avatar
cRTrn13 committed
299

cRTrn13's avatar
cRTrn13 committed
300
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
301

cRTrn13's avatar
cRTrn13 committed
302 303
    for (a = 0; a < 16; a++) {
        key[a] ^= tmp_buf[a];
cRTrn13's avatar
cRTrn13 committed
304 305
    }

cRTrn13's avatar
cRTrn13 committed
306 307 308 309 310 311 312 313
    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);
    gcry_cipher_decrypt(gcry_h, tmp_buf + 16, len - 16, tmp_buf + 16, len - 16);

    gcry_cipher_close(gcry_h);

cRTrn13's avatar
cRTrn13 committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    if (_verify_ts(tmp_buf,len)) {
        DEBUG(DBG_AACS, "Decrypted %s unit [%d bytes] from offset %ld (0x%08x)\n", len % 6144 ? "PARTIAL" : "FULL", len, offset, aacs);

        memcpy(buf, tmp_buf, len);

        X_FREE(tmp_buf);

        return 1;
    } else if (curr_uk < aacs->num_uks - 1) {
        return _decrypt_unit(aacs, buf, len, offset, curr_uk++);
    }

    X_FREE(tmp_buf);

    return 0;
}

cRTrn13's avatar
cRTrn13 committed
331
AACS *aacs_open(const char *path, const char *configfile_path)
cRTrn13's avatar
cRTrn13 committed
332
{
cRTrn13's avatar
cRTrn13 committed
333
    DEBUG(DBG_AACS, "libaacs v%s [%ld]\n", LIBAACS_VERSION, sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
334

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

cRTrn13's avatar
cRTrn13 committed
337
    if ((aacs->kf = configfile_open(configfile_path))) {
338 339 340 341
        DEBUG(DBG_AACS, "Searching for VUK...\n");
        if(_find_vuk(aacs, path)) {
            if (_calc_uks(aacs, path)) {
                configfile_close(aacs->kf);
342
                aacs->kf = NULL;
343 344 345 346 347 348

                DEBUG(DBG_AACS, "AACS initialized! (0x%08x)\n", aacs);
                return aacs;
            }
        }

349 350 351
        DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
        //_calc_pk(aacs);
        if (_calc_mk(aacs, path)) {
352
           if (_calc_vuk(aacs, path)) {
353
                if (_calc_uks(aacs, path)) {
cRTrn13's avatar
cRTrn13 committed
354
                    configfile_close(aacs->kf);
355
                    aacs->kf = NULL;
356 357

                    DEBUG(DBG_AACS, "AACS initialized! (0x%08x)\n", aacs);
358 359 360 361
                    return aacs;
                }
            }
        }
362 363 364

        configfile_close(aacs->kf);
        aacs->kf = NULL;
cRTrn13's avatar
cRTrn13 committed
365
    }
cRTrn13's avatar
cRTrn13 committed
366

cRTrn13's avatar
cRTrn13 committed
367 368
    DEBUG(DBG_AACS, "Failed to initialize AACS! (0x%08x)\n", aacs);

369 370
    aacs_close(aacs);

cRTrn13's avatar
cRTrn13 committed
371
    return NULL;
cRTrn13's avatar
cRTrn13 committed
372 373
}

cRTrn13's avatar
cRTrn13 committed
374
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
375
{
376 377 378
    X_FREE(aacs->uks);

    DEBUG(DBG_AACS, "AACS destroyed! (0x%08x)\n", aacs);
cRTrn13's avatar
cRTrn13 committed
379

cRTrn13's avatar
cRTrn13 committed
380 381 382
    X_FREE(aacs);
}

cRTrn13's avatar
cRTrn13 committed
383
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf, uint32_t len, uint64_t offset)
384
{
cRTrn13's avatar
cRTrn13 committed
385
    return _decrypt_unit(aacs, buf, len, offset, 0);
386
}
cRTrn13's avatar
cRTrn13 committed
387

cRTrn13's avatar
cRTrn13 committed
388
uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
389 390 391
{
    return aacs->vid;
}