2 * Copyright (C) 2008-2009 Andrej Stepanchuk
3 * Copyright (C) 2009-2010 Howard Chu
4 * Copyright (C) 2010 2a665470ced7adb7156fcef47f8199a6371c117b8a79e399a2771e0b36384090
6 * This file is part of librtmp.
8 * librtmp is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1,
11 * or (at your option) any later version.
13 * librtmp is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with librtmp see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/lgpl.html
25 /* This file is #included in rtmp.c, it is not meant to be compiled alone */
28 #include <polarssl/sha2.h>
29 #include <polarssl/arc4.h>
30 #ifndef SHA256_DIGEST_LENGTH
31 #define SHA256_DIGEST_LENGTH 32
33 #define HMAC_CTX sha2_context
34 #define HMAC_setup(ctx, key, len) sha2_hmac_starts(&ctx, (unsigned char *)key, len, 0)
35 #define HMAC_crunch(ctx, buf, len) sha2_hmac_update(&ctx, buf, len)
36 #define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; sha2_hmac_finish(&ctx, dig)
38 typedef arc4_context
* RC4_handle
;
39 #define RC4_alloc(h) *h = malloc(sizeof(arc4_context))
40 #define RC4_setkey(h,l,k) arc4_setup(h,k,l)
41 #define RC4_encrypt(h,l,d) arc4_crypt(h,l,(unsigned char *)d,(unsigned char *)d)
42 #define RC4_encrypt2(h,l,s,d) arc4_crypt(h,l,(unsigned char *)s,(unsigned char *)d)
43 #define RC4_free(h) free(h)
45 #elif defined(USE_GNUTLS)
46 #include <nettle/hmac.h>
47 #include <nettle/arcfour.h>
48 #ifndef SHA256_DIGEST_LENGTH
49 #define SHA256_DIGEST_LENGTH 32
52 #define HMAC_CTX struct hmac_sha256_ctx
53 #define HMAC_setup(ctx, key, len) hmac_sha256_set_key(&ctx, len, key)
54 #define HMAC_crunch(ctx, buf, len) hmac_sha256_update(&ctx, len, buf)
55 #define HMAC_finish(ctx, dig, dlen) dlen = SHA256_DIGEST_LENGTH; hmac_sha256_digest(&ctx, SHA256_DIGEST_LENGTH, dig)
56 #define HMAC_close(ctx)
58 typedef struct arcfour_ctx
* RC4_handle
;
59 #define RC4_alloc(h) *h = malloc(sizeof(struct arcfour_ctx))
60 #define RC4_setkey(h,l,k) arcfour_set_key(h, l, k)
61 #define RC4_encrypt(h,l,d) arcfour_crypt(h,l,(uint8_t *)d,(uint8_t *)d)
62 #define RC4_encrypt2(h,l,s,d) arcfour_crypt(h,l,(uint8_t *)d,(uint8_t *)s)
63 #define RC4_free(h) free(h)
65 #else /* USE_OPENSSL */
66 #include <openssl/sha.h>
67 #include <openssl/hmac.h>
68 #include <openssl/rc4.h>
69 #if OPENSSL_VERSION_NUMBER < 0x0090800 || !defined(SHA256_DIGEST_LENGTH)
70 #error Your OpenSSL is too old, need 0.9.8 or newer with SHA256
72 #if OPENSSL_VERSION_NUMBER >= 0x10100000
73 #define HMAC_CTX HMAC_CTX *
74 #define HMAC_setup(ctx, key, len) ctx = HMAC_CTX_new(); HMAC_Init_ex(ctx, key, len, EVP_sha256(), 0)
75 #define HMAC_crunch(ctx, buf, len) HMAC_Update(ctx, buf, len)
76 #define HMAC_finish(ctx, dig, dlen) HMAC_Final(ctx, dig, &dlen); HMAC_CTX_free(ctx)
78 #define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, key, len, EVP_sha256(), 0)
79 #define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, buf, len)
80 #define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, dig, &dlen); HMAC_CTX_cleanup(&ctx)
83 typedef RC4_KEY
* RC4_handle
;
84 #define RC4_alloc(h) *h = malloc(sizeof(RC4_KEY))
85 #define RC4_setkey(h,l,k) RC4_set_key(h,l,k)
86 #define RC4_encrypt(h,l,d) RC4(h,l,(uint8_t *)d,(uint8_t *)d)
87 #define RC4_encrypt2(h,l,s,d) RC4(h,l,(uint8_t *)s,(uint8_t *)d)
88 #define RC4_free(h) free(h)
95 static const uint8_t GenuineFMSKey
[] = {
96 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62,
97 0x65, 0x20, 0x46, 0x6c,
98 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65,
99 0x72, 0x76, 0x65, 0x72,
100 0x20, 0x30, 0x30, 0x31, /* Genuine Adobe Flash Media Server 001 */
102 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1,
103 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
104 0x93, 0xb8, 0xe6, 0x36,
105 0xcf, 0xeb, 0x31, 0xae
108 static const uint8_t GenuineFPKey
[] = {
109 0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20, 0x41, 0x64, 0x6F, 0x62,
110 0x65, 0x20, 0x46, 0x6C,
111 0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x30,
112 0x30, 0x31, /* Genuine Adobe Flash Player 001 */
114 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E,
115 0x7E, 0x57, 0x6E, 0xEC,
116 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB,
120 static void InitRC4Encryption
121 (uint8_t * secretKey
,
123 uint8_t * pubKeyOut
, RC4_handle
*rc4keyIn
, RC4_handle
*rc4keyOut
)
125 uint8_t digest
[SHA256_DIGEST_LENGTH
];
126 unsigned int digestLen
= 0;
130 RC4_alloc(rc4keyOut
);
132 HMAC_setup(ctx
, secretKey
, 128);
133 HMAC_crunch(ctx
, pubKeyIn
, 128);
134 HMAC_finish(ctx
, digest
, digestLen
);
136 RTMP_Log(RTMP_LOGDEBUG
, "RC4 Out Key: ");
137 RTMP_LogHex(RTMP_LOGDEBUG
, digest
, 16);
139 RC4_setkey(*rc4keyOut
, 16, digest
);
141 HMAC_setup(ctx
, secretKey
, 128);
142 HMAC_crunch(ctx
, pubKeyOut
, 128);
143 HMAC_finish(ctx
, digest
, digestLen
);
145 RTMP_Log(RTMP_LOGDEBUG
, "RC4 In Key: ");
146 RTMP_LogHex(RTMP_LOGDEBUG
, digest
, 16);
148 RC4_setkey(*rc4keyIn
, 16, digest
);
151 typedef unsigned int (getoff
)(uint8_t *buf
, unsigned int len
);
154 GetDHOffset2(uint8_t *handshake
, unsigned int len
)
156 unsigned int offset
= 0;
157 uint8_t *ptr
= handshake
+ 768;
160 assert(RTMP_SIG_SIZE
<= len
);
170 res
= (offset
% 632) + 8;
174 RTMP_Log(RTMP_LOGERROR
,
175 "%s: Couldn't calculate correct DH offset (got %d), exiting!",
183 GetDigestOffset2(uint8_t *handshake
, unsigned int len
)
185 unsigned int offset
= 0;
186 uint8_t *ptr
= handshake
+ 772;
197 res
= (offset
% 728) + 776;
201 RTMP_Log(RTMP_LOGERROR
,
202 "%s: Couldn't calculate correct digest offset (got %d), exiting",
210 GetDHOffset1(uint8_t *handshake
, unsigned int len
)
212 unsigned int offset
= 0;
213 uint8_t *ptr
= handshake
+ 1532;
216 assert(RTMP_SIG_SIZE
<= len
);
226 res
= (offset
% 632) + 772;
228 if (res
+ 128 > 1531)
230 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't calculate DH offset (got %d), exiting!",
239 GetDigestOffset1(uint8_t *handshake
, unsigned int len
)
241 unsigned int offset
= 0;
242 uint8_t *ptr
= handshake
+ 8;
255 res
= (offset
% 728) + 12;
259 RTMP_Log(RTMP_LOGERROR
,
260 "%s: Couldn't calculate digest offset (got %d), exiting!",
268 static getoff
*digoff
[] = {GetDigestOffset1
, GetDigestOffset2
};
269 static getoff
*dhoff
[] = {GetDHOffset1
, GetDHOffset2
};
272 HMACsha256(const uint8_t *message
, size_t messageLen
, const uint8_t *key
,
273 size_t keylen
, uint8_t *digest
)
275 unsigned int digestLen
;
278 HMAC_setup(ctx
, key
, keylen
);
279 HMAC_crunch(ctx
, message
, messageLen
);
280 HMAC_finish(ctx
, digest
, digestLen
);
282 assert(digestLen
== 32);
286 CalculateDigest(unsigned int digestPos
, uint8_t *handshakeMessage
,
287 const uint8_t *key
, size_t keyLen
, uint8_t *digest
)
289 const int messageLen
= RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
;
290 uint8_t message
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
];
292 memcpy(message
, handshakeMessage
, digestPos
);
293 memcpy(message
+ digestPos
,
294 &handshakeMessage
[digestPos
+ SHA256_DIGEST_LENGTH
],
295 messageLen
- digestPos
);
297 HMACsha256(message
, messageLen
, key
, keyLen
, digest
);
301 VerifyDigest(unsigned int digestPos
, uint8_t *handshakeMessage
, const uint8_t *key
,
304 uint8_t calcDigest
[SHA256_DIGEST_LENGTH
];
306 CalculateDigest(digestPos
, handshakeMessage
, key
, keyLen
, calcDigest
);
308 return memcmp(&handshakeMessage
[digestPos
], calcDigest
,
309 SHA256_DIGEST_LENGTH
) == 0;
314 * Type = [1 bytes] plain: 0x03, encrypted: 0x06, 0x08, 0x09
315 * -------------------------------------------------------------------- [1536 bytes]
316 * Uptime = [4 bytes] big endian unsigned number, uptime
317 * Version = [4 bytes] each byte represents a version number, e.g. 9.0.124.0
322 static const uint32_t rtmpe8_keys
[16][4] = {
323 {0xbff034b2, 0x11d9081f, 0xccdfb795, 0x748de732},
324 {0x086a5eb6, 0x1743090e, 0x6ef05ab8, 0xfe5a39e2},
325 {0x7b10956f, 0x76ce0521, 0x2388a73a, 0x440149a1},
326 {0xa943f317, 0xebf11bb2, 0xa691a5ee, 0x17f36339},
327 {0x7a30e00a, 0xb529e22c, 0xa087aea5, 0xc0cb79ac},
328 {0xbdce0c23, 0x2febdeff, 0x1cfaae16, 0x1123239d},
329 {0x55dd3f7b, 0x77e7e62e, 0x9bb8c499, 0xc9481ee4},
330 {0x407bb6b4, 0x71e89136, 0xa7aebf55, 0xca33b839},
331 {0xfcf6bdc3, 0xb63c3697, 0x7ce4f825, 0x04d959b2},
332 {0x28e091fd, 0x41954c4c, 0x7fb7db00, 0xe3a066f8},
333 {0x57845b76, 0x4f251b03, 0x46d45bcd, 0xa2c30d29},
334 {0x0acceef8, 0xda55b546, 0x03473452, 0x5863713b},
335 {0xb82075dc, 0xa75f1fee, 0xd84268e8, 0xa72a44cc},
336 {0x07cf6e9e, 0xa16d7b25, 0x9fa7ae6c, 0xd92f5629},
337 {0xfeb1eae4, 0x8c8c3ce1, 0x4e0064a7, 0x6a387c2a},
338 {0x893a9427, 0xcc3013a2, 0xf106385b, 0xa829f927}
341 /* RTMPE type 8 uses XTEA on the regular signature
342 * http://en.wikipedia.org/wiki/XTEA
344 static void rtmpe8_sig(uint8_t *in
, uint8_t *out
, int keyid
)
346 unsigned int i
, num_rounds
= 32;
347 uint32_t v0
, v1
, sum
=0, delta
=0x9E3779B9;
350 v0
= in
[0] | (in
[1] << 8) | (in
[2] << 16) | (in
[3] << 24);
351 v1
= in
[4] | (in
[5] << 8) | (in
[6] << 16) | (in
[7] << 24);
352 k
= rtmpe8_keys
[keyid
];
354 for (i
=0; i
< num_rounds
; i
++) {
355 v0
+= (((v1
<< 4) ^ (v1
>> 5)) + v1
) ^ (sum
+ k
[sum
& 3]);
357 v1
+= (((v0
<< 4) ^ (v0
>> 5)) + v0
) ^ (sum
+ k
[(sum
>>11) & 3]);
360 out
[0] = v0
; v0
>>= 8;
361 out
[1] = v0
; v0
>>= 8;
362 out
[2] = v0
; v0
>>= 8;
365 out
[4] = v1
; v1
>>= 8;
366 out
[5] = v1
; v1
>>= 8;
367 out
[6] = v1
; v1
>>= 8;
371 /* RTMPE type 9 uses Blowfish on the regular signature
372 * http://en.wikipedia.org/wiki/Blowfish_(cipher)
375 typedef struct bf_key
{
377 uint32_t p
[BF_ROUNDS
+2];
380 static const uint32_t bf_sinit
[][256] = {
383 { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
384 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
385 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
386 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
387 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
388 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
389 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
390 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
391 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
392 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
393 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
394 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
395 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
396 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
397 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
398 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
399 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
400 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
401 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
402 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
403 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
404 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
405 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
406 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
407 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
408 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
409 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
410 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
411 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
412 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
413 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
414 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
415 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
416 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
417 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
418 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
419 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
420 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
421 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
422 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
423 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
424 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
425 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, },
428 { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
429 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
430 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
431 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
432 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
433 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
434 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
435 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
436 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
437 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
438 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
439 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
440 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
441 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
442 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
443 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
444 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
445 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
446 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
447 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
448 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
449 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
450 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
451 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
452 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
453 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
454 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
455 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
456 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
457 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
458 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
459 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
460 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
461 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
462 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
463 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
464 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
465 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
466 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
467 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
468 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
469 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
470 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, },
473 { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
474 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
475 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
476 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
477 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
478 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
479 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
480 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
481 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
482 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
483 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
484 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
485 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
486 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
487 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
488 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
489 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
490 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
491 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
492 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
493 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
494 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
495 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
496 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
497 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
498 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
499 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
500 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
501 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
502 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
503 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
504 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
505 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
506 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
507 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
508 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
509 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
510 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
511 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
512 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
513 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
514 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
515 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, },
518 { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
519 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
520 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
521 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
522 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
523 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
524 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
525 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
526 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
527 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
528 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
529 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
530 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
531 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
532 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
533 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
534 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
535 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
536 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
537 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
538 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
539 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
540 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
541 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
542 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
543 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
544 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
545 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
546 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
547 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
548 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
549 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
550 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
551 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
552 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
553 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
554 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
555 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
556 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
557 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
558 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
559 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
560 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, },
563 static const uint32_t bf_pinit
[] = {
565 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
566 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
567 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
572 static const unsigned char rtmpe9_keys
[16][KEYBYTES
] = {
573 { 0x79, 0x34, 0x77, 0x4c, 0x67, 0xd1, 0x38, 0x3a, 0xdf, 0xb3, 0x56, 0xbe,
574 0x8b, 0x7b, 0xd0, 0x24, 0x38, 0xe0, 0x73, 0x58, 0x41, 0x5d, 0x69, 0x67, },
575 { 0x46, 0xf6, 0xb4, 0xcc, 0x01, 0x93, 0xe3, 0xa1, 0x9e, 0x7d, 0x3c, 0x65,
576 0x55, 0x86, 0xfd, 0x09, 0x8f, 0xf7, 0xb3, 0xc4, 0x6f, 0x41, 0xca, 0x5c, },
577 { 0x1a, 0xe7, 0xe2, 0xf3, 0xf9, 0x14, 0x79, 0x94, 0xc0, 0xd3, 0x97, 0x43,
578 0x08, 0x7b, 0xb3, 0x84, 0x43, 0x2f, 0x9d, 0x84, 0x3f, 0x21, 0x01, 0x9b, },
579 { 0xd3, 0xe3, 0x54, 0xb0, 0xf7, 0x1d, 0xf6, 0x2b, 0x5a, 0x43, 0x4d, 0x04,
580 0x83, 0x64, 0x3e, 0x0d, 0x59, 0x2f, 0x61, 0xcb, 0xb1, 0x6a, 0x59, 0x0d, },
581 { 0xc8, 0xc1, 0xe9, 0xb8, 0x16, 0x56, 0x99, 0x21, 0x7b, 0x5b, 0x36, 0xb7,
582 0xb5, 0x9b, 0xdf, 0x06, 0x49, 0x2c, 0x97, 0xf5, 0x95, 0x48, 0x85, 0x7e, },
583 { 0xeb, 0xe5, 0xe6, 0x2e, 0xa4, 0xba, 0xd4, 0x2c, 0xf2, 0x16, 0xe0, 0x8f,
584 0x66, 0x23, 0xa9, 0x43, 0x41, 0xce, 0x38, 0x14, 0x84, 0x95, 0x00, 0x53, },
585 { 0x66, 0xdb, 0x90, 0xf0, 0x3b, 0x4f, 0xf5, 0x6f, 0xe4, 0x9c, 0x20, 0x89,
586 0x35, 0x5e, 0xd2, 0xb2, 0xc3, 0x9e, 0x9f, 0x7f, 0x63, 0xb2, 0x28, 0x81, },
587 { 0xbb, 0x20, 0xac, 0xed, 0x2a, 0x04, 0x6a, 0x19, 0x94, 0x98, 0x9b, 0xc8,
588 0xff, 0xcd, 0x93, 0xef, 0xc6, 0x0d, 0x56, 0xa7, 0xeb, 0x13, 0xd9, 0x30, },
589 { 0xbc, 0xf2, 0x43, 0x82, 0x09, 0x40, 0x8a, 0x87, 0x25, 0x43, 0x6d, 0xe6,
590 0xbb, 0xa4, 0xb9, 0x44, 0x58, 0x3f, 0x21, 0x7c, 0x99, 0xbb, 0x3f, 0x24, },
591 { 0xec, 0x1a, 0xaa, 0xcd, 0xce, 0xbd, 0x53, 0x11, 0xd2, 0xfb, 0x83, 0xb6,
592 0xc3, 0xba, 0xab, 0x4f, 0x62, 0x79, 0xe8, 0x65, 0xa9, 0x92, 0x28, 0x76, },
593 { 0xc6, 0x0c, 0x30, 0x03, 0x91, 0x18, 0x2d, 0x7b, 0x79, 0xda, 0xe1, 0xd5,
594 0x64, 0x77, 0x9a, 0x12, 0xc5, 0xb1, 0xd7, 0x91, 0x4f, 0x96, 0x4c, 0xa3, },
595 { 0xd7, 0x7c, 0x2a, 0xbf, 0xa6, 0xe7, 0x85, 0x7c, 0x45, 0xad, 0xff, 0x12,
596 0x94, 0xd8, 0xde, 0xa4, 0x5c, 0x3d, 0x79, 0xa4, 0x44, 0x02, 0x5d, 0x22, },
597 { 0x16, 0x19, 0x0d, 0x81, 0x6a, 0x4c, 0xc7, 0xf8, 0xb8, 0xf9, 0x4e, 0xcd,
598 0x2c, 0x9e, 0x90, 0x84, 0xb2, 0x08, 0x25, 0x60, 0xe1, 0x1e, 0xae, 0x18, },
599 { 0xe9, 0x7c, 0x58, 0x26, 0x1b, 0x51, 0x9e, 0x49, 0x82, 0x60, 0x61, 0xfc,
600 0xa0, 0xa0, 0x1b, 0xcd, 0xf5, 0x05, 0xd6, 0xa6, 0x6d, 0x07, 0x88, 0xa3, },
601 { 0x2b, 0x97, 0x11, 0x8b, 0xd9, 0x4e, 0xd9, 0xdf, 0x20, 0xe3, 0x9c, 0x10,
602 0xe6, 0xa1, 0x35, 0x21, 0x11, 0xf9, 0x13, 0x0d, 0x0b, 0x24, 0x65, 0xb2, },
603 { 0x53, 0x6a, 0x4c, 0x54, 0xac, 0x8b, 0x9b, 0xb8, 0x97, 0x29, 0xfc, 0x60,
604 0x2c, 0x5b, 0x3a, 0x85, 0x68, 0xb5, 0xaa, 0x6a, 0x44, 0xcd, 0x3f, 0xa7, },
607 #define BF_ENC(X,S) \
608 (((S[0][X>>24] + S[1][X>>16 & 0xff]) ^ S[2][(X>>8) & 0xff]) + S[3][X & 0xff])
610 static void bf_enc(uint32_t *x
, bf_key
*key
)
620 for (i
= 0; i
< BF_ROUNDS
; ++i
) {
622 Xr
^= BF_ENC(Xl
,key
->s
);
629 Xl
^= key
->p
[BF_ROUNDS
];
630 Xr
^= key
->p
[BF_ROUNDS
+ 1];
636 static void bf_setkey(const unsigned char *kp
, int keybytes
, bf_key
*key
)
644 memcpy(key
->p
, bf_pinit
, sizeof(key
->p
));
645 memcpy(key
->s
, bf_sinit
, sizeof(key
->s
));
648 for (i
= 0; i
< BF_ROUNDS
+ 2; ++i
) {
650 for (k
= 0; k
< 4; ++k
) {
651 data
= (data
<< 8) | kp
[j
];
663 for (i
= 0; i
< BF_ROUNDS
+ 2; i
+= 2) {
667 key
->p
[i
+ 1] = d
[1];
670 for (i
= 0; i
< 4; ++i
) {
671 for (j
= 0; j
< 256; j
+= 2) {
676 key
->s
[i
][j
+ 1] = d
[1];
681 static void rtmpe9_sig(uint8_t *in
, uint8_t *out
, int keyid
)
686 bf_setkey(rtmpe9_keys
[keyid
], KEYBYTES
, &key
);
688 /* input is little-endian */
689 d
[0] = in
[0] | (in
[1] << 8) | (in
[2] << 16) | (in
[3] << 24);
690 d
[1] = in
[4] | (in
[5] << 8) | (in
[6] << 16) | (in
[7] << 24);
692 out
[0] = d
[0] & 0xff;
693 out
[1] = (d
[0] >> 8) & 0xff;
694 out
[2] = (d
[0] >> 16) & 0xff;
695 out
[3] = (d
[0] >> 24) & 0xff;
696 out
[4] = d
[1] & 0xff;
697 out
[5] = (d
[1] >> 8) & 0xff;
698 out
[6] = (d
[1] >> 16) & 0xff;
699 out
[7] = (d
[1] >> 24) & 0xff;
703 HandShake(RTMP
* r
, int FP9HandShake
)
707 int digestPosClient
= 0;
708 int encrypted
= r
->Link
.protocol
& RTMP_FEATURE_ENC
;
710 RC4_handle keyIn
= 0;
711 RC4_handle keyOut
= 0;
716 uint8_t clientbuf
[RTMP_SIG_SIZE
+ 4], *clientsig
=clientbuf
+4;
717 uint8_t serversig
[RTMP_SIG_SIZE
], client2
[RTMP_SIG_SIZE
], *reply
;
719 getoff
*getdh
= NULL
, *getdig
= NULL
;
721 if (encrypted
|| r
->Link
.SWFSize
)
724 FP9HandShake
= FALSE
;
726 r
->Link
.rc4keyIn
= r
->Link
.rc4keyOut
= 0;
730 clientsig
[-1] = 0x06; /* 0x08 is RTMPE as well */
734 clientsig
[-1] = 0x03;
736 uptime
= htonl(RTMP_GetTime());
737 memcpy(clientsig
, &uptime
, 4);
741 /* set version to at least 9.0.115.0 */
755 RTMP_Log(RTMP_LOGDEBUG
, "%s: Client type: %02X", __FUNCTION__
, clientsig
[-1]);
756 getdig
= digoff
[offalg
];
757 getdh
= dhoff
[offalg
];
761 memset(&clientsig
[4], 0, 4);
764 /* generate random data */
766 memset(clientsig
+8, 0, RTMP_SIG_SIZE
-8);
768 ip
= (int32_t *)(clientsig
+8);
769 for (i
= 2; i
< RTMP_SIG_SIZE
/4; i
++)
773 /* set handshake digest */
778 /* generate Diffie-Hellmann parameters */
779 r
->Link
.dh
= DHInit(1024);
782 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't initialize Diffie-Hellmann!",
787 dhposClient
= getdh(clientsig
, RTMP_SIG_SIZE
);
788 RTMP_Log(RTMP_LOGDEBUG
, "%s: DH pubkey position: %d", __FUNCTION__
, dhposClient
);
790 if (!DHGenerateKey(r
->Link
.dh
))
792 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't generate Diffie-Hellmann public key!",
797 if (!DHGetPublicKey(r
->Link
.dh
, &clientsig
[dhposClient
], 128))
799 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't write public key!", __FUNCTION__
);
804 digestPosClient
= getdig(clientsig
, RTMP_SIG_SIZE
); /* reuse this value in verification */
805 RTMP_Log(RTMP_LOGDEBUG
, "%s: Client digest offset: %d", __FUNCTION__
,
808 CalculateDigest(digestPosClient
, clientsig
, GenuineFPKey
, 30,
809 &clientsig
[digestPosClient
]);
811 RTMP_Log(RTMP_LOGDEBUG
, "%s: Initial client digest: ", __FUNCTION__
);
812 RTMP_LogHex(RTMP_LOGDEBUG
, clientsig
+ digestPosClient
,
813 SHA256_DIGEST_LENGTH
);
817 RTMP_Log(RTMP_LOGDEBUG
, "Clientsig: ");
818 RTMP_LogHex(RTMP_LOGDEBUG
, clientsig
, RTMP_SIG_SIZE
);
821 if (!WriteN(r
, (char *)clientsig
-1, RTMP_SIG_SIZE
+ 1))
824 if (ReadN(r
, (char *)&type
, 1) != 1) /* 0x03 or 0x06 */
827 RTMP_Log(RTMP_LOGDEBUG
, "%s: Type Answer : %02X", __FUNCTION__
, type
);
829 if (type
!= clientsig
[-1])
830 RTMP_Log(RTMP_LOGWARNING
, "%s: Type mismatch: client sent %d, server answered %d",
831 __FUNCTION__
, clientsig
[-1], type
);
833 if (ReadN(r
, (char *)serversig
, RTMP_SIG_SIZE
) != RTMP_SIG_SIZE
)
836 /* decode server response */
837 memcpy(&uptime
, serversig
, 4);
838 uptime
= ntohl(uptime
);
840 RTMP_Log(RTMP_LOGDEBUG
, "%s: Server Uptime : %d", __FUNCTION__
, uptime
);
841 RTMP_Log(RTMP_LOGDEBUG
, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__
, serversig
[4],
842 serversig
[5], serversig
[6], serversig
[7]);
844 if (FP9HandShake
&& type
== 3 && !serversig
[4])
845 FP9HandShake
= FALSE
;
848 RTMP_Log(RTMP_LOGDEBUG
, "Server signature:");
849 RTMP_LogHex(RTMP_LOGDEBUG
, serversig
, RTMP_SIG_SIZE
);
854 uint8_t digestResp
[SHA256_DIGEST_LENGTH
];
855 uint8_t *signatureResp
= NULL
;
857 /* we have to use this signature now to find the correct algorithms for getting the digest and DH positions */
858 int digestPosServer
= getdig(serversig
, RTMP_SIG_SIZE
);
860 if (!VerifyDigest(digestPosServer
, serversig
, GenuineFMSKey
, 36))
862 RTMP_Log(RTMP_LOGWARNING
, "Trying different position for server digest!");
864 getdig
= digoff
[offalg
];
865 getdh
= dhoff
[offalg
];
866 digestPosServer
= getdig(serversig
, RTMP_SIG_SIZE
);
868 if (!VerifyDigest(digestPosServer
, serversig
, GenuineFMSKey
, 36))
870 RTMP_Log(RTMP_LOGERROR
, "Couldn't verify the server digest"); /* continuing anyway will probably fail */
875 /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
878 const char swfVerify
[] = { 0x01, 0x01 };
879 char *vend
= r
->Link
.SWFVerificationResponse
+sizeof(r
->Link
.SWFVerificationResponse
);
881 memcpy(r
->Link
.SWFVerificationResponse
, swfVerify
, 2);
882 AMF_EncodeInt32(&r
->Link
.SWFVerificationResponse
[2], vend
, r
->Link
.SWFSize
);
883 AMF_EncodeInt32(&r
->Link
.SWFVerificationResponse
[6], vend
, r
->Link
.SWFSize
);
884 HMACsha256(r
->Link
.SWFHash
, SHA256_DIGEST_LENGTH
,
885 &serversig
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
],
886 SHA256_DIGEST_LENGTH
,
887 (uint8_t *)&r
->Link
.SWFVerificationResponse
[10]);
890 /* do Diffie-Hellmann Key exchange for encrypted RTMP */
893 /* compute secret key */
894 uint8_t secretKey
[128] = { 0 };
895 int len
, dhposServer
;
897 dhposServer
= getdh(serversig
, RTMP_SIG_SIZE
);
898 RTMP_Log(RTMP_LOGDEBUG
, "%s: Server DH public key offset: %d", __FUNCTION__
,
900 len
= DHComputeSharedSecretKey(r
->Link
.dh
, &serversig
[dhposServer
],
904 RTMP_Log(RTMP_LOGDEBUG
, "%s: Wrong secret key position!", __FUNCTION__
);
908 RTMP_Log(RTMP_LOGDEBUG
, "%s: Secret key: ", __FUNCTION__
);
909 RTMP_LogHex(RTMP_LOGDEBUG
, secretKey
, 128);
911 InitRC4Encryption(secretKey
,
912 (uint8_t *) & serversig
[dhposServer
],
913 (uint8_t *) & clientsig
[dhposClient
],
920 memset(reply
, 0xff, RTMP_SIG_SIZE
);
922 ip
= (int32_t *)reply
;
923 for (i
= 0; i
< RTMP_SIG_SIZE
/4; i
++)
926 /* calculate response now */
927 signatureResp
= reply
+RTMP_SIG_SIZE
-SHA256_DIGEST_LENGTH
;
929 HMACsha256(&serversig
[digestPosServer
], SHA256_DIGEST_LENGTH
,
930 GenuineFPKey
, sizeof(GenuineFPKey
), digestResp
);
931 HMACsha256(reply
, RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
, digestResp
,
932 SHA256_DIGEST_LENGTH
, signatureResp
);
934 /* some info output */
935 RTMP_Log(RTMP_LOGDEBUG
,
936 "%s: Calculated digest key from secure key and server digest: ",
938 RTMP_LogHex(RTMP_LOGDEBUG
, digestResp
, SHA256_DIGEST_LENGTH
);
943 uint8_t *dptr
= digestResp
;
944 uint8_t *sig
= signatureResp
;
945 /* encrypt signatureResp */
946 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
947 rtmpe8_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
951 uint8_t *dptr
= digestResp
;
952 uint8_t *sig
= signatureResp
;
953 /* encrypt signatureResp */
954 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
955 rtmpe9_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
958 RTMP_Log(RTMP_LOGDEBUG
, "%s: Client signature calculated:", __FUNCTION__
);
959 RTMP_LogHex(RTMP_LOGDEBUG
, signatureResp
, SHA256_DIGEST_LENGTH
);
965 uptime
= htonl(RTMP_GetTime());
966 memcpy(reply
+4, &uptime
, 4);
971 RTMP_Log(RTMP_LOGDEBUG
, "%s: Sending handshake response: ",
973 RTMP_LogHex(RTMP_LOGDEBUG
, reply
, RTMP_SIG_SIZE
);
975 if (!WriteN(r
, (char *)reply
, RTMP_SIG_SIZE
))
978 /* 2nd part of handshake */
979 if (ReadN(r
, (char *)serversig
, RTMP_SIG_SIZE
) != RTMP_SIG_SIZE
)
983 RTMP_Log(RTMP_LOGDEBUG
, "%s: 2nd handshake: ", __FUNCTION__
);
984 RTMP_LogHex(RTMP_LOGDEBUG
, serversig
, RTMP_SIG_SIZE
);
989 uint8_t signature
[SHA256_DIGEST_LENGTH
];
990 uint8_t digest
[SHA256_DIGEST_LENGTH
];
992 if (serversig
[4] == 0 && serversig
[5] == 0 && serversig
[6] == 0
993 && serversig
[7] == 0)
995 RTMP_Log(RTMP_LOGDEBUG
,
996 "%s: Wait, did the server just refuse signed authentication?",
999 RTMP_Log(RTMP_LOGDEBUG
, "%s: Server sent signature:", __FUNCTION__
);
1000 RTMP_LogHex(RTMP_LOGDEBUG
, &serversig
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
],
1001 SHA256_DIGEST_LENGTH
);
1003 /* verify server response */
1004 HMACsha256(&clientsig
[digestPosClient
], SHA256_DIGEST_LENGTH
,
1005 GenuineFMSKey
, sizeof(GenuineFMSKey
), digest
);
1006 HMACsha256(serversig
, RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
, digest
,
1007 SHA256_DIGEST_LENGTH
, signature
);
1009 /* show some information */
1010 RTMP_Log(RTMP_LOGDEBUG
, "%s: Digest key: ", __FUNCTION__
);
1011 RTMP_LogHex(RTMP_LOGDEBUG
, digest
, SHA256_DIGEST_LENGTH
);
1016 uint8_t *dptr
= digest
;
1017 uint8_t *sig
= signature
;
1018 /* encrypt signature */
1019 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
1020 rtmpe8_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
1024 uint8_t *dptr
= digest
;
1025 uint8_t *sig
= signature
;
1026 /* encrypt signatureResp */
1027 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
1028 rtmpe9_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
1031 RTMP_Log(RTMP_LOGDEBUG
, "%s: Signature calculated:", __FUNCTION__
);
1032 RTMP_LogHex(RTMP_LOGDEBUG
, signature
, SHA256_DIGEST_LENGTH
);
1034 (signature
, &serversig
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
],
1035 SHA256_DIGEST_LENGTH
) != 0)
1037 RTMP_Log(RTMP_LOGWARNING
, "%s: Server not genuine Adobe!", __FUNCTION__
);
1042 RTMP_Log(RTMP_LOGDEBUG
, "%s: Genuine Adobe Flash Media Server", __FUNCTION__
);
1047 char buff
[RTMP_SIG_SIZE
];
1048 /* set keys for encryption from now on */
1049 r
->Link
.rc4keyIn
= keyIn
;
1050 r
->Link
.rc4keyOut
= keyOut
;
1053 /* update the keystreams */
1054 if (r
->Link
.rc4keyIn
)
1056 RC4_encrypt(r
->Link
.rc4keyIn
, RTMP_SIG_SIZE
, (uint8_t *) buff
);
1059 if (r
->Link
.rc4keyOut
)
1061 RC4_encrypt(r
->Link
.rc4keyOut
, RTMP_SIG_SIZE
, (uint8_t *) buff
);
1067 if (memcmp(serversig
, clientsig
, RTMP_SIG_SIZE
) != 0)
1069 RTMP_Log(RTMP_LOGWARNING
, "%s: client signature does not match!",
1074 RTMP_Log(RTMP_LOGDEBUG
, "%s: Handshaking finished....", __FUNCTION__
);
1079 SHandShake(RTMP
* r
)
1082 int dhposServer
= 0;
1083 int digestPosServer
= 0;
1084 RC4_handle keyIn
= 0;
1085 RC4_handle keyOut
= 0;
1086 int FP9HandShake
= FALSE
;
1090 uint8_t clientsig
[RTMP_SIG_SIZE
];
1091 uint8_t serverbuf
[RTMP_SIG_SIZE
+ 4], *serversig
= serverbuf
+4;
1094 getoff
*getdh
= NULL
, *getdig
= NULL
;
1096 if (ReadN(r
, (char *)&type
, 1) != 1) /* 0x03 or 0x06 */
1099 if (ReadN(r
, (char *)clientsig
, RTMP_SIG_SIZE
) != RTMP_SIG_SIZE
)
1102 RTMP_Log(RTMP_LOGDEBUG
, "%s: Type Requested : %02X", __FUNCTION__
, type
);
1103 RTMP_LogHex(RTMP_LOGDEBUG2
, clientsig
, RTMP_SIG_SIZE
);
1109 else if (type
== 6 || type
== 8)
1113 FP9HandShake
= TRUE
;
1114 r
->Link
.protocol
|= RTMP_FEATURE_ENC
;
1115 /* use FP10 if client is capable */
1116 if (clientsig
[4] == 128)
1121 RTMP_Log(RTMP_LOGERROR
, "%s: Unknown version %02x",
1122 __FUNCTION__
, type
);
1126 if (!FP9HandShake
&& clientsig
[4])
1127 FP9HandShake
= TRUE
;
1129 serversig
[-1] = type
;
1131 r
->Link
.rc4keyIn
= r
->Link
.rc4keyOut
= 0;
1133 uptime
= htonl(RTMP_GetTime());
1134 memcpy(serversig
, &uptime
, 4);
1138 /* Server version */
1144 getdig
= digoff
[offalg
];
1145 getdh
= dhoff
[offalg
];
1149 memset(&serversig
[4], 0, 4);
1152 /* generate random data */
1154 memset(serversig
+8, 0, RTMP_SIG_SIZE
-8);
1156 ip
= (int32_t *)(serversig
+8);
1157 for (i
= 2; i
< RTMP_SIG_SIZE
/4; i
++)
1161 /* set handshake digest */
1166 /* generate Diffie-Hellmann parameters */
1167 r
->Link
.dh
= DHInit(1024);
1170 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't initialize Diffie-Hellmann!",
1175 dhposServer
= getdh(serversig
, RTMP_SIG_SIZE
);
1176 RTMP_Log(RTMP_LOGDEBUG
, "%s: DH pubkey position: %d", __FUNCTION__
, dhposServer
);
1178 if (!DHGenerateKey(r
->Link
.dh
))
1180 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't generate Diffie-Hellmann public key!",
1186 (r
->Link
.dh
, (uint8_t *) &serversig
[dhposServer
], 128))
1188 RTMP_Log(RTMP_LOGERROR
, "%s: Couldn't write public key!", __FUNCTION__
);
1193 digestPosServer
= getdig(serversig
, RTMP_SIG_SIZE
); /* reuse this value in verification */
1194 RTMP_Log(RTMP_LOGDEBUG
, "%s: Server digest offset: %d", __FUNCTION__
,
1197 CalculateDigest(digestPosServer
, serversig
, GenuineFMSKey
, 36,
1198 &serversig
[digestPosServer
]);
1200 RTMP_Log(RTMP_LOGDEBUG
, "%s: Initial server digest: ", __FUNCTION__
);
1201 RTMP_LogHex(RTMP_LOGDEBUG
, serversig
+ digestPosServer
,
1202 SHA256_DIGEST_LENGTH
);
1205 RTMP_Log(RTMP_LOGDEBUG2
, "Serversig: ");
1206 RTMP_LogHex(RTMP_LOGDEBUG2
, serversig
, RTMP_SIG_SIZE
);
1208 if (!WriteN(r
, (char *)serversig
-1, RTMP_SIG_SIZE
+ 1))
1211 /* decode client response */
1212 memcpy(&uptime
, clientsig
, 4);
1213 uptime
= ntohl(uptime
);
1215 RTMP_Log(RTMP_LOGDEBUG
, "%s: Client Uptime : %d", __FUNCTION__
, uptime
);
1216 RTMP_Log(RTMP_LOGDEBUG
, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__
, clientsig
[4],
1217 clientsig
[5], clientsig
[6], clientsig
[7]);
1221 uint8_t digestResp
[SHA256_DIGEST_LENGTH
];
1222 uint8_t *signatureResp
= NULL
;
1224 /* we have to use this signature now to find the correct algorithms for getting the digest and DH positions */
1225 int digestPosClient
= getdig(clientsig
, RTMP_SIG_SIZE
);
1227 if (!VerifyDigest(digestPosClient
, clientsig
, GenuineFPKey
, 30))
1229 RTMP_Log(RTMP_LOGWARNING
, "Trying different position for client digest!");
1231 getdig
= digoff
[offalg
];
1232 getdh
= dhoff
[offalg
];
1234 digestPosClient
= getdig(clientsig
, RTMP_SIG_SIZE
);
1236 if (!VerifyDigest(digestPosClient
, clientsig
, GenuineFPKey
, 30))
1238 RTMP_Log(RTMP_LOGERROR
, "Couldn't verify the client digest"); /* continuing anyway will probably fail */
1243 /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
1244 if (r
->Link
.SWFSize
)
1246 const char swfVerify
[] = { 0x01, 0x01 };
1247 char *vend
= r
->Link
.SWFVerificationResponse
+sizeof(r
->Link
.SWFVerificationResponse
);
1249 memcpy(r
->Link
.SWFVerificationResponse
, swfVerify
, 2);
1250 AMF_EncodeInt32(&r
->Link
.SWFVerificationResponse
[2], vend
, r
->Link
.SWFSize
);
1251 AMF_EncodeInt32(&r
->Link
.SWFVerificationResponse
[6], vend
, r
->Link
.SWFSize
);
1252 HMACsha256(r
->Link
.SWFHash
, SHA256_DIGEST_LENGTH
,
1253 &serversig
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
],
1254 SHA256_DIGEST_LENGTH
,
1255 (uint8_t *)&r
->Link
.SWFVerificationResponse
[10]);
1258 /* do Diffie-Hellmann Key exchange for encrypted RTMP */
1261 int dhposClient
, len
;
1262 /* compute secret key */
1263 uint8_t secretKey
[128] = { 0 };
1265 dhposClient
= getdh(clientsig
, RTMP_SIG_SIZE
);
1266 RTMP_Log(RTMP_LOGDEBUG
, "%s: Client DH public key offset: %d", __FUNCTION__
,
1269 DHComputeSharedSecretKey(r
->Link
.dh
,
1270 (uint8_t *) &clientsig
[dhposClient
], 128,
1274 RTMP_Log(RTMP_LOGDEBUG
, "%s: Wrong secret key position!", __FUNCTION__
);
1278 RTMP_Log(RTMP_LOGDEBUG
, "%s: Secret key: ", __FUNCTION__
);
1279 RTMP_LogHex(RTMP_LOGDEBUG
, secretKey
, 128);
1281 InitRC4Encryption(secretKey
,
1282 (uint8_t *) &clientsig
[dhposClient
],
1283 (uint8_t *) &serversig
[dhposServer
],
1288 /* calculate response now */
1289 signatureResp
= clientsig
+RTMP_SIG_SIZE
-SHA256_DIGEST_LENGTH
;
1291 HMACsha256(&clientsig
[digestPosClient
], SHA256_DIGEST_LENGTH
,
1292 GenuineFMSKey
, sizeof(GenuineFMSKey
), digestResp
);
1293 HMACsha256(clientsig
, RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
, digestResp
,
1294 SHA256_DIGEST_LENGTH
, signatureResp
);
1298 uint8_t *dptr
= digestResp
;
1299 uint8_t *sig
= signatureResp
;
1300 /* encrypt signatureResp */
1301 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
1302 rtmpe8_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
1306 uint8_t *dptr
= digestResp
;
1307 uint8_t *sig
= signatureResp
;
1308 /* encrypt signatureResp */
1309 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
1310 rtmpe9_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
1314 /* some info output */
1315 RTMP_Log(RTMP_LOGDEBUG
,
1316 "%s: Calculated digest key from secure key and server digest: ",
1318 RTMP_LogHex(RTMP_LOGDEBUG
, digestResp
, SHA256_DIGEST_LENGTH
);
1320 RTMP_Log(RTMP_LOGDEBUG
, "%s: Server signature calculated:", __FUNCTION__
);
1321 RTMP_LogHex(RTMP_LOGDEBUG
, signatureResp
, SHA256_DIGEST_LENGTH
);
1326 uptime
= htonl(RTMP_GetTime());
1327 memcpy(clientsig
+4, &uptime
, 4);
1331 RTMP_Log(RTMP_LOGDEBUG2
, "%s: Sending handshake response: ",
1333 RTMP_LogHex(RTMP_LOGDEBUG2
, clientsig
, RTMP_SIG_SIZE
);
1335 if (!WriteN(r
, (char *)clientsig
, RTMP_SIG_SIZE
))
1338 /* 2nd part of handshake */
1339 if (ReadN(r
, (char *)clientsig
, RTMP_SIG_SIZE
) != RTMP_SIG_SIZE
)
1342 RTMP_Log(RTMP_LOGDEBUG2
, "%s: 2nd handshake: ", __FUNCTION__
);
1343 RTMP_LogHex(RTMP_LOGDEBUG2
, clientsig
, RTMP_SIG_SIZE
);
1347 uint8_t signature
[SHA256_DIGEST_LENGTH
];
1348 uint8_t digest
[SHA256_DIGEST_LENGTH
];
1350 RTMP_Log(RTMP_LOGDEBUG
, "%s: Client sent signature:", __FUNCTION__
);
1351 RTMP_LogHex(RTMP_LOGDEBUG
, &clientsig
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
],
1352 SHA256_DIGEST_LENGTH
);
1354 /* verify client response */
1355 HMACsha256(&serversig
[digestPosServer
], SHA256_DIGEST_LENGTH
,
1356 GenuineFPKey
, sizeof(GenuineFPKey
), digest
);
1357 HMACsha256(clientsig
, RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
, digest
,
1358 SHA256_DIGEST_LENGTH
, signature
);
1362 uint8_t *dptr
= digest
;
1363 uint8_t *sig
= signature
;
1364 /* encrypt signatureResp */
1365 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
1366 rtmpe8_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
1370 uint8_t *dptr
= digest
;
1371 uint8_t *sig
= signature
;
1372 /* encrypt signatureResp */
1373 for (i
=0; i
<SHA256_DIGEST_LENGTH
; i
+=8)
1374 rtmpe9_sig(sig
+i
, sig
+i
, dptr
[i
] % 15);
1378 /* show some information */
1379 RTMP_Log(RTMP_LOGDEBUG
, "%s: Digest key: ", __FUNCTION__
);
1380 RTMP_LogHex(RTMP_LOGDEBUG
, digest
, SHA256_DIGEST_LENGTH
);
1382 RTMP_Log(RTMP_LOGDEBUG
, "%s: Signature calculated:", __FUNCTION__
);
1383 RTMP_LogHex(RTMP_LOGDEBUG
, signature
, SHA256_DIGEST_LENGTH
);
1385 (signature
, &clientsig
[RTMP_SIG_SIZE
- SHA256_DIGEST_LENGTH
],
1386 SHA256_DIGEST_LENGTH
) != 0)
1388 RTMP_Log(RTMP_LOGWARNING
, "%s: Client not genuine Adobe!", __FUNCTION__
);
1393 RTMP_Log(RTMP_LOGDEBUG
, "%s: Genuine Adobe Flash Player", __FUNCTION__
);
1398 char buff
[RTMP_SIG_SIZE
];
1399 /* set keys for encryption from now on */
1400 r
->Link
.rc4keyIn
= keyIn
;
1401 r
->Link
.rc4keyOut
= keyOut
;
1403 /* update the keystreams */
1404 if (r
->Link
.rc4keyIn
)
1406 RC4_encrypt(r
->Link
.rc4keyIn
, RTMP_SIG_SIZE
, (uint8_t *) buff
);
1409 if (r
->Link
.rc4keyOut
)
1411 RC4_encrypt(r
->Link
.rc4keyOut
, RTMP_SIG_SIZE
, (uint8_t *) buff
);
1417 if (memcmp(serversig
, clientsig
, RTMP_SIG_SIZE
) != 0)
1419 RTMP_Log(RTMP_LOGWARNING
, "%s: client signature does not match!",
1424 RTMP_Log(RTMP_LOGDEBUG
, "%s: Handshaking finished....", __FUNCTION__
);