From 471de8614f5725d95e8e4dd4c1c4a268eda31c04 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Tue, 24 Aug 2010 16:17:19 +0200 Subject: [PATCH] Implemented FMS encryption. Dat betekend werkend H264 en AAC, bitches! --- Connector_RTMP/Makefile | 2 +- Connector_RTMP/crypto.cpp | 506 +++++++++++++++++++++++++++++++++ Connector_RTMP/crypto.h | 45 +++ Connector_RTMP/handshake.cpp | 97 ++++++- Connector_RTMP/main.cpp | 11 +- Connector_RTMP/parsechunks.cpp | 13 +- Server/playh264.sh | 9 + 7 files changed, 671 insertions(+), 12 deletions(-) create mode 100644 Connector_RTMP/crypto.cpp create mode 100644 Connector_RTMP/crypto.h create mode 100755 Server/playh264.sh diff --git a/Connector_RTMP/Makefile b/Connector_RTMP/Makefile index 3dbacaef..622eb1fa 100644 --- a/Connector_RTMP/Makefile +++ b/Connector_RTMP/Makefile @@ -6,7 +6,7 @@ CCFLAGS = -Wall -Wextra -funsigned-char -g CC = $(CROSS)g++ LD = $(CROSS)ld AR = $(CROSS)ar -LIBS = +LIBS = -lssl -lcrypto .SUFFIXES: .cpp .PHONY: clean default default: $(OUT) diff --git a/Connector_RTMP/crypto.cpp b/Connector_RTMP/crypto.cpp new file mode 100644 index 00000000..9f62e5ce --- /dev/null +++ b/Connector_RTMP/crypto.cpp @@ -0,0 +1,506 @@ +#define STR(x) (((std::string)(x)).c_str()) + +#include "crypto.h" + +#define P768 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF" + +#define P1024 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \ +"FFFFFFFFFFFFFFFF" + +#define Q1024 \ +"7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \ +"948127044533E63A0105DF531D89CD9128A5043CC71A026E" \ +"F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \ +"F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \ +"F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \ +"FFFFFFFFFFFFFFFF" + +#define P1536 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ +"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ +"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ +"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" + +#define P2048 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ +"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ +"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ +"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ +"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ +"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ +"15728E5A8AACAA68FFFFFFFFFFFFFFFF" + +#define P3072 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ +"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ +"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ +"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ +"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ +"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ +"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ +"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ +"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ +"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ +"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ +"43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + +#define P4096 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ +"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ +"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ +"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ +"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ +"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ +"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ +"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ +"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ +"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ +"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ +"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ +"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ +"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ +"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ +"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ +"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \ +"FFFFFFFFFFFFFFFF" + +#define P6144 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ +"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ +"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ +"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ +"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ +"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ +"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ +"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ +"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ +"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ +"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ +"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ +"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ +"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ +"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ +"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ +"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \ +"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \ +"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \ +"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \ +"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \ +"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \ +"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \ +"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \ +"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \ +"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \ +"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \ +"12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF" + +#define P8192 \ +"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ +"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ +"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ +"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ +"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ +"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ +"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ +"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ +"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ +"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ +"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ +"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ +"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ +"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ +"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ +"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ +"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ +"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ +"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ +"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ +"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \ +"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \ +"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \ +"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \ +"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \ +"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \ +"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \ +"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \ +"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \ +"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \ +"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \ +"12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" \ +"38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" \ +"741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" \ +"3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" \ +"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" \ +"4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" \ +"062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" \ +"4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" \ +"B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" \ +"4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" \ +"9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" \ +"60C980DD98EDD3DFFFFFFFFFFFFFFFFF" + + +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, 0x65, 0x72, + 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001 + 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, + 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Player 001 + 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 + + +void replace(std::string &target, std::string search, std::string replacement) { + if (search == replacement) + return; + if (search == "") + return; + std::string::size_type i = std::string::npos; + while ((i = target.find(search)) != std::string::npos) { + target.replace(i, search.length(), replacement); + } +} + + +DHWrapper::DHWrapper(int32_t bitsCount) { + _bitsCount = bitsCount; + _pDH = NULL; + _pSharedKey = NULL; + _sharedKeyLength = 0; + _peerPublickey = NULL; +} + +DHWrapper::~DHWrapper() { + Cleanup(); +} + +bool DHWrapper::Initialize() { + Cleanup(); + + //1. Create the DH + _pDH = DH_new(); + if (_pDH == NULL) { + Cleanup(); + return false; + } + + //2. Create his internal p and g + _pDH->p = BN_new(); + if (_pDH->p == NULL) { + Cleanup(); + return false; + } + _pDH->g = BN_new(); + if (_pDH->g == NULL) { + Cleanup(); + return false; + } + + //3. initialize p, g and key length + if (BN_hex2bn(&_pDH->p, P1024) == 0) { + Cleanup(); + return false; + } + if (BN_set_word(_pDH->g, 2) != 1) { + Cleanup(); + return false; + } + + //4. Set the key length + _pDH->length = _bitsCount; + + //5. Generate private and public key + if (DH_generate_key(_pDH) != 1) { + Cleanup(); + return false; + } + + return true; +} + +bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength) { + if (_pDH == NULL) { + return false; + } + + return CopyKey(_pDH->pub_key, pDst, dstLength); +} + +bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength) { + if (_pDH == NULL) { + return false; + } + + return CopyKey(_pDH->priv_key, pDst, dstLength); +} + +bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length) { + if (_pDH == NULL) { + return false; + } + + if (_sharedKeyLength != 0 || _pSharedKey != NULL) { + return false; + } + + _sharedKeyLength = DH_size(_pDH); + if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024) { + return false; + } + _pSharedKey = new uint8_t[_sharedKeyLength]; + + _peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0); + if (_peerPublickey == NULL) { + return false; + } + + if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength) { + return false; + } + + return true; +} + +bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength) { + if (_pDH == NULL) { + return false; + } + + if (dstLength != _sharedKeyLength) { + return false; + } + + memcpy(pDst, _pSharedKey, _sharedKeyLength); + + return true; +} + +void DHWrapper::Cleanup() { + if (_pDH != NULL) { + if (_pDH->p != NULL) { + BN_free(_pDH->p); + _pDH->p = NULL; + } + if (_pDH->g != NULL) { + BN_free(_pDH->g); + _pDH->g = NULL; + } + DH_free(_pDH); + _pDH = NULL; + } + + if (_pSharedKey != NULL) { + delete[] _pSharedKey; + _pSharedKey = NULL; + } + _sharedKeyLength = 0; + + if (_peerPublickey != NULL) { + BN_free(_peerPublickey); + _peerPublickey = NULL; + } +} + +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)) { + return false; + } + + 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) { + 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); + + 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); + + RC4_set_key(rc4keyIn, 16, digest); +} + +std::string md5(std::string source, bool textResult) { + EVP_MD_CTX mdctx; + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; + + EVP_DigestInit(&mdctx, EVP_md5()); + EVP_DigestUpdate(&mdctx, STR(source), source.length()); + EVP_DigestFinal_ex(&mdctx, md_value, &md_len); + EVP_MD_CTX_cleanup(&mdctx); + + if (textResult) { + std::string result = ""; + char tmp[3]; + for (uint32_t i = 0; i < md_len; i++) { + sprintf(tmp, "%02x", md_value[i]); + result += tmp; + } + return result; + } else { + return std::string((char *) md_value, md_len); + } +} + +std::string b64(std::string source) { + return b64((uint8_t *) STR(source), source.size()); +} + +std::string b64(uint8_t *pBuffer, uint32_t length) { + BIO *bmem; + BIO *b64; + BUF_MEM *bptr; + + b64 = BIO_new(BIO_f_base64()); + bmem = BIO_new(BIO_s_mem()); + + b64 = BIO_push(b64, bmem); + BIO_write(b64, pBuffer, length); + std::string result = ""; + if (BIO_flush(b64) == 1) { + BIO_get_mem_ptr(b64, &bptr); + result = std::string(bptr->data, bptr->length); + } + + BIO_free_all(b64); + + + replace(result, "\n", ""); + replace(result, "\r", ""); + + return result; +} + +std::string unb64(std::string source) { + return unb64((uint8_t *)STR(source),source.length()); +} + +std::string unb64(uint8_t *pBuffer, uint32_t length){ + // create a memory buffer containing base64 encoded data + //BIO* bmem = BIO_new_mem_buf((void*) STR(source), source.length()); + BIO* bmem = BIO_new_mem_buf((void *)pBuffer, length); + + // push a Base64 filter so that reading from buffer decodes it + BIO *bioCmd = BIO_new(BIO_f_base64()); + // we don't want newlines + BIO_set_flags(bioCmd, BIO_FLAGS_BASE64_NO_NL); + bmem = BIO_push(bioCmd, bmem); + + char *pOut = new char[length]; + + int finalLen = BIO_read(bmem, (void*) pOut, length); + BIO_free_all(bmem); + std::string result(pOut, finalLen); + delete[] pOut; + return result; +} + +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(), NULL); + HMAC_Update(&ctx, (unsigned char *) pData, dataLength); + HMAC_Final(&ctx, (unsigned char *) pResult, &digestLen); + HMAC_CTX_cleanup(&ctx); +} + +uint32_t GetDigestOffset0(uint8_t *pBuffer) { + uint32_t offset = pBuffer[8] + pBuffer[9] + pBuffer[10] + pBuffer[11]; + return (offset % 728) + 12; +} +uint32_t GetDigestOffset1(uint8_t *pBuffer) { + uint32_t offset = pBuffer[772] + pBuffer[773] + pBuffer[774] + pBuffer[775]; + return (offset % 728) + 776; +} +uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){ + if (scheme == 0){return GetDigestOffset0(pBuffer);}else{return GetDigestOffset1(pBuffer);} +} +uint32_t GetDHOffset0(uint8_t *pBuffer) { + uint32_t offset = pBuffer[1532] + pBuffer[1533] + pBuffer[1534] + pBuffer[1535]; + return (offset % 632) + 772; +} +uint32_t GetDHOffset1(uint8_t *pBuffer) { + uint32_t offset = pBuffer[768] + pBuffer[769] + pBuffer[770] + pBuffer[771]; + return (offset % 632) + 8; +} +uint32_t GetDHOffset(uint8_t *pBuffer, uint8_t scheme){ + if (scheme == 0){return GetDHOffset0(pBuffer);}else{return GetDHOffset1(pBuffer);} +} + + +bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) { + 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 = (memcmp(pBuffer+clientDigestOffset, pTempHash, 32) == 0); + #ifdef DEBUG + fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed"); + #endif + delete[] pTempBuffer; + delete[] pTempHash; + return result; +} diff --git a/Connector_RTMP/crypto.h b/Connector_RTMP/crypto.h new file mode 100644 index 00000000..8d36188b --- /dev/null +++ b/Connector_RTMP/crypto.h @@ -0,0 +1,45 @@ +#ifndef _CRYPTO_H +#define _CRYPTO_H +#define DLLEXP + +#include +#include +#include +#include +#include +#include +#include +#include + +class DLLEXP DHWrapper { +private: + int32_t _bitsCount; + DH *_pDH; + uint8_t *_pSharedKey; + int32_t _sharedKeyLength; + 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); +private: + void Cleanup(); + bool CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength); +}; + + +DLLEXP void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, + RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut); +DLLEXP std::string md5(std::string source, bool textResult); +DLLEXP std::string b64(std::string source); +DLLEXP std::string b64(uint8_t *pBuffer, uint32_t length); +DLLEXP std::string unb64(std::string source); +DLLEXP std::string unb64(uint8_t *pBuffer, uint32_t length); + +#endif /* _CRYPTO_H */ + diff --git a/Connector_RTMP/handshake.cpp b/Connector_RTMP/handshake.cpp index adc81739..43143dc8 100644 --- a/Connector_RTMP/handshake.cpp +++ b/Connector_RTMP/handshake.cpp @@ -1,13 +1,15 @@ +#undef OLDHANDSHAKE //change to #define for old handshake method + +char versionstring[] = "PLSRTMPServer"; + +#ifdef OLDHANDSHAKE struct Handshake { char Time[4]; char Zero[4]; char Random[1528]; };//Handshake -char versionstring[] = "PLSRTMPServer"; - -void doHandshake(){ - srand(time(NULL)); +bool doHandshake(){ char Version; Handshake Client; Handshake Server; @@ -45,4 +47,91 @@ void doHandshake(){ fread(Client.Zero, 1, 4, stdin); fread(Client.Random, 1, 1528, stdin); rec_cnt+=1536; + return true; }//doHandshake + +#else + +#include "crypto.cpp" //cryptography for handshaking + +bool doHandshake(){ + char Version; + /** Read C0 **/ + fread(&Version, 1, 1, stdin); + uint8_t Client[1536]; + uint8_t Server[3072]; + fread(&Client, 1, 1536, stdin); + 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){Server[i] = versionstring[i%13];}//"random" data + + bool encrypted = (Version == 6); + #ifdef DEBUG + fprintf(stderr, "Handshake version is %hhi\n", Version); + #endif + uint8_t _validationScheme = 5; + if (ValidateClientScheme(Client, 0)) _validationScheme = 0; + if (ValidateClientScheme(Client, 1)) _validationScheme = 1; + + #ifdef DEBUG + fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off"); + #endif + + //**** FIRST 1536 bytes from server response ****// + //compute DH key position + uint32_t serverDHOffset = GetDHOffset(Server, _validationScheme); + uint32_t clientDHOffset = GetDHOffset(Client, _validationScheme); + + //generate DH key + DHWrapper dhWrapper(1024); + if (!dhWrapper.Initialize()) return false; + if (!dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) return false; + if (!dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) return false; + + if (encrypted) { + uint8_t secretKey[128]; + 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); + uint8_t data[1536]; + 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]; + memcpy(pTempBuffer, Server, serverDigestOffset); + memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1536 - serverDigestOffset - 32); + uint8_t *pTempHash = new uint8_t[512]; + HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash); + memcpy(Server + serverDigestOffset, pTempHash, 32); + delete[] pTempBuffer; + delete[] pTempHash; + + //**** SECOND 1536 bytes from server response ****// + 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]; + HMACsha256(Server + 1536, 1536 - 32, pTempHash, 32, pLastHash); + memcpy(Server + 1536 * 2 - 32, pLastHash, 32); + delete[] pTempHash; + delete[] pLastHash; + //***** DONE BUILDING THE RESPONSE ***// + /** Send response **/ + fwrite(&Version, 1, 1, stdout); + fwrite(&Server, 1, 3072, stdout); + snd_cnt+=3073; + /** Flush, necessary in order to work **/ + fflush(stdout); + /** Read and discard C2 **/ + fread(Client, 1, 1536, stdin); + rec_cnt+=1536; + return true; +} + +#endif diff --git a/Connector_RTMP/main.cpp b/Connector_RTMP/main.cpp index 1521111f..d46c0853 100644 --- a/Connector_RTMP/main.cpp +++ b/Connector_RTMP/main.cpp @@ -40,7 +40,16 @@ int main(){ #ifdef DEBUG fprintf(stderr, "Doing handshake...\n"); #endif - doHandshake(); + if (doHandshake()){ + #ifdef DEBUG + fprintf(stderr, "Handshake succcess!\n"); + #endif + }else{ + #ifdef DEBUG + fprintf(stderr, "Handshake fail!\n"); + #endif + return 0; + } #ifdef DEBUG fprintf(stderr, "Starting processing...\n"); #endif diff --git a/Connector_RTMP/parsechunks.cpp b/Connector_RTMP/parsechunks.cpp index c3de2954..f70ad2ea 100644 --- a/Connector_RTMP/parsechunks.cpp +++ b/Connector_RTMP/parsechunks.cpp @@ -205,11 +205,12 @@ void parseChunk(){ amfreply.getContentP(3)->addContent(AMFType("details", "PLS")); amfreply.getContentP(3)->addContent(AMFType("clientid", (double)1)); SendChunk(4, 20, 1, amfreply.Pack()); - amfreply = AMFType("container", (unsigned char)0xFF); - amfreply.addContent(AMFType("", "|RtmpSampleAccess"));//status reply - amfreply.addContent(AMFType("", (double)1, 0x01));//bool true - audioaccess - amfreply.addContent(AMFType("", (double)1, 0x01));//bool true - videoaccess - SendChunk(4, 20, next.msg_stream_id, amfreply.Pack()); +//No clue what this does. Most real servers send it, though... +// amfreply = AMFType("container", (unsigned char)0xFF); +// amfreply.addContent(AMFType("", "|RtmpSampleAccess"));//status reply +// amfreply.addContent(AMFType("", (double)1, 0x01));//bool true - audioaccess +// amfreply.addContent(AMFType("", (double)1, 0x01));//bool true - videoaccess +// SendChunk(4, 20, next.msg_stream_id, amfreply.Pack()); chunk_snd_max = 1024*1024; SendCTL(1, chunk_snd_max);//send chunk size max (msg 1) ready4data = true;//start sending video data! @@ -231,7 +232,7 @@ void parseChunk(){ break; default: #ifdef DEBUG - fprintf(stderr, "Unknown chunk received! Probably protocol corruption, stopping parsing of incoming data.\n", next.msg_type_id); + fprintf(stderr, "Unknown chunk received! Probably protocol corruption, stopping parsing of incoming data.\n"); #endif stopparsing = true; break; diff --git a/Server/playh264.sh b/Server/playh264.sh new file mode 100755 index 00000000..f38580a9 --- /dev/null +++ b/Server/playh264.sh @@ -0,0 +1,9 @@ +#!/bin/bash +#ffmpeg -y -i "$1" -acodec libfaac -ar 44100 -vcodec libx264 -b 1000k -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -i_qfactor 0.71 -keyint_min 25 -b_strategy 1 -g 150 -r 20 -f flv - 2> /dev/null | ./Server_PLS 500 + + + +#ffmpeg -y -i "$1" -ar 44100 -vcodec libx264 -b 1000k -g 150 -r 20 -f flv - | ./Server_PLS 500 + +ffmpeg -i "$1" -re -acodec aac -ar 44100 -vcodec libx264 -b 700k -vpre ultrafast -refs 1 -bf 0 -g 150 -f flv - 2> /dev/null | ./Server_PLS 500 +