Browse Source

Upgrade aes-decrypter to use webcrypto for HLSe decryption where available. (#777)

* Use 'decrypt' with callback instead of Decrypter directly

Cast request.response ArrayBuffer to Uint8Array for explicit passing to
decrypt

* Fix text with Uint8Array key result

* fix test for decrypting (#1)

* s/var/let/

* Upgrade aes-decrypter to ^2.0.0
pull/6/head
Deirdre Connolly 9 years ago
committed by forbesjo
parent
commit
b9692e29de
  1. 2
      package.json
  2. 27
      src/segment-loader.js
  3. 21
      test/segment-loader.test.js

2
package.json

@ -89,7 +89,7 @@
"test/"
],
"dependencies": {
"aes-decrypter": "^1.0.3",
"aes-decrypter": "^2.0.0",
"global": "^4.3.0",
"m3u8-parser": "^1.0.2",
"mux.js": "^3.0.0",

27
src/segment-loader.js

@ -5,8 +5,8 @@ import Ranges from './ranges';
import {getMediaIndexForTime_ as getMediaIndexForTime, duration} from './playlist';
import videojs from 'video.js';
import SourceUpdater from './source-updater';
import {Decrypter} from 'aes-decrypter';
import mp4probe from 'mux.js/lib/mp4/probe';
import {decrypt} from 'aes-decrypter';
import Config from './config';
import window from 'global/window';
@ -706,7 +706,6 @@ export default class SegmentLoader extends videojs.EventTarget {
let segmentInfo;
let segment;
let keyXhrRequest;
let view;
// timeout of previously aborted request
if (!this.xhr_ ||
@ -789,13 +788,7 @@ export default class SegmentLoader extends videojs.EventTarget {
return this.trigger('error');
}
view = new DataView(request.response);
segment.key.bytes = new Uint32Array([
view.getUint32(0),
view.getUint32(4),
view.getUint32(8),
view.getUint32(12)
]);
segment.key.bytes = new Uint8Array(request.response);
// if the media sequence is greater than 2^32, the IV will be incorrect
// assuming 10s segments, that would be about 1300 years
@ -857,14 +850,14 @@ export default class SegmentLoader extends videojs.EventTarget {
// this is an encrypted segment
// incrementally decrypt the segment
/* eslint-disable no-new, handle-callback-err */
new Decrypter(segmentInfo.encryptedBytes,
segment.key.bytes,
segment.key.iv,
(function(err, bytes) {
// err always null
segmentInfo.bytes = bytes;
this.handleSegment_();
}).bind(this));
decrypt(segmentInfo.encryptedBytes,
segment.key.bytes,
segment.key.iv,
(function(err, bytes) {
// err always null
segmentInfo.bytes = bytes;
this.handleSegment_();
}).bind(this));
/* eslint-enable */
} else {
this.handleSegment_();

21
test/segment-loader.test.js

@ -913,7 +913,11 @@ QUnit.test('the key is saved to the segment in the correct format', function() {
segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex];
QUnit.deepEqual(segment.key.bytes,
new Uint32Array([0, 0x01000000, 0x02000000, 0x03000000]),
new Uint8Array([
0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00]),
'passed the specified segment key');
// verify stats
@ -955,19 +959,25 @@ function() {
QUnit.equal(loader.mediaRequests, 1, '1 request');
});
QUnit.test('segment with key has decrypted bytes appended during processing', function() {
QUnit.test('segment with key has decrypted bytes appended during processing', function(assert) {
let keyRequest;
let segmentRequest;
let doneDecrypting = assert.async();
// stop processing so we can examine segment info
loader.handleSegment_ = function() {};
loader.handleSegment_ = function() {
QUnit.ok(loader.pendingSegment_.bytes, 'decrypted bytes in segment');
doneDecrypting();
};
loader.playlist(playlistWithDuration(10, {isEncrypted: true}));
loader.mimeType(this.mimeType);
loader.load();
segmentRequest = this.requests.pop();
segmentRequest.response = new Uint8Array(8).buffer;
// this response is [0, 1, 2, 3, 4, 5, 6, 7] encrypted
segmentRequest.response = new Uint8Array([60, 15, 94, 17, 13, 247, 26, 97, 97, 236, 17, 188, 250, 16, 52, 39]).buffer;
segmentRequest.respond(200, null, '');
QUnit.ok(loader.pendingSegment_.encryptedBytes, 'encrypted bytes in segment');
QUnit.ok(!loader.pendingSegment_.bytes, 'no decrypted bytes in segment');
@ -980,10 +990,9 @@ QUnit.test('segment with key has decrypted bytes appended during processing', fu
this.clock.tick(1);
// Allow the decrypter's async stream to run the callback
this.clock.tick(1);
QUnit.ok(loader.pendingSegment_.bytes, 'decrypted bytes in segment');
// verify stats
QUnit.equal(loader.mediaBytesTransferred, 8, '8 bytes');
QUnit.equal(loader.mediaBytesTransferred, 16, '16 bytes');
QUnit.equal(loader.mediaRequests, 1, '1 request');
});

Loading…
Cancel
Save