Зашифруйте и расшифруйте видео с помощью API WebCrypto, используя AES и пользовательский ключ - PullRequest
0 голосов
/ 24 мая 2018

Мне было интересно, как зашифровать и расшифровать видео с помощью API WebCrypto, используя AES и пользовательский ключ.Я только нашел этот код и только указывает, как зашифровать видео, но не как расшифровать его, также использует случайный ключ.Заранее спасибо.

  function processFile(evt) {
    var file = evt.target.files[0],
        reader = new FileReader();

    reader.onload = function(e) {
        var data = e.target.result,
            iv = crypto.getRandomValues(new Uint8Array(16));

        crypto.subtle.generateKey({ 'name': 'AES-CBC', 'length': 256 }, false, ['encrypt', 'decrypt'])
            .then(key => crypto.subtle.encrypt({ 'name': 'AES-CBC', iv }, key, data) )
            .then(encrypted => {
                console.log(encrypted);
                alert('The encrypted data is ' + encrypted.byteLength + ' bytes long'); // encrypted is an ArrayBuffer
            })
            .catch(console.error);
    }

    reader.readAsArrayBuffer(file);   
}

Ответы [ 2 ]

0 голосов
/ 04 августа 2018

вот демонстрационная программа, которая расшифровывает и воспроизводит видео HLS с помощью aes-256-cbc:

https://kaizhu256.github.io/node-demo-hls-encrypted/index.html

, что было достигнуто путем взлома вызова ajax в hls.js (https://github.com/video-dev/hls.js/blob/v0.8.9/dist/hls.js) для расшифровки ответа xhr. перед передачей его на воспроизведение видео:

--- assets.hls.v0.8.9.js    2018-08-04 03:59:42.000000000 +0700
+++ assets.hls.v0.8.9.crypto.js 2018-08-04 03:59:42.000000000 +0700
@@ -1,3 +1,97 @@
+var local;
+(function () {
+    (function () {
+        local = local || {};
+        local.base64ToBuffer = function (b64, mode) {
+        /*
+         * this function will convert b64 to Uint8Array
+         * https://gist.github.com/wang-bin/7332335
+         */
+            /*globals Uint8Array*/
+            var bff, byte, chr, ii, jj, map64, mod4;
+            b64 = b64 || '';
+            bff = new Uint8Array(b64.length); // 3/4
+            byte = 0;
+            jj = 0;
+            map64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+            mod4 = 0;
+            for (ii = 0; ii < b64.length; ii += 1) {
+                chr = map64.indexOf(b64[ii]);
+                if (chr >= 0) {
+                    mod4 %= 4;
+                    if (mod4 === 0) {
+                        byte = chr;
+                    } else {
+                        byte = byte * 64 + chr;
+                        bff[jj] = 255 & (byte >> ((-2 * (mod4 + 1)) & 6));
+                        jj += 1;
+                    }
+                    mod4 += 1;
+                }
+            }
+            // optimization - create resized-view of bff
+            bff = bff.subarray(0, jj);
+            // mode !== 'string'
+            if (mode !== 'string') {
+                return bff;
+            }
+            // mode === 'string' - browser js-env
+            if (typeof window === 'object' && window && typeof window.TextDecoder === 'function') {
+                return new window.TextDecoder().decode(bff);
+            }
+            // mode === 'string' - node js-env
+            Object.setPrototypeOf(bff, Buffer.prototype);
+            return String(bff);
+        };
+        local.cryptoAes256CbcByteDecrypt = function (key, data, onError, mode) {
+        /*
+         * this function will aes-256-cbc decrypt with the hex-key, Uint8Array data
+         * example usage:
+            key = '0000000000000000000000000000000000000000000000000000000000000000';
+            local.cryptoAes256CbcByteEncrypt(key, new Uint8Array([1,2,3]), function (error, data) {
+                console.assert(!error, error);
+                local.cryptoAes256CbcByteDecrypt(key, data, console.log);
+            });
+         */
+            /*globals Uint8Array*/
+            var cipher, crypto, ii, iv, tmp;
+            // init key
+            tmp = key;
+            key = new Uint8Array(32);
+            for (ii = 0; ii < key.length; ii += 2) {
+                key[ii] = parseInt(tmp.slice(2 * ii, 2 * ii + 2), 16);
+            }
+            // base64
+            if (mode === 'base64') {
+                data = local.base64ToBuffer(data);
+            }
+            if (!(data instanceof Uint8Array)) {
+                data = new Uint8Array(data);
+            }
+            // init iv
+            iv = data.subarray(0, 16);
+            // optimization - create resized-view of data
+            data = data.subarray(16);
+            crypto = typeof window === 'object' && window.crypto;
+            /* istanbul ignore next */
+            if (!(crypto && crypto.subtle && typeof crypto.subtle.importKey === 'function')) {
+                setTimeout(function () {
+                    crypto = require('crypto');
+                    cipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
+                    onError(null, Buffer.concat([cipher.update(data), cipher.final()]));
+                });
+                return;
+            }
+            crypto.subtle.importKey('raw', key, {
+                name: 'AES-CBC'
+            }, false, ['decrypt']).then(function (key) {
+                crypto.subtle.decrypt({ iv: iv, name: 'AES-CBC' }, key, data).then(function (data) {
+                    onError(null, new Uint8Array(data));
+                }).catch(onError);
+            }).catch(onError);
+        };
+    }());
+}());
 (function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
@@ -10919,6 +11013,22 @@
           }
           stats.loaded = stats.total = len;
           var response = { url: xhr.responseURL, data: data };
+          if (data && window.modeMediaEncrypted && window.mediaEncryptedKey) {
+              var self = this;
+              local.cryptoAes256CbcByteDecrypt(
+                window.mediaEncryptedKey,
+                data,
+                function (error, data) {
+                  response.data = typeof xhr.response === 'string'
+                    ? new TextDecoder().decode(data)
+                    : data;
+                  stats.loaded = stats.total = data.byteLength;
+                  self.callbacks.onSuccess(response, stats, context, xhr);
+                },
+                typeof xhr.response === 'string' && 'base64'
+              );
+              return;
+          }
           this.callbacks.onSuccess(response, stats, context, xhr);
         } else {
           // if max nb of retries reached or if http status between 400 and 499 (such error cannot be recovered, retrying is useless), return error
0 голосов
/ 26 мая 2018

Вы найдете полные примеры того, как генерировать ключи, импортировать ключи, шифровать и дешифровать с использованием AES-GCM здесь: https://github.com/diafygi/webcrypto-examples/blob/master/README.md#aes-gcm

Вы должны использовать GCM, так как это аутентифицированный режим шифрования.Для WebCrypto нет потокового интерфейса, поэтому вам придется обрабатывать блоками, иначе это будет очень просто.

Скорее всего, вы захотите использовать ECDH для обмена ключом AES.На той же странице есть примеры и для этого.

...