Such style. (Code style unification)
This commit is contained in:
parent
57bcd8f25c
commit
8c01ec8897
57 changed files with 6548 additions and 6437 deletions
|
@ -39,59 +39,61 @@ std::map<unsigned int, RTMPStream::Chunk> RTMPStream::lastrecv;
|
|||
#include <openssl/hmac.h>
|
||||
|
||||
#define P1024 \
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
|
||||
|
||||
uint8_t genuineFMSKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
|
||||
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72,
|
||||
0x76, // Genuine Adobe Flash Media Server 001
|
||||
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
|
||||
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68
|
||||
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72,
|
||||
0x76, // Genuine Adobe Flash Media Server 001
|
||||
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
|
||||
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
|
||||
}; // 68
|
||||
|
||||
uint8_t genuineFPKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
|
||||
0x50, 0x6c, 0x61,
|
||||
0x79, // Genuine Adobe Flash Player 001
|
||||
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
|
||||
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62
|
||||
0x50, 0x6c, 0x61,
|
||||
0x79, // Genuine Adobe Flash Player 001
|
||||
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
|
||||
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
|
||||
}; // 62
|
||||
|
||||
inline uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){
|
||||
if (scheme == 0){
|
||||
inline uint32_t GetDigestOffset(uint8_t * pBuffer, uint8_t scheme) {
|
||||
if (scheme == 0) {
|
||||
return ((pBuffer[8] + pBuffer[9] + pBuffer[10] + pBuffer[11]) % 728) + 12;
|
||||
}else{
|
||||
} else {
|
||||
return ((pBuffer[772] + pBuffer[773] + pBuffer[774] + pBuffer[775]) % 728) + 776;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t GetDHOffset(uint8_t *pBuffer, uint8_t scheme){
|
||||
if (scheme == 0){
|
||||
inline uint32_t GetDHOffset(uint8_t * pBuffer, uint8_t scheme) {
|
||||
if (scheme == 0) {
|
||||
return ((pBuffer[1532] + pBuffer[1533] + pBuffer[1534] + pBuffer[1535]) % 632) + 772;
|
||||
}else{
|
||||
} else {
|
||||
return ((pBuffer[768] + pBuffer[769] + pBuffer[770] + pBuffer[771]) % 632) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
class DHWrapper{
|
||||
class DHWrapper {
|
||||
private:
|
||||
int32_t _bitsCount;
|
||||
DH *_pDH;
|
||||
uint8_t *_pSharedKey;
|
||||
DH * _pDH;
|
||||
uint8_t * _pSharedKey;
|
||||
int32_t _sharedKeyLength;
|
||||
BIGNUM *_peerPublickey;
|
||||
BIGNUM * _peerPublickey;
|
||||
public:
|
||||
DHWrapper(int32_t bitsCount);
|
||||
virtual ~DHWrapper();
|
||||
bool Initialize();
|
||||
bool CopyPublicKey(uint8_t *pDst, int32_t dstLength);
|
||||
bool CopyPrivateKey(uint8_t *pDst, int32_t dstLength);
|
||||
bool CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length);
|
||||
bool CopySharedKey(uint8_t *pDst, int32_t dstLength);
|
||||
bool CopyPublicKey(uint8_t * pDst, int32_t dstLength);
|
||||
bool CopyPrivateKey(uint8_t * pDst, int32_t dstLength);
|
||||
bool CreateSharedKey(uint8_t * pPeerPublicKey, int32_t length);
|
||||
bool CopySharedKey(uint8_t * pDst, int32_t dstLength);
|
||||
private:
|
||||
void Cleanup();
|
||||
bool CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength);
|
||||
bool CopyKey(BIGNUM * pNum, uint8_t * pDst, int32_t dstLength);
|
||||
};
|
||||
|
||||
DHWrapper::DHWrapper(int32_t bitsCount){
|
||||
DHWrapper::DHWrapper(int32_t bitsCount) {
|
||||
_bitsCount = bitsCount;
|
||||
_pDH = 0;
|
||||
_pSharedKey = 0;
|
||||
|
@ -99,73 +101,73 @@ DHWrapper::DHWrapper(int32_t bitsCount){
|
|||
_peerPublickey = 0;
|
||||
}
|
||||
|
||||
DHWrapper::~DHWrapper(){
|
||||
DHWrapper::~DHWrapper() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
bool DHWrapper::Initialize(){
|
||||
bool DHWrapper::Initialize() {
|
||||
Cleanup();
|
||||
_pDH = DH_new();
|
||||
if ( !_pDH){
|
||||
if (!_pDH) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
_pDH->p = BN_new();
|
||||
if ( !_pDH->p){
|
||||
if (!_pDH->p) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
_pDH->g = BN_new();
|
||||
if ( !_pDH->g){
|
||||
if (!_pDH->g) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
if (BN_hex2bn( &_pDH->p, P1024) == 0){
|
||||
if (BN_hex2bn(&_pDH->p, P1024) == 0) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
if (BN_set_word(_pDH->g, 2) != 1){
|
||||
if (BN_set_word(_pDH->g, 2) != 1) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
_pDH->length = _bitsCount;
|
||||
if (DH_generate_key(_pDH) != 1){
|
||||
if (DH_generate_key(_pDH) != 1) {
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CopyPublicKey(uint8_t * pDst, int32_t dstLength) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
return CopyKey(_pDH->pub_key, pDst, dstLength);
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CopyPrivateKey(uint8_t * pDst, int32_t dstLength) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
return CopyKey(_pDH->priv_key, pDst, dstLength);
|
||||
}
|
||||
|
||||
bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CreateSharedKey(uint8_t * pPeerPublicKey, int32_t length) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
if (_sharedKeyLength != 0 || _pSharedKey){
|
||||
if (_sharedKeyLength != 0 || _pSharedKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_sharedKeyLength = DH_size(_pDH);
|
||||
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){
|
||||
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_pSharedKey = new uint8_t[_sharedKeyLength];
|
||||
_peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0);
|
||||
if ( !_peerPublickey){
|
||||
if (!_peerPublickey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -173,93 +175,93 @@ bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength){
|
||||
if ( !_pDH){
|
||||
bool DHWrapper::CopySharedKey(uint8_t * pDst, int32_t dstLength) {
|
||||
if (!_pDH) {
|
||||
return false;
|
||||
}
|
||||
if (dstLength != _sharedKeyLength){
|
||||
if (dstLength != _sharedKeyLength) {
|
||||
return false;
|
||||
}
|
||||
memcpy(pDst, _pSharedKey, _sharedKeyLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DHWrapper::Cleanup(){
|
||||
if (_pDH){
|
||||
if (_pDH->p){
|
||||
void DHWrapper::Cleanup() {
|
||||
if (_pDH) {
|
||||
if (_pDH->p) {
|
||||
BN_free(_pDH->p);
|
||||
_pDH->p = 0;
|
||||
}
|
||||
if (_pDH->g){
|
||||
if (_pDH->g) {
|
||||
BN_free(_pDH->g);
|
||||
_pDH->g = 0;
|
||||
}
|
||||
DH_free(_pDH);
|
||||
_pDH = 0;
|
||||
}
|
||||
if (_pSharedKey){
|
||||
if (_pSharedKey) {
|
||||
delete[] _pSharedKey;
|
||||
_pSharedKey = 0;
|
||||
}
|
||||
_sharedKeyLength = 0;
|
||||
if (_peerPublickey){
|
||||
if (_peerPublickey) {
|
||||
BN_free(_peerPublickey);
|
||||
_peerPublickey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength){
|
||||
bool DHWrapper::CopyKey(BIGNUM * pNum, uint8_t * pDst, int32_t dstLength) {
|
||||
int32_t keySize = BN_num_bytes(pNum);
|
||||
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){
|
||||
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)) {
|
||||
return false;
|
||||
}
|
||||
if (BN_bn2bin(pNum, pDst) != keySize){
|
||||
if (BN_bn2bin(pNum, pDst) != keySize) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut){
|
||||
void InitRC4Encryption(uint8_t * secretKey, uint8_t * pubKeyIn, uint8_t * pubKeyOut, RC4_KEY * rc4keyIn, RC4_KEY * rc4keyOut) {
|
||||
uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
unsigned int digestLen = 0;
|
||||
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init( &ctx);
|
||||
HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update( &ctx, pubKeyIn, 128);
|
||||
HMAC_Final( &ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup( &ctx);
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update(&ctx, pubKeyIn, 128);
|
||||
HMAC_Final(&ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
|
||||
RC4_set_key(rc4keyOut, 16, digest);
|
||||
|
||||
HMAC_CTX_init( &ctx);
|
||||
HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update( &ctx, pubKeyOut, 128);
|
||||
HMAC_Final( &ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup( &ctx);
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
|
||||
HMAC_Update(&ctx, pubKeyOut, 128);
|
||||
HMAC_Final(&ctx, digest, &digestLen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
|
||||
RC4_set_key(rc4keyIn, 16, digest);
|
||||
}
|
||||
|
||||
void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult){
|
||||
void HMACsha256(const void * pData, uint32_t dataLength, const void * pKey, uint32_t keyLength, void * pResult) {
|
||||
unsigned int digestLen;
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init( &ctx);
|
||||
HMAC_Init_ex( &ctx, (unsigned char*)pKey, keyLength, EVP_sha256(), 0);
|
||||
HMAC_Update( &ctx, (unsigned char *)pData, dataLength);
|
||||
HMAC_Final( &ctx, (unsigned char *)pResult, &digestLen);
|
||||
HMAC_CTX_cleanup( &ctx);
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init_ex(&ctx, (unsigned char *)pKey, keyLength, EVP_sha256(), 0);
|
||||
HMAC_Update(&ctx, (unsigned char *)pData, dataLength);
|
||||
HMAC_Final(&ctx, (unsigned char *)pResult, &digestLen);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
}
|
||||
|
||||
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
|
||||
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) {
|
||||
uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);
|
||||
uint8_t *pTempBuffer = new uint8_t[1536 - 32];
|
||||
uint8_t * pTempBuffer = new uint8_t[1536 - 32];
|
||||
memcpy(pTempBuffer, pBuffer, clientDigestOffset);
|
||||
memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32);
|
||||
uint8_t *pTempHash = new uint8_t[512];
|
||||
uint8_t * pTempHash = new uint8_t[512];
|
||||
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
|
||||
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result?"success":"failed");
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Client scheme validation %hhi %s", scheme, result ? "success" : "failed");
|
||||
delete[] pTempBuffer;
|
||||
delete[] pTempHash;
|
||||
return result;
|
||||
|
@ -268,58 +270,58 @@ bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
|
|||
/// Packs up the chunk for sending over the network.
|
||||
/// \warning Do not call if you are not actually sending the resulting data!
|
||||
/// \returns A std::string ready to be sent.
|
||||
std::string & RTMPStream::Chunk::Pack(){
|
||||
std::string & RTMPStream::Chunk::Pack() {
|
||||
static std::string output;
|
||||
output.clear();
|
||||
bool allow_short = lastsend.count(cs_id);
|
||||
RTMPStream::Chunk prev = lastsend[cs_id];
|
||||
unsigned int tmpi;
|
||||
unsigned char chtype = 0x00;
|
||||
if (allow_short && (prev.cs_id == cs_id)){
|
||||
if (msg_stream_id == prev.msg_stream_id){
|
||||
if (allow_short && (prev.cs_id == cs_id)) {
|
||||
if (msg_stream_id == prev.msg_stream_id) {
|
||||
chtype = 0x40; //do not send msg_stream_id
|
||||
if (len == prev.len){
|
||||
if (msg_type_id == prev.msg_type_id){
|
||||
if (len == prev.len) {
|
||||
if (msg_type_id == prev.msg_type_id) {
|
||||
chtype = 0x80; //do not send len and msg_type_id
|
||||
if (timestamp == prev.timestamp){
|
||||
if (timestamp == prev.timestamp) {
|
||||
chtype = 0xC0; //do not send timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel
|
||||
if (timestamp < prev.timestamp){
|
||||
if (timestamp < prev.timestamp) {
|
||||
chtype = 0x00;
|
||||
}
|
||||
}
|
||||
if (cs_id <= 63){
|
||||
if (cs_id <= 63) {
|
||||
output += (unsigned char)(chtype | cs_id);
|
||||
}else{
|
||||
if (cs_id <= 255 + 64){
|
||||
} else {
|
||||
if (cs_id <= 255 + 64) {
|
||||
output += (unsigned char)(chtype | 0);
|
||||
output += (unsigned char)(cs_id - 64);
|
||||
}else{
|
||||
} else {
|
||||
output += (unsigned char)(chtype | 1);
|
||||
output += (unsigned char)((cs_id - 64) % 256);
|
||||
output += (unsigned char)((cs_id - 64) / 256);
|
||||
}
|
||||
}
|
||||
unsigned int ntime = 0;
|
||||
if (chtype != 0xC0){
|
||||
if (chtype != 0xC0) {
|
||||
//timestamp or timestamp diff
|
||||
if (chtype == 0x00){
|
||||
if (chtype == 0x00) {
|
||||
tmpi = timestamp;
|
||||
}else{
|
||||
} else {
|
||||
tmpi = timestamp - prev.timestamp;
|
||||
}
|
||||
if (tmpi >= 0x00ffffff){
|
||||
if (tmpi >= 0x00ffffff) {
|
||||
ntime = tmpi;
|
||||
tmpi = 0x00ffffff;
|
||||
}
|
||||
output += (unsigned char)((tmpi >> 16) & 0xff);
|
||||
output += (unsigned char)((tmpi >> 8) & 0xff);
|
||||
output += (unsigned char)(tmpi & 0xff);
|
||||
if (chtype != 0x80){
|
||||
if (chtype != 0x80) {
|
||||
//len
|
||||
tmpi = len;
|
||||
output += (unsigned char)((tmpi >> 16) & 0xff);
|
||||
|
@ -327,7 +329,7 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
output += (unsigned char)(tmpi & 0xff);
|
||||
//msg type id
|
||||
output += (unsigned char)msg_type_id;
|
||||
if (chtype != 0x40){
|
||||
if (chtype != 0x40) {
|
||||
//msg stream id
|
||||
output += (unsigned char)(msg_stream_id % 256);
|
||||
output += (unsigned char)(msg_stream_id / 256);
|
||||
|
@ -337,28 +339,28 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
}
|
||||
}
|
||||
//support for 0x00ffffff timestamps
|
||||
if (ntime){
|
||||
if (ntime) {
|
||||
output += (unsigned char)(ntime & 0xff);
|
||||
output += (unsigned char)((ntime >> 8) & 0xff);
|
||||
output += (unsigned char)((ntime >> 16) & 0xff);
|
||||
output += (unsigned char)((ntime >> 24) & 0xff);
|
||||
}
|
||||
len_left = 0;
|
||||
while (len_left < len){
|
||||
while (len_left < len) {
|
||||
tmpi = len - len_left;
|
||||
if (tmpi > RTMPStream::chunk_snd_max){
|
||||
if (tmpi > RTMPStream::chunk_snd_max) {
|
||||
tmpi = RTMPStream::chunk_snd_max;
|
||||
}
|
||||
output.append(data, len_left, tmpi);
|
||||
len_left += tmpi;
|
||||
if (len_left < len){
|
||||
if (cs_id <= 63){
|
||||
if (len_left < len) {
|
||||
if (cs_id <= 63) {
|
||||
output += (unsigned char)(0xC0 + cs_id);
|
||||
}else{
|
||||
if (cs_id <= 255 + 64){
|
||||
} else {
|
||||
if (cs_id <= 255 + 64) {
|
||||
output += (unsigned char)(0xC0);
|
||||
output += (unsigned char)(cs_id - 64);
|
||||
}else{
|
||||
} else {
|
||||
output += (unsigned char)(0xC1);
|
||||
output += (unsigned char)((cs_id - 64) % 256);
|
||||
output += (unsigned char)((cs_id - 64) / 256);
|
||||
|
@ -372,7 +374,7 @@ std::string & RTMPStream::Chunk::Pack(){
|
|||
} //SendChunk
|
||||
|
||||
/// Default constructor, creates an empty chunk with all values initialized to zero.
|
||||
RTMPStream::Chunk::Chunk(){
|
||||
RTMPStream::Chunk::Chunk() {
|
||||
headertype = 0;
|
||||
cs_id = 0;
|
||||
timestamp = 0;
|
||||
|
@ -385,7 +387,7 @@ RTMPStream::Chunk::Chunk(){
|
|||
} //constructor
|
||||
|
||||
/// Packs up a chunk with the given arguments as properties.
|
||||
std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data){
|
||||
std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = cs_id;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -403,7 +405,7 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i
|
|||
/// \param data Contents of the media data.
|
||||
/// \param len Length of the media data, in bytes.
|
||||
/// \param ts Timestamp of the media data, relative to current system time.
|
||||
std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){
|
||||
std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = msg_type_id + 42;
|
||||
ch.timestamp = ts;
|
||||
|
@ -412,13 +414,13 @@ std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * d
|
|||
ch.len_left = 0;
|
||||
ch.msg_type_id = msg_type_id;
|
||||
ch.msg_stream_id = 1;
|
||||
ch.data = std::string((char*)data, (size_t)len);
|
||||
ch.data = std::string((char *)data, (size_t)len);
|
||||
return ch.Pack();
|
||||
} //SendMedia
|
||||
|
||||
/// Packs up a chunk with media contents.
|
||||
/// \param tag FLV::Tag with media to send.
|
||||
std::string & RTMPStream::SendMedia(FLV::Tag & tag){
|
||||
std::string & RTMPStream::SendMedia(FLV::Tag & tag) {
|
||||
static RTMPStream::Chunk ch;
|
||||
//Commented bit is more efficient and correct according to RTMP spec.
|
||||
//Simply passing "4" is the only thing that actually plays correctly, though.
|
||||
|
@ -435,7 +437,7 @@ std::string & RTMPStream::SendMedia(FLV::Tag & tag){
|
|||
} //SendMedia
|
||||
|
||||
/// Packs up a chunk for a control message with 1 argument.
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -445,12 +447,12 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){
|
|||
ch.msg_type_id = type;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(4);
|
||||
*(int*)((char*)ch.data.c_str()) = htonl(data);
|
||||
*(int *)((char *)ch.data.c_str()) = htonl(data);
|
||||
return ch.Pack();
|
||||
} //SendCTL
|
||||
|
||||
/// Packs up a chunk for a control message with 2 arguments.
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2){
|
||||
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -460,13 +462,13 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigne
|
|||
ch.msg_type_id = type;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(5);
|
||||
*(unsigned int*)((char*)ch.data.c_str()) = htonl(data);
|
||||
*(unsigned int *)((char *)ch.data.c_str()) = htonl(data);
|
||||
ch.data[4] = data2;
|
||||
return ch.Pack();
|
||||
} //SendCTL
|
||||
|
||||
/// Packs up a chunk for a user control message with 1 argument.
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -476,14 +478,14 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){
|
|||
ch.msg_type_id = 4;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(6);
|
||||
*(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data);
|
||||
*(unsigned int *)(((char *)ch.data.c_str()) + 2) = htonl(data);
|
||||
ch.data[0] = 0;
|
||||
ch.data[1] = type;
|
||||
return ch.Pack();
|
||||
} //SendUSR
|
||||
|
||||
/// Packs up a chunk for a user control message with 2 arguments.
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2){
|
||||
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2) {
|
||||
static RTMPStream::Chunk ch;
|
||||
ch.cs_id = 2;
|
||||
ch.timestamp = Util::getMS();
|
||||
|
@ -493,8 +495,8 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
|
|||
ch.msg_type_id = 4;
|
||||
ch.msg_stream_id = 0;
|
||||
ch.data.resize(10);
|
||||
*(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data);
|
||||
*(unsigned int*)(((char*)ch.data.c_str()) + 6) = htonl(data2);
|
||||
*(unsigned int *)(((char *)ch.data.c_str()) + 2) = htonl(data);
|
||||
*(unsigned int *)(((char *)ch.data.c_str()) + 6) = htonl(data2);
|
||||
ch.data[0] = 0;
|
||||
ch.data[1] = type;
|
||||
return ch.Pack();
|
||||
|
@ -508,14 +510,14 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
|
|||
/// \param indata The input string to parse and update.
|
||||
/// \warning This function will destroy the current data in this chunk!
|
||||
/// \returns True if a whole chunk could be read, false otherwise.
|
||||
bool RTMPStream::Chunk::Parse(std::string & indata){
|
||||
gettimeofday( &RTMPStream::lastrec, 0);
|
||||
bool RTMPStream::Chunk::Parse(std::string & indata) {
|
||||
gettimeofday(&RTMPStream::lastrec, 0);
|
||||
unsigned int i = 0;
|
||||
if (indata.size() < 1) return false; //need at least a byte
|
||||
|
||||
unsigned char chunktype = indata[i++ ];
|
||||
//read the chunkstream ID properly
|
||||
switch (chunktype & 0x3F){
|
||||
switch (chunktype & 0x3F) {
|
||||
case 0:
|
||||
if (indata.size() < 2) return false; //need at least 2 bytes to continue
|
||||
cs_id = indata[i++ ] + 64;
|
||||
|
@ -535,7 +537,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
|
||||
//process the rest of the header, for each chunk type
|
||||
headertype = chunktype & 0xC0;
|
||||
switch (headertype){
|
||||
switch (headertype) {
|
||||
case 0x00:
|
||||
if (indata.size() < i + 11) return false; //can't read whole header
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
|
@ -553,13 +555,13 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
break;
|
||||
case 0x40:
|
||||
if (indata.size() < i + 7) return false; //can't read whole header
|
||||
if (!allow_short){
|
||||
if (!allow_short) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = indata[i++ ] * 256 * 256;
|
||||
|
@ -571,13 +573,13 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
break;
|
||||
case 0x80:
|
||||
if (indata.size() < i + 3) return false; //can't read whole header
|
||||
if (!allow_short){
|
||||
if (!allow_short) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = prev.len;
|
||||
|
@ -586,7 +588,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0xC0:
|
||||
if (!allow_short){
|
||||
if (!allow_short) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = prev.timestamp;
|
||||
|
@ -597,18 +599,18 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
break;
|
||||
}
|
||||
//calculate chunk length, real length, and length left till complete
|
||||
if (len_left > 0){
|
||||
if (len_left > 0) {
|
||||
real_len = len_left;
|
||||
len_left -= real_len;
|
||||
}else{
|
||||
} else {
|
||||
real_len = len;
|
||||
}
|
||||
if (real_len > RTMPStream::chunk_rec_max){
|
||||
if (real_len > RTMPStream::chunk_rec_max) {
|
||||
len_left += real_len - RTMPStream::chunk_rec_max;
|
||||
real_len = RTMPStream::chunk_rec_max;
|
||||
}
|
||||
//read extended timestamp, if neccesary
|
||||
if (timestamp == 0x00ffffff){
|
||||
if (timestamp == 0x00ffffff) {
|
||||
if (indata.size() < i + 4) return false; //can't read whole header
|
||||
timestamp = indata[i++ ] * 256 * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256 * 256;
|
||||
|
@ -617,10 +619,10 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
}
|
||||
|
||||
//read data if length > 0, and allocate it
|
||||
if (real_len > 0){
|
||||
if (prev.len_left > 0){
|
||||
if (real_len > 0) {
|
||||
if (prev.len_left > 0) {
|
||||
data = prev.data;
|
||||
}else{
|
||||
} else {
|
||||
data = "";
|
||||
}
|
||||
if (indata.size() < i + real_len) return false; //can't read all data (yet)
|
||||
|
@ -628,12 +630,12 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
indata = indata.substr(i + real_len);
|
||||
lastrecv[cs_id] = *this;
|
||||
RTMPStream::rec_cnt += i + real_len;
|
||||
if (len_left == 0){
|
||||
if (len_left == 0) {
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return Parse(indata);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
data = "";
|
||||
indata = indata.substr(i + real_len);
|
||||
lastrecv[cs_id] = *this;
|
||||
|
@ -650,17 +652,17 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
|||
/// \param buffer The input to parse and update.
|
||||
/// \warning This function will destroy the current data in this chunk!
|
||||
/// \returns True if a whole chunk could be read, false otherwise.
|
||||
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
||||
gettimeofday( &RTMPStream::lastrec, 0);
|
||||
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer) {
|
||||
gettimeofday(&RTMPStream::lastrec, 0);
|
||||
unsigned int i = 0;
|
||||
if ( !buffer.available(3)){
|
||||
if (!buffer.available(3)) {
|
||||
return false;
|
||||
} //we want at least 3 bytes
|
||||
std::string indata = buffer.copy(3);
|
||||
|
||||
unsigned char chunktype = indata[i++ ];
|
||||
//read the chunkstream ID properly
|
||||
switch (chunktype & 0x3F){
|
||||
switch (chunktype & 0x3F) {
|
||||
case 0:
|
||||
cs_id = indata[i++ ] + 64;
|
||||
break;
|
||||
|
@ -677,9 +679,9 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
|
||||
//process the rest of the header, for each chunk type
|
||||
headertype = chunktype & 0xC0;
|
||||
switch (headertype){
|
||||
switch (headertype) {
|
||||
case 0x00:
|
||||
if ( !buffer.available(i + 11)){
|
||||
if (!buffer.available(i + 11)) {
|
||||
return false;
|
||||
} //can't read whole header
|
||||
indata = buffer.copy(i + 11);
|
||||
|
@ -697,17 +699,17 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id += indata[i++ ] * 256 * 256 * 256;
|
||||
break;
|
||||
case 0x40:
|
||||
if ( !buffer.available(i + 7)){
|
||||
if (!buffer.available(i + 7)) {
|
||||
return false;
|
||||
} //can't read whole header
|
||||
indata = buffer.copy(i + 7);
|
||||
if (prev.msg_type_id == 0){
|
||||
if (prev.msg_type_id == 0) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x40 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = indata[i++ ] * 256 * 256;
|
||||
|
@ -718,17 +720,17 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0x80:
|
||||
if ( !buffer.available(i + 3)){
|
||||
if (!buffer.available(i + 3)) {
|
||||
return false;
|
||||
} //can't read whole header
|
||||
indata = buffer.copy(i + 3);
|
||||
if (prev.msg_type_id == 0){
|
||||
if (prev.msg_type_id == 0) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0x80 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = indata[i++ ] * 256 * 256;
|
||||
timestamp += indata[i++ ] * 256;
|
||||
timestamp += indata[i++ ];
|
||||
if (timestamp != 0x00ffffff){
|
||||
if (timestamp != 0x00ffffff) {
|
||||
timestamp += prev.timestamp;
|
||||
}
|
||||
len = prev.len;
|
||||
|
@ -737,7 +739,7 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
msg_stream_id = prev.msg_stream_id;
|
||||
break;
|
||||
case 0xC0:
|
||||
if (prev.msg_type_id == 0){
|
||||
if (prev.msg_type_id == 0) {
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: Header type 0xC0 with no valid previous chunk!");
|
||||
}
|
||||
timestamp = prev.timestamp;
|
||||
|
@ -748,19 +750,19 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
break;
|
||||
}
|
||||
//calculate chunk length, real length, and length left till complete
|
||||
if (len_left > 0){
|
||||
if (len_left > 0) {
|
||||
real_len = len_left;
|
||||
len_left -= real_len;
|
||||
}else{
|
||||
} else {
|
||||
real_len = len;
|
||||
}
|
||||
if (real_len > RTMPStream::chunk_rec_max){
|
||||
if (real_len > RTMPStream::chunk_rec_max) {
|
||||
len_left += real_len - RTMPStream::chunk_rec_max;
|
||||
real_len = RTMPStream::chunk_rec_max;
|
||||
}
|
||||
//read extended timestamp, if neccesary
|
||||
if (timestamp == 0x00ffffff){
|
||||
if ( !buffer.available(i + 4)){
|
||||
if (timestamp == 0x00ffffff) {
|
||||
if (!buffer.available(i + 4)) {
|
||||
return false;
|
||||
} //can't read timestamp
|
||||
indata = buffer.copy(i + 4);
|
||||
|
@ -771,24 +773,24 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
}
|
||||
|
||||
//read data if length > 0, and allocate it
|
||||
if (real_len > 0){
|
||||
if ( !buffer.available(i + real_len)){
|
||||
if (real_len > 0) {
|
||||
if (!buffer.available(i + real_len)) {
|
||||
return false;
|
||||
} //can't read all data (yet)
|
||||
buffer.remove(i); //remove the header
|
||||
if (prev.len_left > 0){
|
||||
if (prev.len_left > 0) {
|
||||
data = prev.data + buffer.remove(real_len); //append the data and remove from buffer
|
||||
}else{
|
||||
} else {
|
||||
data = buffer.remove(real_len); //append the data and remove from buffer
|
||||
}
|
||||
lastrecv[cs_id] = *this;
|
||||
RTMPStream::rec_cnt += i + real_len;
|
||||
if (len_left == 0){
|
||||
if (len_left == 0) {
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
return Parse(buffer);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
buffer.remove(i); //remove the header
|
||||
data = "";
|
||||
indata = indata.substr(i + real_len);
|
||||
|
@ -802,10 +804,10 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
|
|||
/// After calling this function, don't forget to read and ignore 1536 extra bytes,
|
||||
/// these are the handshake response and not interesting for us because we don't do client
|
||||
/// verification.
|
||||
bool RTMPStream::doHandshake(){
|
||||
bool RTMPStream::doHandshake() {
|
||||
char Version;
|
||||
//Read C0
|
||||
if (handshake_in.size() < 1537){
|
||||
if (handshake_in.size() < 1537) {
|
||||
DEBUG_MSG(DLVL_FAIL, "Handshake wasn't filled properly (%lu/1537) - aborting!", handshake_in.size());
|
||||
return false;
|
||||
}
|
||||
|
@ -816,9 +818,9 @@ bool RTMPStream::doHandshake(){
|
|||
RTMPStream::rec_cnt += 1537;
|
||||
|
||||
//Build S1 Packet
|
||||
*((uint32_t*)Server) = 0; //time zero
|
||||
*(((uint32_t*)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4
|
||||
for (int i = 8; i < 3072; ++i){
|
||||
*((uint32_t *)Server) = 0; //time zero
|
||||
*(((uint32_t *)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4
|
||||
for (int i = 8; i < 3072; ++i) {
|
||||
Server[i] = FILLER_DATA[i % sizeof(FILLER_DATA)];
|
||||
} //"random" data
|
||||
|
||||
|
@ -828,7 +830,7 @@ bool RTMPStream::doHandshake(){
|
|||
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
|
||||
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
|
||||
|
||||
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted?"on":"off");
|
||||
DEBUG_MSG(DLVL_HIGH, "Handshake type is %hhi, encryption is %s", _validationScheme, encrypted ? "on" : "off");
|
||||
|
||||
//FIRST 1536 bytes from server response
|
||||
//compute DH key position
|
||||
|
@ -837,34 +839,34 @@ bool RTMPStream::doHandshake(){
|
|||
|
||||
//generate DH key
|
||||
DHWrapper dhWrapper(1024);
|
||||
if ( !dhWrapper.Initialize()){
|
||||
if (!dhWrapper.Initialize()) {
|
||||
return false;
|
||||
}
|
||||
if ( !dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)){
|
||||
if (!dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) {
|
||||
return false;
|
||||
}
|
||||
if ( !dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)){
|
||||
if (!dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (encrypted){
|
||||
if (encrypted) {
|
||||
uint8_t secretKey[128];
|
||||
if ( !dhWrapper.CopySharedKey(secretKey, sizeof(secretKey))){
|
||||
if (!dhWrapper.CopySharedKey(secretKey, sizeof(secretKey))) {
|
||||
return false;
|
||||
}
|
||||
RC4_KEY _pKeyIn;
|
||||
RC4_KEY _pKeyOut;
|
||||
InitRC4Encryption(secretKey, (uint8_t*) &Client[clientDHOffset], (uint8_t*) &Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
|
||||
InitRC4Encryption(secretKey, (uint8_t *) &Client[clientDHOffset], (uint8_t *) &Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
|
||||
uint8_t data[1536];
|
||||
RC4( &_pKeyIn, 1536, data, data);
|
||||
RC4( &_pKeyOut, 1536, data, data);
|
||||
RC4(&_pKeyIn, 1536, data, data);
|
||||
RC4(&_pKeyOut, 1536, data, data);
|
||||
}
|
||||
//generate the digest
|
||||
uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme);
|
||||
uint8_t *pTempBuffer = new uint8_t[1536 - 32];
|
||||
uint8_t * pTempBuffer = new uint8_t[1536 - 32];
|
||||
memcpy(pTempBuffer, Server, serverDigestOffset);
|
||||
memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1536 - serverDigestOffset - 32);
|
||||
uint8_t *pTempHash = new uint8_t[512];
|
||||
uint8_t * pTempHash = new uint8_t[512];
|
||||
HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash);
|
||||
memcpy(Server + serverDigestOffset, pTempHash, 32);
|
||||
delete[] pTempBuffer;
|
||||
|
@ -874,7 +876,7 @@ bool RTMPStream::doHandshake(){
|
|||
uint32_t keyChallengeIndex = GetDigestOffset(Client, _validationScheme);
|
||||
pTempHash = new uint8_t[512];
|
||||
HMACsha256(Client + keyChallengeIndex, 32, genuineFMSKey, 68, pTempHash);
|
||||
uint8_t *pLastHash = new uint8_t[512];
|
||||
uint8_t * pLastHash = new uint8_t[512];
|
||||
HMACsha256(Server + 1536, 1536 - 32, pTempHash, 32, pLastHash);
|
||||
memcpy(Server + 1536 * 2 - 32, pLastHash, 32);
|
||||
delete[] pTempHash;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue