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 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; }