我想知道如何使用AES和自定义密钥使用WebCrypto API加密和解密视频。我只找到了这段代码并且只指示了如何加密视频而不是如何解密它,也使用随机密钥。提前谢谢。
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);
}
答案 0 :(得分:1)
您可以在此处找到有关如何使用AES-GCM生成密钥,导入密钥,加密和解密的完整示例: https://github.com/diafygi/webcrypto-examples/blob/master/README.md#aes-gcm
您应该使用GCM,因为它是经过身份验证的加密模式。 WebCrypto没有流接口,因此您必须处理块,否则它非常直接。
您可能希望使用ECDH来交换AES密钥。同一页也有相关的例子。
答案 1 :(得分:1)
这是一个使用aes-256-cbc解密和播放HLS视频的演示:
https://kaizhu256.github.io/node-demo-hls-encrypted/index.html
通过在hls.js(https://github.com/video-dev/hls.js/blob/v0.8.9/dist/hls.js)中破解ajax调用来解密xhr.response,然后再将其传递给视频播放来实现:
--- 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