diff mbox series

[FFmpeg-devel,v2] Add support for playing Audible AAXC (.aaxc) files

Message ID 387521585805732@sas1-2bf44b70450e.qloud-c.yandex.net
State Superseded
Headers show
Series [FFmpeg-devel,v2] Add support for playing Audible AAXC (.aaxc) files | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Vesselin Bontchev April 2, 2020, 5:39 a.m. UTC

Comments

Carl Eugen Hoyos April 2, 2020, 8:49 p.m. UTC | #1
Am Do., 2. Apr. 2020 um 07:39 Uhr schrieb Vesselin Bontchev
<vesselin.bontchev@yandex.com>:

> +    c->aes_decrypt = av_aes_alloc();

Don't you have to free this in the fail path?
An alternative is to allocate this after the length check...
If the alloc function returns NULL, you should return
ENOMEM.

Carl Eugen
diff mbox series

Patch

From 854a6197ecae1ddf226876952d0e7935830db2cf Mon Sep 17 00:00:00 2001
From: Vesselin Bontchev <vesselin.bontchev@yandex.com>
Date: Sat, 1 Jan 2000 09:00:00 +0000
Subject: [PATCH v2] Add support for playing Audible AAXC (.aaxc) files

The AAXC container format is the same as the (already supported) Audible
AAX format but it uses a different encryption scheme.

Note: audible_key and audible_iv values are variable (per file) and are
externally fed.

It is possible to extend https://github.com/mkb79/Audible to derive the
audible_key and audible_key values.

Relevant code:

def decrypt_voucher(deviceSerialNumber, customerId, deviceType, asin, voucher):
    buf = (deviceType + deviceSerialNumber + customerId + asin).encode("ascii")
    digest = hashlib.sha256(buf).digest()
    key = digest[0:16]
    iv = digest[16:]

    # decrypt "voucher" using AES in CBC mode with no padding
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(voucher).rstrip(b"\x00")
    return json.loads(plaintext)

The decrypted "voucher" has the required audible_key and audible_iv
values.

Signed-off-by: Vesselin Bontchev <vesselin.bontchev@yandex.com>
---
 libavformat/isom.h |  4 ++++
 libavformat/mov.c  | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 4943b80ccf..6f7de09155 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -285,6 +285,10 @@  typedef struct MOVContext {
     int activation_bytes_size;
     void *audible_fixed_key;
     int audible_fixed_key_size;
+    void *audible_key;
+    int audible_key_size;
+    void *audible_iv;
+    int audible_iv_size;
     struct AVAES *aes_decrypt;
     uint8_t *decryption_key;
     int decryption_key_len;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index f01502a5f8..075afe589d 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1085,6 +1085,40 @@  fail:
     return ret;
 }
 
+static int mov_aaxc_crypto(MOVContext *c)
+{
+    int ret = 0;
+
+    c->aes_decrypt = av_aes_alloc();
+    if (!c->aes_decrypt) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    /* verify audible_key */
+    if (c->audible_key_size != 16) {
+        av_log(c->fc, AV_LOG_FATAL, "[aaxc] audible_key value needs to be 16 bytes!\n");
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+
+    /* verify audible_iv */
+    if (c->audible_iv_size != 16) {
+        av_log(c->fc, AV_LOG_FATAL, "[aaxc] audible_iv value needs to be 16 bytes!\n");
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+
+    memcpy(c->file_key, c->audible_key, 16);
+    memcpy(c->file_iv, c->audible_iv, 16);
+
+    c->aax_mode = 1;
+
+fail:
+
+    return ret;
+}
+
 // Audible AAX (and AAX+) bytestream decryption
 static int aax_filter(uint8_t *input, int size, MOVContext *c)
 {
@@ -1133,6 +1167,11 @@  static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     av_dict_set(&c->fc->metadata, "compatible_brands",
                 comp_brands_str, AV_DICT_DONT_STRDUP_VAL);
 
+    // Logic for handling Audible's .aaxc files
+    if (!strcmp(type, "aaxc")) {
+        mov_aaxc_crypto(c);
+    }
+
     return 0;
 }
 
@@ -8069,6 +8108,10 @@  static const AVOption mov_options[] = {
         AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = FLAGS },
     { "activation_bytes", "Secret bytes for Audible AAX files", OFFSET(activation_bytes),
         AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
+    { "audible_key", "AES-128 Key for Audible AAXC files", OFFSET(audible_key),
+        AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
+    { "audible_iv", "AES-128 IV for Audible AAXC files", OFFSET(audible_iv),
+        AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_DECODING_PARAM },
     { "audible_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files!
         "Fixed key used for handling Audible AAX files", OFFSET(audible_fixed_key),
         AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd20a51d67"},
-- 
2.26.0