97d703e4 by David LaPalomento

Merge pull request #540 from BrandonOCasey/browserify-p3

browserify-p3: decrypter
2 parents a8daa7f7 1011b09b
......@@ -47,13 +47,11 @@
<script src="/node_modules/video.js/dist/video.js"></script>
<script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script>
<script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="/src/videojs-contrib-hls.js"></script>
<script src="/src/xhr.js"></script>
<script src="/dist/videojs-contrib-hls.js"></script>
<script src="/src/playlist.js"></script>
<script src="/src/playlist-loader.js"></script>
<script src="/src/decrypter.js"></script>
<script src="/src/bin-utils.js"></script>
<script>
(function(window, videojs) {
......
......@@ -2,7 +2,7 @@ var browserify = require('browserify');
var fs = require('fs');
var glob = require('glob');
glob('test/{m3u8,stub}.test.js', function(err, files) {
glob('test/{decryper,m3u8,stub}.test.js', function(err, files) {
browserify(files)
.transform('babelify')
.bundle()
......
......@@ -3,7 +3,7 @@ var fs = require('fs');
var glob = require('glob');
var watchify = require('watchify');
glob('test/{m3u8,stub}.test.js', function(err, files) {
glob('test/{decrypter,m3u8,stub}.test.js', function(err, files) {
var b = browserify(files, {
cache: {},
packageCache: {},
......
......@@ -35,22 +35,23 @@
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the authors.
*/
(function(window, videojs, unpad) {
'use strict';
var AES, AsyncStream, Decrypter, decrypt, ntoh;
import Stream from './stream';
import {unpad} from 'pkcs7';
/**
* Convert network-order (big-endian) bytes into their little-endian
* representation.
*/
ntoh = function(word) {
const ntoh = function(word) {
return (word << 24) |
((word & 0xff00) << 8) |
((word & 0xff0000) >> 8) |
(word >>> 24);
};
let aesTables;
/**
* Schedule out an AES key for both encryption and decryption. This
* is a low-level class. Use a cipher mode to do bulk encryption.
......@@ -58,16 +59,33 @@ ntoh = function(word) {
* @constructor
* @param key {Array} The key as an array of 4, 6 or 8 words.
*/
AES = function (key) {
this._precompute();
var i, j, tmp,
encKey, decKey,
sbox = this._tables[0][4], decTable = this._tables[1],
keyLen = key.length, rcon = 1;
class AES {
constructor(key) {
/**
* The expanded S-box and inverse S-box tables. These will be computed
* on the client so that we don't have to send them down the wire.
*
* There are two tables, _tables[0] is for encryption and
* _tables[1] is for decryption.
*
* The first 4 sub-tables are the expanded S-box with MixColumns. The
* last (_tables[01][4]) is the S-box itself.
*
* @private
*/
this._tables = this._precompute();
let i;
let j;
let tmp;
let encKey;
let decKey;
let sbox = this._tables[0][4];
let decTable = this._tables[1];
let keyLen = key.length;
let rcon = 1;
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
throw new Error("Invalid aes key size");
throw new Error('Invalid aes key size');
}
encKey = key.slice(0);
......@@ -76,81 +94,83 @@ AES = function (key) {
// schedule encryption keys
for (i = keyLen; i < 4 * keyLen + 28; i++) {
tmp = encKey[i-1];
tmp = encKey[i - 1];
// apply sbox
if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) {
tmp = sbox[tmp>>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255];
if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) {
tmp = sbox[tmp >>> 24] << 24 ^
sbox[tmp >> 16 & 255] << 16 ^
sbox[tmp >> 8 & 255] << 8 ^
sbox[tmp & 255];
// shift rows and add rcon
if (i%keyLen === 0) {
tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24;
rcon = rcon<<1 ^ (rcon>>7)*283;
if (i % keyLen === 0) {
tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
rcon = rcon << 1 ^ (rcon >> 7) * 283;
}
}
encKey[i] = encKey[i-keyLen] ^ tmp;
encKey[i] = encKey[i - keyLen] ^ tmp;
}
// schedule decryption keys
for (j = 0; i; j++, i--) {
tmp = encKey[j&3 ? i : i - 4];
if (i<=4 || j<4) {
tmp = encKey[j & 3 ? i : i - 4];
if (i <= 4 || j < 4) {
decKey[j] = tmp;
} else {
decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^
decTable[1][sbox[tmp>>16 & 255]] ^
decTable[2][sbox[tmp>>8 & 255]] ^
decKey[j] = decTable[0][sbox[tmp >>> 24 ]] ^
decTable[1][sbox[tmp >> 16 & 255]] ^
decTable[2][sbox[tmp >> 8 & 255]] ^
decTable[3][sbox[tmp & 255]];
}
}
};
}
AES.prototype = {
/**
* The expanded S-box and inverse S-box tables. These will be computed
* on the client so that we don't have to send them down the wire.
*
* There are two tables, _tables[0] is for encryption and
* _tables[1] is for decryption.
*
* The first 4 sub-tables are the expanded S-box with MixColumns. The
* last (_tables[01][4]) is the S-box itself.
*
* @private
*/
_tables: [[[],[],[],[],[]],[[],[],[],[],[]]],
/**
* Expand the S-box tables.
*
* @private
*/
_precompute: function () {
var encTable = this._tables[0], decTable = this._tables[1],
sbox = encTable[4], sboxInv = decTable[4],
i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec;
_precompute() {
let tables = [[[], [], [], [], []], [[], [], [], [], []]];
let encTable = tables[0];
let decTable = tables[1];
let sbox = encTable[4];
let sboxInv = decTable[4];
let i;
let x;
let xInv;
let d = [];
let th = [];
let x2;
let x4;
let x8;
let s;
let tEnc;
let tDec;
// Compute double and third tables
for (i = 0; i < 256; i++) {
th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i;
th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
}
for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
// Compute sbox
s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4;
s = s>>8 ^ s&255 ^ 99;
s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
s = s >> 8 ^ s & 255 ^ 99;
sbox[x] = s;
sboxInv[s] = x;
// Compute MixColumns
x8 = d[x4 = d[x2 = d[x]]];
tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100;
tEnc = d[s]*0x101 ^ s*0x1010100;
tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
tEnc = d[s] * 0x101 ^ s * 0x1010100;
for (i = 0; i < 4; i++) {
encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8;
decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8;
encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
}
}
......@@ -159,7 +179,8 @@ AES.prototype = {
encTable[i] = encTable[i].slice(0);
decTable[i] = decTable[i].slice(0);
}
},
return tables;
}
/**
* Decrypt 16 bytes, specified as four 32-bit words.
......@@ -173,50 +194,71 @@ AES.prototype = {
* writing results
* @return {Array} The plaintext.
*/
decrypt:function (encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
var key = this._key[1],
decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
let key = this._key[1];
// state variables a,b,c,d are loaded with pre-whitened data
a = encrypted0 ^ key[0],
b = encrypted3 ^ key[1],
c = encrypted2 ^ key[2],
d = encrypted1 ^ key[3],
a2, b2, c2,
nInnerRounds = key.length / 4 - 2, // key.length === 2 ?
i,
kIndex = 4,
table = this._tables[1],
let a = encrypted0 ^ key[0];
let b = encrypted3 ^ key[1];
let c = encrypted2 ^ key[2];
let d = encrypted1 ^ key[3];
let a2;
let b2;
let c2;
// key.length === 2 ?
let nInnerRounds = key.length / 4 - 2;
let i;
let kIndex = 4;
let table = this._tables[1];
// load up the tables
table0 = table[0],
table1 = table[1],
table2 = table[2],
table3 = table[3],
sbox = table[4];
let table0 = table[0];
let table1 = table[1];
let table2 = table[2];
let table3 = table[3];
let sbox = table[4];
// Inner rounds. Cribbed from OpenSSL.
for (i = 0; i < nInnerRounds; i++) {
a2 = table0[a>>>24] ^ table1[b>>16 & 255] ^ table2[c>>8 & 255] ^ table3[d & 255] ^ key[kIndex];
b2 = table0[b>>>24] ^ table1[c>>16 & 255] ^ table2[d>>8 & 255] ^ table3[a & 255] ^ key[kIndex + 1];
c2 = table0[c>>>24] ^ table1[d>>16 & 255] ^ table2[a>>8 & 255] ^ table3[b & 255] ^ key[kIndex + 2];
d = table0[d>>>24] ^ table1[a>>16 & 255] ^ table2[b>>8 & 255] ^ table3[c & 255] ^ key[kIndex + 3];
a2 = table0[a >>> 24] ^
table1[b >> 16 & 255] ^
table2[c >> 8 & 255] ^
table3[d & 255] ^
key[kIndex];
b2 = table0[b >>> 24] ^
table1[c >> 16 & 255] ^
table2[d >> 8 & 255] ^
table3[a & 255] ^
key[kIndex + 1];
c2 = table0[c >>> 24] ^
table1[d >> 16 & 255] ^
table2[a >> 8 & 255] ^
table3[b & 255] ^
key[kIndex + 2];
d = table0[d >>> 24] ^
table1[a >> 16 & 255] ^
table2[b >> 8 & 255] ^
table3[c & 255] ^
key[kIndex + 3];
kIndex += 4;
a=a2; b=b2; c=c2;
a = a2; b = b2; c = c2;
}
// Last round.
for (i = 0; i < 4; i++) {
out[(3 & -i) + offset] =
sbox[a>>>24 ]<<24 ^
sbox[b>>16 & 255]<<16 ^
sbox[c>>8 & 255]<<8 ^
sbox[a >>> 24] << 24 ^
sbox[b >> 16 & 255] << 16 ^
sbox[c >> 8 & 255] << 8 ^
sbox[d & 255] ^
key[kIndex++];
a2=a; a=b; b=c; c=d; d=a2;
a2 = a; a = b; b = c; c = d; d = a2;
}
}
};
}
/* eslint-disable max-len */
/**
* Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
* @param encrypted {Uint8Array} the encrypted bytes
......@@ -229,24 +271,32 @@ AES.prototype = {
* @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
* @see https://tools.ietf.org/html/rfc2315
*/
decrypt = function(encrypted, key, initVector) {
var
/* eslint-enable max-len */
export const decrypt = function(encrypted, key, initVector) {
// word-level access to the encrypted bytes
encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2),
let encrypted32 = new Int32Array(encrypted.buffer,
encrypted.byteOffset,
encrypted.byteLength >> 2);
decipher = new AES(Array.prototype.slice.call(key)),
let decipher = new AES(Array.prototype.slice.call(key));
// byte and word-level access for the decrypted output
decrypted = new Uint8Array(encrypted.byteLength),
decrypted32 = new Int32Array(decrypted.buffer),
let decrypted = new Uint8Array(encrypted.byteLength);
let decrypted32 = new Int32Array(decrypted.buffer);
// temporary variables for working with the IV, encrypted, and
// decrypted data
init0, init1, init2, init3,
encrypted0, encrypted1, encrypted2, encrypted3,
let init0;
let init1;
let init2;
let init3;
let encrypted0;
let encrypted1;
let encrypted2;
let encrypted3;
// iteration variable
wordIx;
let wordIx;
// pull out the words of the IV to ensure we don't modify the
// passed-in reference and easier access
......@@ -290,13 +340,14 @@ decrypt = function(encrypted, key, initVector) {
return decrypted;
};
AsyncStream = function() {
export class AsyncStream extends Stream {
constructor() {
super(Stream);
this.jobs = [];
this.delay = 1;
this.timeout_ = null;
};
AsyncStream.prototype = new videojs.Hls.Stream();
AsyncStream.prototype.processJob_ = function() {
}
processJob_() {
this.jobs.shift()();
if (this.jobs.length) {
this.timeout_ = setTimeout(this.processJob_.bind(this),
......@@ -304,21 +355,23 @@ AsyncStream.prototype.processJob_ = function() {
} else {
this.timeout_ = null;
}
};
AsyncStream.prototype.push = function(job) {
}
push(job) {
this.jobs.push(job);
if (!this.timeout_) {
this.timeout_ = setTimeout(this.processJob_.bind(this),
this.delay);
}
};
}
}
export class Decrypter {
constructor(encrypted, key, initVector, done) {
let step = Decrypter.STEP;
let encrypted32 = new Int32Array(encrypted.buffer);
let decrypted = new Uint8Array(encrypted.byteLength);
let i = 0;
Decrypter = function(encrypted, key, initVector, done) {
var
step = Decrypter.STEP,
encrypted32 = new Int32Array(encrypted.buffer),
decrypted = new Uint8Array(encrypted.byteLength),
i = 0;
this.asyncStream_ = new AsyncStream();
// split up the encryption job and do the individual chunks asynchronously
......@@ -327,12 +380,10 @@ Decrypter = function(encrypted, key, initVector, done) {
initVector,
decrypted));
for (i = step; i < encrypted32.length; i += step) {
initVector = new Uint32Array([
ntoh(encrypted32[i - 4]),
initVector = new Uint32Array([ntoh(encrypted32[i - 4]),
ntoh(encrypted32[i - 3]),
ntoh(encrypted32[i - 2]),
ntoh(encrypted32[i - 1])
]);
ntoh(encrypted32[i - 1])]);
this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step),
key,
initVector,
......@@ -343,22 +394,22 @@ Decrypter = function(encrypted, key, initVector, done) {
// remove pkcs#7 padding from the decrypted bytes
done(null, unpad(decrypted));
});
};
Decrypter.prototype = new videojs.Hls.Stream();
Decrypter.prototype.decryptChunk_ = function(encrypted, key, initVector, decrypted) {
}
decryptChunk_(encrypted, key, initVector, decrypted) {
return function() {
var bytes = decrypt(encrypted,
key,
initVector);
let bytes = decrypt(encrypted, key, initVector);
decrypted.set(bytes, encrypted.byteOffset);
};
};
// the maximum number of bytes to process at one time
Decrypter.STEP = 4 * 8000;
}
}
// exports
videojs.Hls.decrypt = decrypt;
videojs.Hls.Decrypter = Decrypter;
videojs.Hls.AsyncStream = AsyncStream;
// the maximum number of bytes to process at one time
// 4 * 8000;
Decrypter.STEP = 32000;
})(window, window.videojs, window.pkcs7.unpad);
export default {
decrypt,
Decrypter,
AsyncStream
};
......
import m3u8 from './m3u8';
import Stream from './stream';
import videojs from 'video.js';
import {Decrypter, decrypt, AsyncStream} from './decrypter';
if(typeof window.videojs.Hls === 'undefined') {
videojs.Hls = {};
}
videojs.Hls.Stream = Stream;
videojs.m3u8 = m3u8;
videojs.Hls.decrypt = decrypt;
videojs.Hls.Decrypter = Decrypter;
videojs.Hls.AsyncStream = AsyncStream;
......
(function(window, videojs, unpad, undefined) {
'use strict';
/*
======== A Handy Little QUnit Reference ========
http://api.qunitjs.com/
Test methods:
module(name, {[setup][ ,teardown]})
test(name, callback)
expect(numberOfAssertions)
stop(increment)
start(decrement)
Test assertions:
ok(value, [message])
equal(actual, expected, [message])
notEqual(actual, expected, [message])
deepEqual(actual, expected, [message])
notDeepEqual(actual, expected, [message])
strictEqual(actual, expected, [message])
notStrictEqual(actual, expected, [message])
throws(block, [expected], [message])
*/
// see docs/hlse.md for instructions on how test data was generated
import QUnit from 'qunit';
import {unpad} from 'pkcs7';
import sinon from 'sinon';
import {decrypt, Decrypter, AsyncStream} from '../src/decrypter';
var stringFromBytes = function(bytes) {
var result = '', i;
// see docs/hlse.md for instructions on how test data was generated
const stringFromBytes = function(bytes) {
let result = '';
for (i = 0; i < bytes.length; i++) {
for (let i = 0; i < bytes.length; i++) {
result += String.fromCharCode(bytes[i]);
}
return result;
};
QUnit.module('Decryption');
test('decrypts a single AES-128 with PKCS7 block', function() {
var
key = new Uint32Array([0, 0, 0, 0]),
initVector = key,
QUnit.test('decrypts a single AES-128 with PKCS7 block', function() {
let key = new Uint32Array([0, 0, 0, 0]);
let initVector = key;
// the string "howdy folks" encrypted
encrypted = new Uint8Array([
let encrypted = new Uint8Array([
0xce, 0x90, 0x97, 0xd0,
0x08, 0x46, 0x4d, 0x18,
0x4f, 0xae, 0x01, 0x1c,
0x82, 0xa8, 0xf0, 0x67]);
0x82, 0xa8, 0xf0, 0x67
]);
deepEqual('howdy folks',
stringFromBytes(unpad(videojs.Hls.decrypt(encrypted, key, initVector))),
'decrypted with a byte array key');
QUnit.deepEqual('howdy folks',
stringFromBytes(unpad(decrypt(encrypted, key, initVector))),
'decrypted with a byte array key'
);
});
test('decrypts multiple AES-128 blocks with CBC', function() {
var
key = new Uint32Array([0, 0, 0, 0]),
initVector = key,
QUnit.test('decrypts multiple AES-128 blocks with CBC', function() {
let key = new Uint32Array([0, 0, 0, 0]);
let initVector = key;
// the string "0123456789abcdef01234" encrypted
encrypted = new Uint8Array([
let encrypted = new Uint8Array([
0x14, 0xf5, 0xfe, 0x74,
0x69, 0x66, 0xf2, 0x92,
0x65, 0x1c, 0x22, 0x88,
0xbb, 0xff, 0x46, 0x09,
0x0b, 0xde, 0x5e, 0x71,
0x77, 0x87, 0xeb, 0x84,
0xa9, 0x54, 0xc2, 0x45,
0xe9, 0x4e, 0x29, 0xb3
]);
QUnit.deepEqual('0123456789abcdef01234',
stringFromBytes(unpad(decrypt(encrypted, key, initVector))),
'decrypted multiple blocks');
});
QUnit.test(
'verify that the deepcopy works by doing two decrypts in the same test',
function() {
let key = new Uint32Array([0, 0, 0, 0]);
let initVector = key;
// the string "howdy folks" encrypted
let pkcs7Block = new Uint8Array([
0xce, 0x90, 0x97, 0xd0,
0x08, 0x46, 0x4d, 0x18,
0x4f, 0xae, 0x01, 0x1c,
0x82, 0xa8, 0xf0, 0x67
]);
QUnit.deepEqual('howdy folks',
stringFromBytes(unpad(decrypt(pkcs7Block, key, initVector))),
'decrypted with a byte array key'
);
// the string "0123456789abcdef01234" encrypted
let cbcBlocks = new Uint8Array([
0x14, 0xf5, 0xfe, 0x74,
0x69, 0x66, 0xf2, 0x92,
0x65, 0x1c, 0x22, 0x88,
......@@ -67,38 +84,40 @@ test('decrypts multiple AES-128 blocks with CBC', function() {
0xe9, 0x4e, 0x29, 0xb3
]);
deepEqual('0123456789abcdef01234',
stringFromBytes(unpad(videojs.Hls.decrypt(encrypted, key, initVector))),
QUnit.deepEqual('0123456789abcdef01234',
stringFromBytes(unpad(decrypt(cbcBlocks, key, initVector))),
'decrypted multiple blocks');
});
var clock;
QUnit.module('Incremental Processing', {
setup: function() {
clock = sinon.useFakeTimers();
beforeEach() {
this.clock = sinon.useFakeTimers();
},
teardown: function() {
clock.restore();
afterEach() {
this.clock.restore();
}
});
test('executes a callback after a timeout', function() {
var asyncStream = new videojs.Hls.AsyncStream(),
calls = '';
QUnit.test('executes a callback after a timeout', function() {
let asyncStream = new AsyncStream();
let calls = '';
asyncStream.push(function() {
calls += 'a';
});
clock.tick(asyncStream.delay);
equal(calls, 'a', 'invoked the callback once');
clock.tick(asyncStream.delay);
equal(calls, 'a', 'only invoked the callback once');
this.clock.tick(asyncStream.delay);
QUnit.equal(calls, 'a', 'invoked the callback once');
this.clock.tick(asyncStream.delay);
QUnit.equal(calls, 'a', 'only invoked the callback once');
});
test('executes callback in series', function() {
var asyncStream = new videojs.Hls.AsyncStream(),
calls = '';
QUnit.test('executes callback in series', function() {
let asyncStream = new AsyncStream();
let calls = '';
asyncStream.push(function() {
calls += 'a';
});
......@@ -106,62 +125,62 @@ test('executes callback in series', function() {
calls += 'b';
});
clock.tick(asyncStream.delay);
equal(calls, 'a', 'invoked the first callback');
clock.tick(asyncStream.delay);
equal(calls, 'ab', 'invoked the second');
this.clock.tick(asyncStream.delay);
QUnit.equal(calls, 'a', 'invoked the first callback');
this.clock.tick(asyncStream.delay);
QUnit.equal(calls, 'ab', 'invoked the second');
});
var decrypter;
QUnit.module('Incremental Decryption', {
setup: function() {
clock = sinon.useFakeTimers();
beforeEach() {
this.clock = sinon.useFakeTimers();
},
teardown: function() {
clock.restore();
afterEach() {
this.clock.restore();
}
});
test('asynchronously decrypts a 4-word block', function() {
var
key = new Uint32Array([0, 0, 0, 0]),
initVector = key,
QUnit.test('asynchronously decrypts a 4-word block', function() {
let key = new Uint32Array([0, 0, 0, 0]);
let initVector = key;
// the string "howdy folks" encrypted
encrypted = new Uint8Array([
0xce, 0x90, 0x97, 0xd0,
let encrypted = new Uint8Array([0xce, 0x90, 0x97, 0xd0,
0x08, 0x46, 0x4d, 0x18,
0x4f, 0xae, 0x01, 0x1c,
0x82, 0xa8, 0xf0, 0x67]),
decrypted;
decrypter = new videojs.Hls.Decrypter(encrypted, key, initVector, function(error, result) {
0x82, 0xa8, 0xf0, 0x67]);
let decrypted;
let decrypter = new Decrypter(encrypted,
key,
initVector,
function(error, result) {
if (error) {
throw new Error(error);
}
decrypted = result;
});
ok(!decrypted, 'asynchronously decrypts');
clock.tick(decrypter.asyncStream_.delay * 2);
QUnit.ok(!decrypted, 'asynchronously decrypts');
this.clock.tick(decrypter.asyncStream_.delay * 2);
ok(decrypted, 'completed decryption');
deepEqual('howdy folks',
QUnit.ok(decrypted, 'completed decryption');
QUnit.deepEqual('howdy folks',
stringFromBytes(decrypted),
'decrypts and unpads the result');
});
test('breaks up input greater than the step value', function() {
var encrypted = new Int32Array(videojs.Hls.Decrypter.STEP + 4),
done = false,
decrypter = new videojs.Hls.Decrypter(encrypted,
QUnit.test('breaks up input greater than the step value', function() {
let encrypted = new Int32Array(Decrypter.STEP + 4);
let done = false;
let decrypter = new Decrypter(encrypted,
new Uint32Array(4),
new Uint32Array(4),
function() {
done = true;
});
clock.tick(decrypter.asyncStream_.delay * 2);
ok(!done, 'not finished after two ticks');
clock.tick(decrypter.asyncStream_.delay);
ok(done, 'finished after the last chunk is decrypted');
});
this.clock.tick(decrypter.asyncStream_.delay * 2);
QUnit.ok(!done, 'not finished after two ticks');
})(window, window.videojs, window.pkcs7.unpad);
this.clock.tick(decrypter.asyncStream_.delay);
QUnit.ok(done, 'finished after the last chunk is decrypted');
});
......
......@@ -12,7 +12,6 @@
<!-- NOTE in order for test to pass we require sinon 1.10.2 exactly -->
<script src="/node_modules/sinon/pkg/sinon.js"></script>
<script src="/node_modules/qunitjs/qunit/qunit.js"></script>
<script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="/node_modules/video.js/dist/video.js"></script>
<script src="/node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script>
......@@ -21,14 +20,12 @@
<script src="/dist/videojs-contrib-hls.js"></script>
<script src="/src/playlist.js"></script>
<script src="/src/playlist-loader.js"></script>
<script src="/src/decrypter.js"></script>
<script src="/src/bin-utils.js"></script>
<script src="/test/videojs-contrib-hls.test.js"></script>
<script src="/dist-test/videojs-contrib-hls.js"></script>
<script src="/test/playlist.test.js"></script>
<script src="/test/playlist-loader.test.js"></script>
<script src="/test/decrypter.test.js"></script>
</body>
</html>
......
......@@ -12,7 +12,6 @@ var DEFAULTS = {
'node_modules/video.js/dist/video-js.css',
// REMOVE ME WHEN BROWSERIFIED
'node_modules/pkcs7/dist/pkcs7.unpad.js',
'node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js',
// these two stub old functionality
......@@ -22,7 +21,6 @@ var DEFAULTS = {
'src/playlist.js',
'src/playlist-loader.js',
'src/decrypter.js',
'src/bin-utils.js',
'test/stub.test.js',
......@@ -47,7 +45,7 @@ var DEFAULTS = {
],
preprocessors: {
'test/{stub,m3u8}.test.js': ['browserify']
'test/{decrypter,stub,m3u8}.test.js': ['browserify']
},
reporters: ['dots'],
......