libaacs | branch: master | npzacs <npz...@gmail.com> | Mon Jan  5 17:22:06 2015 
+0200| [d8ca79150784d9b1896557dc170646a38917cab8] | committer: npzacs

Do in-place decryption without memcpy()

> http://git.videolan.org/gitweb.cgi/libaacs.git/?a=commit;h=d8ca79150784d9b1896557dc170646a38917cab8
---

 src/libaacs/aacs.c |   59 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 19 deletions(-)

diff --git a/src/libaacs/aacs.c b/src/libaacs/aacs.c
index 02eb409..18f2537 100644
--- a/src/libaacs/aacs.c
+++ b/src/libaacs/aacs.c
@@ -70,6 +70,7 @@ struct aacs {
 
     /* CPS unit of currently selected title */
     uint16_t  current_cps_unit;
+    uint8_t   cps_unit_selected;
 
     /* title -> CPS unit mappings */
     uint32_t  num_titles;
@@ -85,10 +86,10 @@ struct aacs {
     uint8_t   device_binding_id[16];
 };
 
-static const uint8_t empty_key[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
-                                   "\x00\x00\x00\x00\x00\x00\x00\x00";
-static const uint8_t aacs_iv[]   = "\x0b\xa0\xf8\xdd\xfe\xa6\x1f\xb3"
-                                   "\xd8\xdf\x9f\x56\x6a\x05\x0f\x78";
+static const uint8_t empty_key[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00 };
+static const uint8_t aacs_iv[16]   = { 0x0b, 0xa0, 0xf8, 0xdd, 0xfe, 0xa6, 
0x1f, 0xb3,
+                                       0xd8, 0xdf, 0x9f, 0x56, 0x6a, 0x05, 
0x0f, 0x78 };
 
 static int _validate_pk(const uint8_t *pk,
                         const uint8_t *cvalue, const uint8_t *uv, const 
uint8_t *vd,
@@ -899,35 +900,39 @@ static int _verify_ts(uint8_t *buf)
 
 static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, 
uint32_t curr_uk)
 {
+    /* inbuf == NULL means in-place decryption */
+
     gcry_cipher_hd_t gcry_h;
     int a;
     uint8_t key[16];
 
+    if (AACS_UNLIKELY(in_buf != NULL)) {
+        memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */
+    }
+
     gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
     gcry_cipher_setkey(gcry_h, aacs->uks + curr_uk * 16, 16);
-    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
+    gcry_cipher_encrypt(gcry_h, key, 16, out_buf, 16); /* here out_buf is 
plain data fron in_buf */
     gcry_cipher_close(gcry_h);
 
     for (a = 0; a < 16; a++) {
-        key[a] ^= in_buf[a];
+        key[a] ^= out_buf[a]; /* here out_buf is plain data fron in_buf */
     }
 
-    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */
-
     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, aacs_iv, 16);
-    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 
16, ALIGNED_UNIT_LEN - 16);
+    if (AACS_UNLIKELY(in_buf != NULL)) {
+        gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, 
in_buf + 16, ALIGNED_UNIT_LEN - 16);
+    } else {
+        gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, NULL, 
0);
+    }
     gcry_cipher_close(gcry_h);
 
     if (_verify_ts(out_buf)) {
         return 1;
     }
 
-    if (curr_uk < aacs->num_uks - 1) {
-        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
-    }
-
     return 0;
 }
 
@@ -1062,28 +1067,42 @@ void aacs_close(AACS *aacs)
 
 int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
 {
-    uint8_t out_buf[ALIGNED_UNIT_LEN];
-    int i;
+    unsigned int i;
 
     if (!(buf[0] & 0xc0)) {
         // TP_extra_header Copy_permission_indicator == 0, unit is not 
encrypted
         return 1;
     }
 
+    /* handle bus encryption first */
     if (aacs->bee && aacs->bec) {
         for (i = 0; i < ALIGNED_UNIT_LEN; i += SECTOR_LEN) {
             _decrypt_bus(aacs, buf + i);
         }
     }
 
-    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
-        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
+    /* decrypt in-place if current unit key is known */
+    if (AACS_LIKELY(aacs->cps_unit_selected) || AACS_LIKELY(aacs->num_uks == 
1)) {
+        if (AACS_LIKELY(_decrypt_unit(aacs, buf, NULL, 
aacs->current_cps_unit))) {
+            return 1;
+        }
 
-        return 1;
+    } else {
+
+        /* unit key is unknown (playback without menus), try each key until 
right key is found */
+        uint8_t out_buf[ALIGNED_UNIT_LEN];
+        for (i = 0; i < aacs->num_uks; i++) {
+            if (_decrypt_unit(aacs, out_buf, buf, i)) {
+                DEBUG(DBG_AACS, "autodetected current CPS unit (%d)\n", i);
+                aacs->current_cps_unit  = i;
+                aacs->cps_unit_selected = 1;
+                memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
+                return 1;
+            }
+        }
     }
 
     DEBUG(DBG_AACS, "Failed decrypting unit [6144 bytes]\n");
-
     return 0;
 }
 
@@ -1264,12 +1283,14 @@ void aacs_select_title(AACS *aacs, uint32_t title)
     if (title == 0xffff) {
         /* first play */
         aacs->current_cps_unit = aacs->cps_units[0];
+        aacs->cps_unit_selected = 0;
         DEBUG(DBG_AACS, "aacs_set_title(first_play): CPS unit %d\n", 
aacs->current_cps_unit);
         return;
     }
 
     if (title <= aacs->num_titles) {
         aacs->current_cps_unit = aacs->cps_units[title + 1];
+        aacs->cps_unit_selected = 1;
         DEBUG(DBG_AACS, "aacs_set_title(%d): CPS unit %d\n", title, 
aacs->current_cps_unit);
         return;
     }

_______________________________________________
libaacs-devel mailing list
libaacs-devel@videolan.org
https://mailman.videolan.org/listinfo/libaacs-devel

Reply via email to