bool InboundRTMPProtocol::ValidateClientScheme(IOBuffer &inputBuffer, uint8_t scheme) { uint8_t *pBuffer = GETIBPOINTER(inputBuffer); uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme); 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]; HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); bool result = true; for (uint32_t i = 0; i < 32; i++) { if (pBuffer[clientDigestOffset + i] != pTempHash[i]) { result = false; break; } } delete[] pTempBuffer; delete[] pTempHash; return result; }
bool ValidateClientScheme(uint8_t *pBuffer, uint8_t scheme){ uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme); uint8_t pTempBuffer[1536 - 32]; memcpy(pTempBuffer, pBuffer, clientDigestOffset); memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32); char pTempHash[32]; Secure::hmac_sha256bin((char *)pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0); MEDIUM_MSG("Client scheme validation %hhi %s", scheme, result ? "success" : "failed"); return result; }
bool OutboundRTMPProtocol::VerifyServer(IOBuffer & inputBuffer) { uint8_t *pBuffer = GETIBPOINTER(inputBuffer) + 1; uint32_t serverDigestOffset = GetDigestOffset(pBuffer, _usedScheme); DEBUG_HANDSHAKE("CLIENT: Validate: 1. serverDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8, serverDigestOffset, _usedScheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, pBuffer, serverDigestOffset); memcpy(pTempBuffer + serverDigestOffset, pBuffer + serverDigestOffset + 32, 1536 - serverDigestOffset - 32); uint8_t * pDigest = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pDigest); DEBUG_HANDSHAKE("CLIENT: Validate: 2. computed serverDigest %s", STR(hex(pDigest, 32))); DEBUG_HANDSHAKE("CLIENT: Validate: 3. found serverDigest %s", STR(hex(pBuffer + serverDigestOffset, 32))); int result = memcmp(pDigest, pBuffer + serverDigestOffset, 32); delete[] pTempBuffer; delete[] pDigest; if (result != 0) { FATAL("Server not verified"); return false; } pBuffer = pBuffer + 1536; uint8_t * pChallange = new uint8_t[512]; HMACsha256(_pClientDigest, 32, genuineFMSKey, 68, pChallange); pDigest = new uint8_t[512]; HMACsha256(pBuffer, 1536 - 32, pChallange, 32, pDigest); DEBUG_HANDSHAKE("CLIENT: Validate: 4. computed serverChallange: %s", STR(hex(pDigest, 32))); DEBUG_HANDSHAKE("CLIENT: Validate: 5. found serverChallange: %s", STR(hex(pBuffer + 1536 - 32, 32))); result = memcmp(pDigest, pBuffer + 1536 - 32, 32); delete[] pChallange; delete[] pDigest; if (result != 0) { FATAL("Server not verified"); return false; } return true; }
bool OutboundRTMPProtocol::PerformHandshakeStage2(IOBuffer &inputBuffer, bool encrypted) { if (encrypted || _pProtocolHandler->ValidateHandshake()) { if (!VerifyServer(inputBuffer)) { FATAL("Unable to verify server"); return false; } } uint8_t *pInputBuffer = GETIBPOINTER(inputBuffer) + 1; uint32_t serverDHOffset = GetDHOffset(pInputBuffer, _usedScheme); if (_pDHWrapper == NULL) { FATAL("dh wrapper not initialized"); return false; } DEBUG_HANDSHAKE("CLIENT: 1. serverDHOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; serverPublicKey: %s", serverDHOffset, _usedScheme, STR(hex(pInputBuffer + serverDHOffset, 128))); if (!_pDHWrapper->CreateSharedKey(pInputBuffer + serverDHOffset, 128)) { FATAL("Unable to create shared key"); return false; } uint8_t secretKey[128]; if (!_pDHWrapper->CopySharedKey(secretKey, sizeof (secretKey))) { FATAL("Unable to compute shared"); return false; } DEBUG_HANDSHAKE("CLIENT: 2. secretKey: %s", STR(hex(secretKey, 128))); if (encrypted) { _pKeyIn = new RC4_KEY; _pKeyOut = new RC4_KEY; InitRC4Encryption( secretKey, (uint8_t*) & pInputBuffer[serverDHOffset], _pClientPublicKey, _pKeyIn, _pKeyOut); uint8_t data[1536]; RC4(_pKeyIn, 1536, data, data); RC4(_pKeyOut, 1536, data, data); } delete _pDHWrapper; _pDHWrapper = NULL; uint32_t serverDigestOffset = GetDigestOffset(pInputBuffer, _usedScheme); DEBUG_HANDSHAKE("CLIENT: 3. serverDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8, serverDigestOffset, _usedScheme); if (_pOutputBuffer == NULL) { _pOutputBuffer = new uint8_t[1536]; } else { delete[] _pOutputBuffer; _pOutputBuffer = new uint8_t[1536]; } for (uint32_t i = 0; i < 1536; i++) { _pOutputBuffer[i] = rand() % 256; } uint8_t * pChallangeKey = new uint8_t[512]; HMACsha256(pInputBuffer + serverDigestOffset, 32, genuineFPKey, 62, pChallangeKey); uint8_t * pDigest = new uint8_t[512]; HMACsha256(_pOutputBuffer, 1536 - 32, pChallangeKey, 32, pDigest); memcpy(_pOutputBuffer + 1536 - 32, pDigest, 32); DEBUG_HANDSHAKE("CLIENT: 4. clientChallange: %s", STR(hex(pDigest, 32))); delete[] pChallangeKey; delete[] pDigest; _outputBuffer.ReadFromBuffer(_pOutputBuffer, 1536); delete[] _pOutputBuffer; _pOutputBuffer = NULL; _rtmpState = RTMP_STATE_DONE; return true; }
bool OutboundRTMPProtocol::PerformHandshakeStage1(bool encrypted) { _outputBuffer.ReadFromByte(encrypted ? 6 : 3); if (_pOutputBuffer == NULL) { _pOutputBuffer = new uint8_t[1536]; } else { delete[] _pOutputBuffer; _pOutputBuffer = new uint8_t[1536]; } for (uint32_t i = 0; i < 1536; i++) { _pOutputBuffer[i] = rand() % 256; } EHTONLP(_pOutputBuffer, 0); _pOutputBuffer[4] = 9; _pOutputBuffer[5] = 0; _pOutputBuffer[6] = 124; _pOutputBuffer[7] = 2; uint32_t clientDHOffset = GetDHOffset(_pOutputBuffer, _usedScheme); _pDHWrapper = new DHWrapper(1024); if (!_pDHWrapper->Initialize()) { FATAL("Unable to initialize DH wrapper"); return false; } if (!_pDHWrapper->CopyPublicKey(_pOutputBuffer + clientDHOffset, 128)) { FATAL("Couldn't write public key!"); return false; } DEBUG_HANDSHAKE("CLIENT: 1. clientDHOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; clientPublicKey: %s", clientDHOffset, _usedScheme, STR(hex(_pOutputBuffer + clientDHOffset, 128))); _pClientPublicKey = new uint8_t[128]; memcpy(_pClientPublicKey, _pOutputBuffer + clientDHOffset, 128); uint32_t clientDigestOffset = GetDigestOffset(_pOutputBuffer, _usedScheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, _pOutputBuffer, clientDigestOffset); memcpy(pTempBuffer + clientDigestOffset, _pOutputBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32); uint8_t *pTempHash = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); memcpy(_pOutputBuffer + clientDigestOffset, pTempHash, 32); DEBUG_HANDSHAKE("CLIENT: 2. clientDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; clientDigest: %s", clientDigestOffset, _usedScheme, STR(hex(_pOutputBuffer + clientDigestOffset, 32))); _pClientDigest = new uint8_t[32]; memcpy(_pClientDigest, pTempHash, 32); delete[] pTempBuffer; delete[] pTempHash; _outputBuffer.ReadFromBuffer(_pOutputBuffer, 1536); delete[] _pOutputBuffer; _pOutputBuffer = NULL; if (_pFarProtocol != NULL) { if (!_pFarProtocol->EnqueueForOutbound()) { FATAL("Unable to signal output data"); return false; } } _rtmpState = RTMP_STATE_CLIENT_REQUEST_SENT; return true; }
bool InboundRTMPProtocol::PerformComplexHandshake(IOBuffer &buffer, bool encrypted) { //get the buffers uint8_t *pInputBuffer = GETIBPOINTER(buffer); if (_pOutputBuffer == NULL) { _pOutputBuffer = new uint8_t[3072]; } else { delete[] _pOutputBuffer; _pOutputBuffer = new uint8_t[3072]; } //timestamp EHTONLP(_pOutputBuffer, (uint32_t) time(NULL)); //version EHTONLP(_pOutputBuffer + 4, (uint32_t) 0x00000000); //generate random data for (uint32_t i = 8; i < 3072; i++) { _pOutputBuffer[i] = rand() % 256; } for (uint32_t i = 0; i < 10; i++) { uint32_t index = rand() % (3072 - HTTP_HEADERS_SERVER_US_LEN); memcpy(_pOutputBuffer + index, HTTP_HEADERS_SERVER_US, HTTP_HEADERS_SERVER_US_LEN); } //**** FIRST 1536 bytes from server response ****// //compute DH key position uint32_t serverDHOffset = GetDHOffset(_pOutputBuffer, _handshakeScheme); uint32_t clientDHOffset = GetDHOffset(pInputBuffer, _handshakeScheme); //generate DH key DHWrapper dhWrapper(1024); if (!dhWrapper.Initialize()) { FATAL("Unable to initialize DH wrapper"); return false; } if (!dhWrapper.CreateSharedKey(pInputBuffer + clientDHOffset, 128)) { FATAL("Unable to create shared key"); return false; } if (!dhWrapper.CopyPublicKey(_pOutputBuffer + serverDHOffset, 128)) { FATAL("Couldn't write public key!"); return false; } if (encrypted) { uint8_t secretKey[128]; if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) { FATAL("Unable to copy shared key"); return false; } _pKeyIn = new RC4_KEY; _pKeyOut = new RC4_KEY; InitRC4Encryption( secretKey, (uint8_t*) & pInputBuffer[clientDHOffset], (uint8_t*) & _pOutputBuffer[serverDHOffset], _pKeyIn, _pKeyOut); //bring the keys to correct cursor uint8_t data[1536]; RC4(_pKeyIn, 1536, data, data); RC4(_pKeyOut, 1536, data, data); } //generate the digest uint32_t serverDigestOffset = GetDigestOffset(_pOutputBuffer, _handshakeScheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, _pOutputBuffer, serverDigestOffset); memcpy(pTempBuffer + serverDigestOffset, _pOutputBuffer + serverDigestOffset + 32, 1536 - serverDigestOffset - 32); uint8_t *pTempHash = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash); //put the digest in place memcpy(_pOutputBuffer + serverDigestOffset, pTempHash, 32); //cleanup delete[] pTempBuffer; delete[] pTempHash; //**** SECOND 1536 bytes from server response ****// //Compute the chalange index from the initial client request uint32_t keyChallengeIndex = GetDigestOffset(pInputBuffer, _handshakeScheme); //compute the key pTempHash = new uint8_t[512]; HMACsha256(pInputBuffer + keyChallengeIndex, //pData 32, //dataLength BaseRTMPProtocol::genuineFMSKey, //key 68, //keyLength pTempHash //pResult ); //generate the hash uint8_t *pLastHash = new uint8_t[512]; HMACsha256(_pOutputBuffer + 1536, //pData 1536 - 32, //dataLength pTempHash, //key 32, //keyLength pLastHash //pResult ); //put the hash where it belongs memcpy(_pOutputBuffer + 1536 * 2 - 32, pLastHash, 32); //cleanup delete[] pTempHash; delete[] pLastHash; //***** DONE BUILDING THE RESPONSE ***// //wire the response if (encrypted) _outputBuffer.ReadFromByte(6); else _outputBuffer.ReadFromByte(3); _outputBuffer.ReadFromBuffer(_pOutputBuffer, 3072); //final cleanup delete[] _pOutputBuffer; _pOutputBuffer = NULL; if (!buffer.IgnoreAll()) { FATAL("Unable to ignore input buffer"); return false; } //signal outbound data if (!EnqueueForOutbound()) { FATAL("Unable to signal outbound data"); return false; } //move to the next stage in the handshake _rtmpState = RTMP_STATE_SERVER_RESPONSE_SENT; return true; }