Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
brainfood
/
videojs-contrib-hls
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
97d703e4
authored
2016-02-04 10:23:34 -0500
by
David LaPalomento
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge pull request #540 from BrandonOCasey/browserify-p3
browserify-p3: decrypter
2 parents
a8daa7f7
1011b09b
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
288 additions
and
222 deletions
index.html
scripts/build-test.js
scripts/watch-test.js
src/decrypter.js
src/stub.js
test/decrypter.test.js
test/index.html
test/karma/common.js
index.html
View file @
97d703e
...
...
@@ -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
)
{
...
...
scripts/build-test.js
View file @
97d703e
...
...
@@ -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
()
...
...
scripts/watch-test.js
View file @
97d703e
...
...
@@ -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
:
{},
...
...
src/decrypter.js
View file @
97d703e
...
...
@@ -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
};
...
...
src/stub.js
View file @
97d703e
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
;
...
...
test/decrypter.test.js
View file @
97d703e
(
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'
);
});
...
...
test/index.html
View file @
97d703e
...
...
@@ -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>
...
...
test/karma/common.js
View file @
97d703e
...
...
@@ -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'
],
...
...
Please
register
or
sign in
to post a comment