no commit message
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.hls.utils {
|
||||
import flash.utils.getTimer;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.events.Event;
|
||||
|
||||
/**
|
||||
* Contains Utility functions for AES-128 CBC Decryption
|
||||
*/
|
||||
public class AES {
|
||||
private var _key : FastAESKey;
|
||||
//private var _keyArray : ByteArray;
|
||||
private var iv0 : uint;
|
||||
private var iv1 : uint;
|
||||
private var iv2 : uint;
|
||||
private var iv3 : uint;
|
||||
/* callback function upon decrypt progress */
|
||||
private var _progress : Function;
|
||||
/* callback function upon decrypt complete */
|
||||
private var _complete : Function;
|
||||
/** Byte data to be decrypt **/
|
||||
private var _data : ByteArray;
|
||||
/** read position **/
|
||||
private var _readPosition : uint;
|
||||
/** write position **/
|
||||
private var _writePosition : uint;
|
||||
/** chunk size to avoid blocking **/
|
||||
private static const CHUNK_SIZE : uint = 2048;
|
||||
/** is bytearray full ? **/
|
||||
private var _dataComplete : Boolean;
|
||||
/** display object used for ENTER_FRAME listener */
|
||||
private var _displayObject : DisplayObject;
|
||||
|
||||
public function AES(displayObject : DisplayObject, key : ByteArray, iv : ByteArray, notifyprogress : Function, notifycomplete : Function) {
|
||||
// _keyArray = key;
|
||||
_key = new FastAESKey(key);
|
||||
iv.position = 0;
|
||||
iv0 = iv.readUnsignedInt();
|
||||
iv1 = iv.readUnsignedInt();
|
||||
iv2 = iv.readUnsignedInt();
|
||||
iv3 = iv.readUnsignedInt();
|
||||
_data = new ByteArray();
|
||||
_dataComplete = false;
|
||||
_progress = notifyprogress;
|
||||
_complete = notifycomplete;
|
||||
_readPosition = 0;
|
||||
_writePosition = 0;
|
||||
_displayObject = displayObject;
|
||||
}
|
||||
|
||||
public function append(data : ByteArray) : void {
|
||||
// CONFIG::LOGGING {
|
||||
// Log.info("notify append");
|
||||
// }
|
||||
_data.position = _writePosition;
|
||||
_data.writeBytes(data);
|
||||
if (_writePosition == 0) {
|
||||
_displayObject.addEventListener(Event.ENTER_FRAME, _decryptTimer);
|
||||
}
|
||||
_writePosition += data.length;
|
||||
}
|
||||
|
||||
public function notifycomplete() : void {
|
||||
// CONFIG::LOGGING {
|
||||
// Log.info("notify complete");
|
||||
// }
|
||||
_dataComplete = true;
|
||||
}
|
||||
|
||||
public function cancel() : void {
|
||||
_displayObject.removeEventListener(Event.ENTER_FRAME, _decryptTimer);
|
||||
}
|
||||
|
||||
private function _decryptTimer(e : Event) : void {
|
||||
var start_time : int = getTimer();
|
||||
var decrypted : Boolean;
|
||||
do {
|
||||
decrypted = _decryptChunk();
|
||||
// dont spend more than 10ms in the decrypt timer to avoid blocking/freezing video
|
||||
// if frame rate is 60fps, we have 1000/60 = 16.6ms budget total per frame
|
||||
} while (decrypted && (getTimer() - start_time) < 10);
|
||||
}
|
||||
|
||||
/** decrypt a small chunk of packets each time to avoid blocking **/
|
||||
private function _decryptChunk() : Boolean {
|
||||
_data.position = _readPosition;
|
||||
var decryptdata : ByteArray;
|
||||
if (_data.bytesAvailable) {
|
||||
if (_data.bytesAvailable <= CHUNK_SIZE) {
|
||||
if (_dataComplete) {
|
||||
// CONFIG::LOGGING {
|
||||
// Log.info("data complete, last chunk");
|
||||
// }
|
||||
_readPosition += _data.bytesAvailable;
|
||||
decryptdata = _decryptCBC(_data, _data.bytesAvailable);
|
||||
unpad(decryptdata);
|
||||
} else {
|
||||
// data not complete, and available data less than chunk size, return
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_readPosition += CHUNK_SIZE;
|
||||
decryptdata = _decryptCBC(_data, CHUNK_SIZE);
|
||||
}
|
||||
_progress(decryptdata);
|
||||
return true;
|
||||
} else {
|
||||
if (_dataComplete) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("AES:data+decrypt completed, callback");
|
||||
}
|
||||
// callback
|
||||
_complete();
|
||||
_displayObject.removeEventListener(Event.ENTER_FRAME, _decryptTimer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cypher Block Chaining Decryption, refer to
|
||||
* http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_
|
||||
* for algorithm description
|
||||
*/
|
||||
private function _decryptCBC(crypt : ByteArray, len : uint) : ByteArray {
|
||||
var src : Vector.<uint> = new Vector.<uint>(4);
|
||||
var dst : Vector.<uint> = new Vector.<uint>(4);
|
||||
var decrypt : ByteArray = new ByteArray();
|
||||
decrypt.length = len;
|
||||
|
||||
for (var i : uint = 0; i < len / 16; i++) {
|
||||
// read src byte array
|
||||
src[0] = crypt.readUnsignedInt();
|
||||
src[1] = crypt.readUnsignedInt();
|
||||
src[2] = crypt.readUnsignedInt();
|
||||
src[3] = crypt.readUnsignedInt();
|
||||
|
||||
// AES decrypt src vector into dst vector
|
||||
_key.decrypt128(src, dst);
|
||||
|
||||
// CBC : write output = XOR(decrypted,IV)
|
||||
decrypt.writeUnsignedInt(dst[0] ^ iv0);
|
||||
decrypt.writeUnsignedInt(dst[1] ^ iv1);
|
||||
decrypt.writeUnsignedInt(dst[2] ^ iv2);
|
||||
decrypt.writeUnsignedInt(dst[3] ^ iv3);
|
||||
|
||||
// CBC : next IV = (input)
|
||||
iv0 = src[0];
|
||||
iv1 = src[1];
|
||||
iv2 = src[2];
|
||||
iv3 = src[3];
|
||||
}
|
||||
decrypt.position = 0;
|
||||
return decrypt;
|
||||
}
|
||||
|
||||
public function unpad(a : ByteArray) : void {
|
||||
var c : uint = a.length % 16;
|
||||
if (c != 0) throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
|
||||
c = a[a.length - 1];
|
||||
for (var i : uint = c; i > 0; i--) {
|
||||
var v : uint = a[a.length - 1];
|
||||
a.length--;
|
||||
if (c != v) throw new Error("PKCS#5:unpad: Invalid padding value. expected [" + c + "], found [" + v + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy() : void {
|
||||
_key.dispose();
|
||||
// _key = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user