diff mbox series

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

Message ID 1844221604326075@mail.yandex.com
State Accepted
Commit 03fb314acfa4f5a4af84a6fc82a425477fd352eb
Headers show
Series [FFmpeg-devel,v4] Add support for playing Audible AAXC (.aaxc) files | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Vesselin Bontchev Nov. 2, 2020, 2:12 p.m. UTC
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")  # improve this!
    return json.loads(plaintext)

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

Update (Nov-2020): This patch has now been tested by multiple folks -
details at the following URL:

https://github.com/mkb79/Audible/issues/3

Signed-off-by: Vesselin Bontchev <vesselin.bontchev@yandex.com>

...

Thanks Carl for all the reviews. Hopefully we can merge this patch soon :)

Vesselin
Subject: [PATCH] [v4] 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")  # improve this!
    return json.loads(plaintext)

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

Update (Nov-2020): This patch has now been tested by multiple folks -
details at the following URL:

https://github.com/mkb79/Audible/issues/3

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

Comments

Paul B Mahol Nov. 5, 2020, 4:15 p.m. UTC | #1
Next time apply without [PATCH v4] in main log

On Mon, Nov 2, 2020 at 3:19 PM Vesselin Bontchev <
vesselin.bontchev@yandex.com> wrote:

> 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")  # improve this!
>     return json.loads(plaintext)
>
> The decrypted "voucher" has the required audible_key and audible_iv
> values.
>
> Update (Nov-2020): This patch has now been tested by multiple folks -
> details at the following URL:
>
> https://github.com/mkb79/Audible/issues/3
>
> Signed-off-by: Vesselin Bontchev <vesselin.bontchev@yandex.com>
>
> ...
>
> Thanks Carl for all the reviews. Hopefully we can merge this patch soon :)
>
> Vesselin
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 78495fd336..5a6d504090 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -286,6 +286,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 dd0db6bca7..2b90e31170 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1075,6 +1075,30 @@  fail:
     return ret;
 }
 
+static int mov_aaxc_crypto(MOVContext *c)
+{
+    if (c->audible_key_size != 16) {
+        av_log(c->fc, AV_LOG_FATAL, "[aaxc] audible_key value needs to be 16 bytes!\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (c->audible_iv_size != 16) {
+        av_log(c->fc, AV_LOG_FATAL, "[aaxc] audible_iv value needs to be 16 bytes!\n");
+        return AVERROR(EINVAL);
+    }
+
+    c->aes_decrypt = av_aes_alloc();
+    if (!c->aes_decrypt) {
+        return AVERROR(ENOMEM);
+    }
+
+    memcpy(c->file_key, c->audible_key, 16);
+    memcpy(c->file_iv, c->audible_iv, 16);
+    c->aax_mode = 1;
+
+    return 0;
+}
+
 // Audible AAX (and AAX+) bytestream decryption
 static int aax_filter(uint8_t *input, int size, MOVContext *c)
 {
@@ -1123,6 +1147,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;
 }
 
@@ -8170,6 +8199,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"},