Skip to content

Commit

Permalink
fix(HLS): Fix load AES media playlist (#7012)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad authored Jul 10, 2024
1 parent dcc60f9 commit 3bd032c
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 58 deletions.
23 changes: 16 additions & 7 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ shaka.hls.HlsParser = class {
if (!segments.length) {
return defaultBasicInfo;
}
const segment = this.getAvailableSegment_(segments);
const {segment, segmentIndex} = this.getAvailableSegment_(segments);
const segmentUris = segment.getUris();
const segmentUri = segmentUris[0];
const parsedUri = new goog.Uri(segmentUri);
Expand All @@ -1050,6 +1050,10 @@ shaka.hls.HlsParser = class {
const initResponse = await this.makeNetworkRequest_(
initSegmentRequest, requestType, {type: initType});
initData = initResponse.data;
if (initSegmentRef.aesKey) {
initData = await shaka.media.SegmentUtils.aesDecrypt(
initData, initSegmentRef.aesKey, 0);
}

initMimeType = initResponse.headers['content-type'];
if (initMimeType) {
Expand All @@ -1064,6 +1068,11 @@ shaka.hls.HlsParser = class {
const type = shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
const response = await this.makeNetworkRequest_(
segmentRequest, requestType, {type});
let data = response.data;
if (segment.aesKey) {
data = await shaka.media.SegmentUtils.aesDecrypt(
data, segment.aesKey, segmentIndex);
}

let contentMimeType = response.headers['content-type'];
if (contentMimeType) {
Expand Down Expand Up @@ -1091,17 +1100,17 @@ shaka.hls.HlsParser = class {
];

if (shaka.util.TsParser.probe(
shaka.util.BufferUtils.toUint8(response.data))) {
shaka.util.BufferUtils.toUint8(data))) {
const basicInfo =
shaka.media.SegmentUtils.getBasicInfoFromTs(response.data);
shaka.media.SegmentUtils.getBasicInfoFromTs(data);
if (basicInfo) {
return basicInfo;
}
} else if (validMp4Extensions.includes(extension) ||
validMp4MimeType.includes(contentMimeType) ||
(initMimeType && validMp4MimeType.includes(initMimeType))) {
const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromMp4(
initData, response.data);
initData, data);
if (basicInfo) {
return basicInfo;
}
Expand Down Expand Up @@ -4266,7 +4275,7 @@ shaka.hls.HlsParser = class {

/**
* @param {!Array.<!shaka.media.SegmentReference>} segments
* @return {!shaka.media.SegmentReference}
* @return {{segment: !shaka.media.SegmentReference, segmentIndex: number}}
* @private
*/
getAvailableSegment_(segments) {
Expand All @@ -4283,7 +4292,7 @@ shaka.hls.HlsParser = class {
segmentIndex ++;
segment = segments[segmentIndex];
}
return segment;
return {segment, segmentIndex};
}

/**
Expand All @@ -4299,7 +4308,7 @@ shaka.hls.HlsParser = class {
const HlsParser = shaka.hls.HlsParser;
const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;

const segment = this.getAvailableSegment_(segments);
const {segment} = this.getAvailableSegment_(segments);

if (segment.status == shaka.media.SegmentReference.Status.MISSING) {
return this.guessMimeTypeFallback_(contentType);
Expand Down
41 changes: 41 additions & 0 deletions lib/media/segment_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,47 @@ shaka.media.SegmentUtils = class {
.parse(data, /* partialOkay= */ true);
return defaultKID;
}

/**
* @param {!BufferSource} rawResult
* @param {shaka.extern.aesKey} aesKey
* @param {number} position
* @return {!Promise.<!BufferSource>}
*/
static async aesDecrypt(rawResult, aesKey, position) {
const key = aesKey;
if (!key.cryptoKey) {
goog.asserts.assert(key.fetchKey, 'If AES cryptoKey was not ' +
'preloaded, fetchKey function should be provided');
await key.fetchKey();
goog.asserts.assert(key.cryptoKey, 'AES cryptoKey should now be set');
}
let iv = key.iv;
if (!iv) {
iv = shaka.util.BufferUtils.toUint8(new ArrayBuffer(16));
let sequence = key.firstMediaSequenceNumber + position;
for (let i = iv.byteLength - 1; i >= 0; i--) {
iv[i] = sequence & 0xff;
sequence >>= 8;
}
}
let algorithm;
if (aesKey.blockCipherMode == 'CBC') {
algorithm = {
name: 'AES-CBC',
iv,
};
} else {
algorithm = {
name: 'AES-CTR',
counter: iv,
// NIST SP800-38A standard suggests that the counter should occupy half
// of the counter block
length: 64,
};
}
return window.crypto.subtle.decrypt(algorithm, key.cryptoKey, rawResult);
}
};


Expand Down
47 changes: 3 additions & 44 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ goog.require('shaka.media.MediaSourceEngine');
goog.require('shaka.media.SegmentIterator');
goog.require('shaka.media.SegmentReference');
goog.require('shaka.media.SegmentPrefetch');
goog.require('shaka.media.SegmentUtils');
goog.require('shaka.net.Backoff');
goog.require('shaka.net.NetworkingEngine');
goog.require('shaka.util.BufferUtils');
goog.require('shaka.util.DelayedTick');
goog.require('shaka.util.Destroyer');
goog.require('shaka.util.Error');
Expand Down Expand Up @@ -1749,48 +1749,6 @@ shaka.media.StreamingEngine = class {
}
}

/**
* @param {!BufferSource} rawResult
* @param {shaka.extern.aesKey} aesKey
* @param {number} position
* @return {!Promise.<!BufferSource>} finalResult
* @private
*/
async aesDecrypt_(rawResult, aesKey, position) {
const key = aesKey;
if (!key.cryptoKey) {
goog.asserts.assert(key.fetchKey, 'If AES cryptoKey was not ' +
'preloaded, fetchKey function should be provided');
await key.fetchKey();
goog.asserts.assert(key.cryptoKey, 'AES cryptoKey should now be set');
}
let iv = key.iv;
if (!iv) {
iv = shaka.util.BufferUtils.toUint8(new ArrayBuffer(16));
let sequence = key.firstMediaSequenceNumber + position;
for (let i = iv.byteLength - 1; i >= 0; i--) {
iv[i] = sequence & 0xff;
sequence >>= 8;
}
}
let algorithm;
if (aesKey.blockCipherMode == 'CBC') {
algorithm = {
name: 'AES-CBC',
iv,
};
} else {
algorithm = {
name: 'AES-CTR',
counter: iv,
// NIST SP800-38A standard suggests that the counter should occupy half
// of the counter block
length: 64,
};
}
return window.crypto.subtle.decrypt(algorithm, key.cryptoKey, rawResult);
}


/**
* Clear per-stream error states and retry any failed streams.
Expand Down Expand Up @@ -2567,7 +2525,8 @@ shaka.media.StreamingEngine = class {
mediaState.operation = null;
let result = response.data;
if (reference.aesKey) {
result = await this.aesDecrypt_(result, reference.aesKey, position);
result = await shaka.media.SegmentUtils.aesDecrypt(
result, reference.aesKey, position);
}
return result;
}
Expand Down
2 changes: 1 addition & 1 deletion test/hls/hls_parser_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe('HlsParser', () => {
keyRequests++;
}
});
await player.load('/base/test/test/assets/hls-aes-256/index.m3u8');
await player.load('/base/test/test/assets/hls-aes-256/media.m3u8');
await video.play();
expect(player.isLive()).toBe(false);

Expand Down
6 changes: 0 additions & 6 deletions test/test/assets/hls-aes-256/index.m3u8

This file was deleted.

0 comments on commit 3bd032c

Please sign in to comment.