New Meta commit
This commit is contained in:
parent
fccf66fba2
commit
2b99f2f5ea
183 changed files with 13333 additions and 14421 deletions
|
|
@ -1,225 +1,170 @@
|
|||
#include "auth.h"
|
||||
#include "bitfields.h"
|
||||
#include "defines.h"
|
||||
#include "encode.h"
|
||||
#include "encryption.h"
|
||||
#include "http_parser.h"
|
||||
#include "nal.h" /*LTS*/
|
||||
#include "rijndael.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "h264.h"
|
||||
|
||||
namespace Encryption{
|
||||
/// helper function for printing binary values
|
||||
std::string hexString(const char *data, unsigned long dataLen){
|
||||
std::stringstream res;
|
||||
for (int i = 0; i < dataLen; i++){
|
||||
res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
|
||||
if (i % 4 == 3){res << " ";}
|
||||
AES::AES(){mbedtls_aes_init(&ctx);}
|
||||
|
||||
AES::~AES(){mbedtls_aes_free(&ctx);}
|
||||
|
||||
void AES::setEncryptKey(const char *key){
|
||||
mbedtls_aes_setkey_enc(&ctx, (const unsigned char *)key, 128);
|
||||
}
|
||||
void AES::setDecryptKey(const char *key){
|
||||
mbedtls_aes_setkey_dec(&ctx, (const unsigned char *)key, 128);
|
||||
}
|
||||
|
||||
DTSC::Packet AES::encryptPacketCTR(const DTSC::Meta &M, const DTSC::Packet &src, uint64_t ivec, size_t newTrack){
|
||||
DTSC::Packet res;
|
||||
if (newTrack == INVALID_TRACK_ID){
|
||||
FAIL_MSG("No target track given for track encryption!");
|
||||
return res;
|
||||
}
|
||||
return res.str();
|
||||
}
|
||||
|
||||
std::string AES_Crypt(const std::string &data, const std::string &key, std::string &ivec){
|
||||
return AES_Crypt(data.data(), data.size(), key.data(), ivec.data());
|
||||
}
|
||||
|
||||
std::string AES_Crypt(const char *data, int dataLen, const char *key, const char *ivec){
|
||||
char *outData = (char *)malloc(dataLen * sizeof(char));
|
||||
memcpy(outData, data, dataLen);
|
||||
AESFullCrypt(outData, dataLen, key, ivec);
|
||||
std::string result = std::string(outData, dataLen);
|
||||
free(outData);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// This function encrypts data in-place.
|
||||
/// It alters all parameters except dataLen.
|
||||
/// Do not use it unless you know what you are doing.
|
||||
void AESPartialCrypt(char *data, int dataLen, char *expandedKey, char *eCount, char *iVec,
|
||||
unsigned int &num, bool &initialize){
|
||||
if (initialize){
|
||||
num = 0;
|
||||
memset(eCount, 0, 16);
|
||||
/// Before use, make sure the iVec is in the UPPER 8 bytes
|
||||
memset(iVec + 8, 0, 8);
|
||||
/// Before use, make sure this is not the only copy of the key you had. It is lost upon initialization
|
||||
char cryptKey[224];
|
||||
AES_set_encrypt_key(expandedKey, 128, cryptKey);
|
||||
memcpy(expandedKey, cryptKey, 224);
|
||||
initialize = false;
|
||||
}
|
||||
char *outData = (char *)malloc(dataLen * sizeof(char));
|
||||
AES_CTR128_crypt(data, outData, dataLen, expandedKey, iVec, eCount, num);
|
||||
memcpy(data, outData, dataLen);
|
||||
free(outData);
|
||||
}
|
||||
|
||||
// Generates the contentkey from a keyseed and a keyid
|
||||
std::string PR_GenerateContentKey(std::string &keyseed, std::string &keyid){
|
||||
char contentKey[16];
|
||||
char dataBlob[92];
|
||||
char keyA[32], keyB[32], keyC[32];
|
||||
std::string keyidBytes = PR_GuidToByteArray(keyid);
|
||||
memcpy(dataBlob, keyseed.data(), 30);
|
||||
memcpy(dataBlob + 30, keyidBytes.data(), 16);
|
||||
memcpy(dataBlob + 46, keyseed.data(), 30);
|
||||
memcpy(dataBlob + 76, keyidBytes.data(), 16);
|
||||
// KeyA is generated from keyseed/keyid
|
||||
Secure::sha256bin(dataBlob, 46, keyA);
|
||||
// KeyB is generated from keyseed/keyid/keyseed
|
||||
Secure::sha256bin(dataBlob, 76, keyB);
|
||||
// KeyC is generated from keyseed/keyid/keyseed/keyid
|
||||
Secure::sha256bin(dataBlob, 92, keyC);
|
||||
for (int i = 0; i < 16; i++){
|
||||
contentKey[i] = keyA[i] ^ keyA[i + 16] ^ keyB[i] ^ keyB[i + 16] ^ keyC[i] ^ keyC[i + 16];
|
||||
}
|
||||
return std::string(contentKey, 16);
|
||||
}
|
||||
|
||||
// Transforms a guid to the MS byte array representation
|
||||
std::string PR_GuidToByteArray(std::string &guid){
|
||||
char result[16];
|
||||
result[0] = guid[3];
|
||||
result[1] = guid[2];
|
||||
result[2] = guid[1];
|
||||
result[3] = guid[0];
|
||||
|
||||
result[4] = guid[5];
|
||||
result[5] = guid[4];
|
||||
|
||||
result[6] = guid[7];
|
||||
result[7] = guid[6];
|
||||
memcpy(result + 8, guid.data() + 8, 8);
|
||||
return std::string(result, 8);
|
||||
}
|
||||
|
||||
/// This function encrypts data in-place.
|
||||
void AESFullCrypt(char *data, int dataLen, const char *key, const char *ivec){
|
||||
unsigned int num = 0;
|
||||
char expandedKey[224];
|
||||
memcpy(expandedKey, key, 16);
|
||||
char eCount[16];
|
||||
char iVec[16];
|
||||
memcpy(iVec, ivec, 8);
|
||||
bool initialize = true;
|
||||
AESPartialCrypt(data, dataLen, expandedKey, eCount, iVec, num, initialize);
|
||||
}
|
||||
|
||||
void encryptPlayReady(DTSC::Packet &thisPack, std::string &codec, const char *iVec, const char *key){
|
||||
char *data;
|
||||
size_t dataLen;
|
||||
thisPack.getString("data", data, dataLen);
|
||||
src.getString("data", data, dataLen);
|
||||
|
||||
if (codec == "H264"){
|
||||
unsigned int num = 0;
|
||||
char expandedKey[224];
|
||||
memcpy(expandedKey, key, 16);
|
||||
char eCount[16];
|
||||
char initVec[16];
|
||||
memcpy(initVec, iVec, 8);
|
||||
bool initialize = true;
|
||||
size_t trackIdx = M.getSourceTrack(newTrack);
|
||||
|
||||
int pos = 0;
|
||||
char *encData = (char *)malloc(dataLen);
|
||||
|
||||
std::deque<int> nalSizes = nalu::parseNalSizes(thisPack);
|
||||
for (std::deque<int>::iterator it = nalSizes.begin(); it != nalSizes.end(); it++){
|
||||
int encrypted = (*it - 5) & ~0xF; // Bitmask to a multiple of 16
|
||||
int clear = *it - encrypted;
|
||||
Encryption::AESPartialCrypt(data + pos + clear, encrypted, expandedKey, eCount, initVec, num, initialize);
|
||||
pos += *it;
|
||||
}
|
||||
size_t dataOffset = 0;
|
||||
|
||||
if (M.getType(trackIdx) == "video" && dataLen > 96){
|
||||
dataOffset = dataLen - (int((dataLen - 96) / 16) * 16);
|
||||
memcpy(encData, data, dataOffset);
|
||||
}
|
||||
if (codec == "AAC"){Encryption::AESFullCrypt(data, dataLen, key, iVec);}
|
||||
}
|
||||
|
||||
/// Converts a hexidecimal string format key to binary string format.
|
||||
std::string binKey(std::string hexkey){
|
||||
char newkey[16];
|
||||
memset(newkey, 0, 16);
|
||||
for (size_t i = 0; i < hexkey.size(); ++i){
|
||||
char c = hexkey[i];
|
||||
newkey[i >> 1] |= ((c & 15) + (((c & 64) >> 6) | ((c & 64) >> 3))) << ((~i & 1) << 2);
|
||||
if (!encryptBlockCTR(ivec, data + dataOffset, encData + dataOffset, dataLen - dataOffset)){
|
||||
FAIL_MSG("Failed to encrypt packet");
|
||||
free(encData);
|
||||
return res;
|
||||
}
|
||||
return std::string(newkey, 16);
|
||||
}
|
||||
|
||||
/// Helper function for urlescape.
|
||||
/// Encodes a character as two hex digits.
|
||||
std::string hex(char dec){
|
||||
char dig1 = (dec & 0xF0) >> 4;
|
||||
char dig2 = (dec & 0x0F);
|
||||
if (dig1 <= 9) dig1 += 48;
|
||||
if (10 <= dig1 && dig1 <= 15) dig1 += 97 - 10;
|
||||
if (dig2 <= 9) dig2 += 48;
|
||||
if (10 <= dig2 && dig2 <= 15) dig2 += 97 - 10;
|
||||
std::string r;
|
||||
r.append(&dig1, 1);
|
||||
r.append(&dig2, 1);
|
||||
return r;
|
||||
}
|
||||
std::string hex(const std::string &input){
|
||||
std::string res;
|
||||
res.reserve(input.size() * 2);
|
||||
for (unsigned int i = 0; i < input.size(); i++){res += hex(input[i]);}
|
||||
res.genericFill(src.getTime(), src.getInt("offset"), newTrack, encData, dataLen, 0, src.getFlag("keyframe"));
|
||||
free(encData);
|
||||
return res;
|
||||
}
|
||||
|
||||
void fillVerimatrix(verimatrixData &vmData){
|
||||
int hostPos = vmData.url.find("://") + 3;
|
||||
int portPos = vmData.url.find(":", hostPos);
|
||||
|
||||
std::string hostName =
|
||||
vmData.url.substr(hostPos, (portPos == std::string::npos ? portPos : portPos - hostPos));
|
||||
int port = (portPos == std::string::npos ? 80 : atoi(vmData.url.data() + portPos + 1));
|
||||
Socket::Connection veriConn(hostName, port, true);
|
||||
|
||||
HTTP::Parser H;
|
||||
H.url = "/CAB/keyfile?PROTECTION-TYPE=PLAYREADY&TYPE=DTV&POSITION=0&RESOURCE-ID=" + vmData.name;
|
||||
H.SetHeader("Host", vmData.url.substr(hostPos));
|
||||
H.SendRequest(veriConn);
|
||||
H.Clean();
|
||||
while (veriConn && (!veriConn.spool() || !H.Read(veriConn))){}
|
||||
vmData.key = binKey(H.GetHeader("Key"));
|
||||
vmData.keyid = H.GetHeader("KeyId");
|
||||
vmData.laurl = H.GetHeader("LAURL");
|
||||
vmData.lauurl = H.GetHeader("LAUURL");
|
||||
std::string AES::encryptBlockCTR(uint64_t ivec, const std::string &inp){
|
||||
char *resPtr = (char *)malloc(inp.size());
|
||||
if (!encryptBlockCTR(ivec, inp.c_str(), resPtr, inp.size())){
|
||||
free(resPtr);
|
||||
return "";
|
||||
}
|
||||
std::string result(resPtr, inp.size());
|
||||
free(resPtr);
|
||||
return result;
|
||||
}
|
||||
|
||||
void verimatrixData::read(const char *shmPage){
|
||||
int offset = 0;
|
||||
url = std::string(shmPage + offset);
|
||||
offset += url.size() + 1; //+1 for the concluding 0-byte
|
||||
name = std::string(shmPage + offset);
|
||||
offset += name.size() + 1; //+1 for the concluding 0-byte
|
||||
key = std::string(shmPage + offset);
|
||||
offset += key.size() + 1; //+1 for the concluding 0-byte
|
||||
keyid = std::string(shmPage + offset);
|
||||
offset += keyid.size() + 1; //+1 for the concluding 0-byte
|
||||
laurl = std::string(shmPage + offset);
|
||||
offset += laurl.size() + 1; //+1 for the concluding 0-byte
|
||||
lauurl = std::string(shmPage + offset);
|
||||
bool AES::encryptBlockCTR(uint64_t ivec, const char *src, char *dest, size_t dataLen){
|
||||
size_t ncOff = 0;
|
||||
unsigned char streamBlock[] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
key = binKey(key);
|
||||
unsigned char nonceCtr[] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
Bit::htobll((char *)nonceCtr, ivec);
|
||||
|
||||
return mbedtls_aes_crypt_ctr(&ctx, dataLen, &ncOff, nonceCtr, streamBlock,
|
||||
(const unsigned char *)src, (unsigned char *)dest) == 0;
|
||||
}
|
||||
|
||||
void verimatrixData::write(char *shmPage){
|
||||
int offset = 0;
|
||||
memcpy(shmPage + offset, url.c_str(), url.size() + 1);
|
||||
offset += url.size() + 1; //+1 for the concluding 0-byte
|
||||
memcpy(shmPage + offset, name.c_str(), name.size() + 1);
|
||||
offset += name.size() + 1; //+1 for the concluding 0-byte
|
||||
std::string tmpKey = hex(key);
|
||||
memcpy(shmPage + offset, tmpKey.c_str(), tmpKey.size() + 1);
|
||||
offset += tmpKey.size() + 1; //+1 for the concluding 0-byte
|
||||
memcpy(shmPage + offset, keyid.c_str(), keyid.size() + 1);
|
||||
offset += keyid.size() + 1; //+1 for the concluding 0-byte
|
||||
memcpy(shmPage + offset, laurl.c_str(), laurl.size() + 1);
|
||||
offset += laurl.size() + 1; //+1 for the concluding 0-byte
|
||||
memcpy(shmPage + offset, lauurl.c_str(), lauurl.size() + 1);
|
||||
DTSC::Packet AES::encryptPacketCBC(const DTSC::Meta &M, const DTSC::Packet &src, char *ivec, size_t newTrack){
|
||||
DTSC::Packet res;
|
||||
if (newTrack == INVALID_TRACK_ID){
|
||||
FAIL_MSG("No target track given for track encryption!");
|
||||
return res;
|
||||
}
|
||||
|
||||
char *data;
|
||||
size_t dataLen;
|
||||
src.getString("data", data, dataLen);
|
||||
|
||||
size_t trackIdx = M.getSourceTrack(newTrack);
|
||||
|
||||
bool encrypt = false;
|
||||
if (M.getCodec(trackIdx) == "H264"){
|
||||
std::deque<nalu::nalData> nalUnits = h264::analysePackets(data, dataLen);
|
||||
for (std::deque<nalu::nalData>::iterator it = nalUnits.begin(); it != nalUnits.end(); it++){
|
||||
if (it->nalType != 1 && it->nalType != 5){continue;}
|
||||
if (it->nalSize <= 48){continue;}
|
||||
encrypt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!encrypt){
|
||||
res.genericFill(src.getTime(), src.getInt("offset"), newTrack, data, dataLen, 0, src.getFlag("keyframe"));
|
||||
return res;
|
||||
}
|
||||
|
||||
char *encData = (char *)malloc(dataLen);
|
||||
|
||||
if (M.getCodec(trackIdx) == "H264"){
|
||||
if (!encryptH264BlockFairplay(ivec, data, encData, dataLen)){
|
||||
ERROR_MSG("Failed to encrypt a block of 16 bytes!");
|
||||
free(encData);
|
||||
return res;
|
||||
}
|
||||
}else{
|
||||
INFO_MSG("Going to fully CBC encrypt a %s packet of %zu bytes", M.getType(trackIdx).c_str(), dataLen);
|
||||
if (!encryptBlockCBC(ivec, data, encData, dataLen)){
|
||||
FAIL_MSG("Failed to encrypt packet");
|
||||
free(encData);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res.genericFill(src.getTime(), src.getInt("offset"), newTrack, encData, dataLen, 0, src.getFlag("keyframe"));
|
||||
free(encData);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool AES::encryptH264BlockFairplay(char *ivec, const char *src, char *dest, size_t dataLen){
|
||||
size_t offset = 0;
|
||||
std::deque<nalu::nalData> nalUnits = h264::analysePackets(src, dataLen);
|
||||
for (std::deque<nalu::nalData>::iterator it = nalUnits.begin(); it != nalUnits.end(); it++){
|
||||
if ((it->nalType != 1 && it->nalType != 5) || it->nalSize <= 48){
|
||||
memcpy(dest + offset, src + offset, it->nalSize + 4);
|
||||
offset += it->nalSize + 4;
|
||||
continue;
|
||||
}
|
||||
memcpy(dest + offset, src + offset, 36);
|
||||
offset += 36;
|
||||
size_t encryptedBlocks = 0;
|
||||
size_t lenToGo = it->nalSize - 32;
|
||||
while (lenToGo){
|
||||
if (lenToGo > 16){
|
||||
if (!encryptBlockCBC(ivec, src + offset, dest + offset, 16)){
|
||||
ERROR_MSG("Failed to encrypt a block of 16 bytes!");
|
||||
return false;
|
||||
}
|
||||
offset += 16;
|
||||
lenToGo -= 16;
|
||||
++encryptedBlocks;
|
||||
}
|
||||
memcpy(dest + offset, src + offset, std::min(lenToGo, (size_t)144));
|
||||
offset += std::min(lenToGo, (size_t)144);
|
||||
lenToGo -= std::min(lenToGo, (size_t)144);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string AES::encryptBlockCBC(char *ivec, const std::string &inp){
|
||||
char *resPtr = (char *)malloc(inp.size());
|
||||
if (!encryptBlockCBC(ivec, inp.c_str(), resPtr, inp.size())){
|
||||
free(resPtr);
|
||||
return "";
|
||||
}
|
||||
std::string result(resPtr, inp.size());
|
||||
free(resPtr);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AES::encryptBlockCBC(char *ivec, const char *src, char *dest, size_t dataLen){
|
||||
if (dataLen % 16){WARN_MSG("Encrypting a non-multiple of 16 bytes: %zu", dataLen);}
|
||||
return mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, dataLen, (unsigned char *)ivec,
|
||||
(const unsigned char *)src, (unsigned char *)dest) == 0;
|
||||
}
|
||||
}// namespace Encryption
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue