More for input buffer checks
[rtmpdump.git] / librtmp / handshake.h
blob0438486df9817ab92857d6688cda837918ba8df0
1 /*
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 */
27 #ifdef USE_POLARSSL
28 #include <polarssl/sha2.h>
29 #include <polarssl/arc4.h>
30 #ifndef SHA256_DIGEST_LENGTH
31 #define SHA256_DIGEST_LENGTH 32
32 #endif
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
50 #endif
51 #undef HMAC_CTX
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
71 #endif
72 #define HMAC_setup(ctx, key, len) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, key, len, EVP_sha256(), 0)
73 #define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, buf, len)
74 #define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, dig, &dlen); HMAC_CTX_cleanup(&ctx)
76 typedef RC4_KEY * RC4_handle;
77 #define RC4_alloc(h) *h = malloc(sizeof(RC4_KEY))
78 #define RC4_setkey(h,l,k) RC4_set_key(h,l,k)
79 #define RC4_encrypt(h,l,d) RC4(h,l,(uint8_t *)d,(uint8_t *)d)
80 #define RC4_encrypt2(h,l,s,d) RC4(h,l,(uint8_t *)s,(uint8_t *)d)
81 #define RC4_free(h) free(h)
82 #endif
84 #define FP10
86 #include "dh.h"
88 static const uint8_t GenuineFMSKey[] = {
89 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62,
90 0x65, 0x20, 0x46, 0x6c,
91 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65,
92 0x72, 0x76, 0x65, 0x72,
93 0x20, 0x30, 0x30, 0x31, /* Genuine Adobe Flash Media Server 001 */
95 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1,
96 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
97 0x93, 0xb8, 0xe6, 0x36,
98 0xcf, 0xeb, 0x31, 0xae
99 }; /* 68 */
101 static const uint8_t GenuineFPKey[] = {
102 0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20, 0x41, 0x64, 0x6F, 0x62,
103 0x65, 0x20, 0x46, 0x6C,
104 0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x30,
105 0x30, 0x31, /* Genuine Adobe Flash Player 001 */
106 0xF0, 0xEE,
107 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E,
108 0x7E, 0x57, 0x6E, 0xEC,
109 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB,
110 0x31, 0xAE
111 }; /* 62 */
113 static void InitRC4Encryption
114 (uint8_t * secretKey,
115 uint8_t * pubKeyIn,
116 uint8_t * pubKeyOut, RC4_handle *rc4keyIn, RC4_handle *rc4keyOut)
118 uint8_t digest[SHA256_DIGEST_LENGTH];
119 unsigned int digestLen = 0;
120 HMAC_CTX ctx;
122 RC4_alloc(rc4keyIn);
123 RC4_alloc(rc4keyOut);
125 HMAC_setup(ctx, secretKey, 128);
126 HMAC_crunch(ctx, pubKeyIn, 128);
127 HMAC_finish(ctx, digest, digestLen);
129 RTMP_Log(RTMP_LOGDEBUG, "RC4 Out Key: ");
130 RTMP_LogHex(RTMP_LOGDEBUG, digest, 16);
132 RC4_setkey(*rc4keyOut, 16, digest);
134 HMAC_setup(ctx, secretKey, 128);
135 HMAC_crunch(ctx, pubKeyOut, 128);
136 HMAC_finish(ctx, digest, digestLen);
138 RTMP_Log(RTMP_LOGDEBUG, "RC4 In Key: ");
139 RTMP_LogHex(RTMP_LOGDEBUG, digest, 16);
141 RC4_setkey(*rc4keyIn, 16, digest);
144 typedef unsigned int (getoff)(uint8_t *buf, unsigned int len);
146 static unsigned int
147 GetDHOffset2(uint8_t *handshake, unsigned int len)
149 unsigned int offset = 0;
150 uint8_t *ptr = handshake + 768;
151 unsigned int res;
153 assert(RTMP_SIG_SIZE <= len);
155 offset += (*ptr);
156 ptr++;
157 offset += (*ptr);
158 ptr++;
159 offset += (*ptr);
160 ptr++;
161 offset += (*ptr);
163 res = (offset % 632) + 8;
165 if (res + 128 > 767)
167 RTMP_Log(RTMP_LOGERROR,
168 "%s: Couldn't calculate correct DH offset (got %d), exiting!",
169 __FUNCTION__, res);
170 exit(1);
172 return res;
175 static unsigned int
176 GetDigestOffset2(uint8_t *handshake, unsigned int len)
178 unsigned int offset = 0;
179 uint8_t *ptr = handshake + 772;
180 unsigned int res;
182 offset += (*ptr);
183 ptr++;
184 offset += (*ptr);
185 ptr++;
186 offset += (*ptr);
187 ptr++;
188 offset += (*ptr);
190 res = (offset % 728) + 776;
192 if (res + 32 > 1535)
194 RTMP_Log(RTMP_LOGERROR,
195 "%s: Couldn't calculate correct digest offset (got %d), exiting",
196 __FUNCTION__, res);
197 exit(1);
199 return res;
202 static unsigned int
203 GetDHOffset1(uint8_t *handshake, unsigned int len)
205 unsigned int offset = 0;
206 uint8_t *ptr = handshake + 1532;
207 unsigned int res;
209 assert(RTMP_SIG_SIZE <= len);
211 offset += (*ptr);
212 ptr++;
213 offset += (*ptr);
214 ptr++;
215 offset += (*ptr);
216 ptr++;
217 offset += (*ptr);
219 res = (offset % 632) + 772;
221 if (res + 128 > 1531)
223 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't calculate DH offset (got %d), exiting!",
224 __FUNCTION__, res);
225 exit(1);
228 return res;
231 static unsigned int
232 GetDigestOffset1(uint8_t *handshake, unsigned int len)
234 unsigned int offset = 0;
235 uint8_t *ptr = handshake + 8;
236 unsigned int res;
238 assert(12 <= len);
240 offset += (*ptr);
241 ptr++;
242 offset += (*ptr);
243 ptr++;
244 offset += (*ptr);
245 ptr++;
246 offset += (*ptr);
248 res = (offset % 728) + 12;
250 if (res + 32 > 771)
252 RTMP_Log(RTMP_LOGERROR,
253 "%s: Couldn't calculate digest offset (got %d), exiting!",
254 __FUNCTION__, res);
255 exit(1);
258 return res;
261 static getoff *digoff[] = {GetDigestOffset1, GetDigestOffset2};
262 static getoff *dhoff[] = {GetDHOffset1, GetDHOffset2};
264 static void
265 HMACsha256(const uint8_t *message, size_t messageLen, const uint8_t *key,
266 size_t keylen, uint8_t *digest)
268 unsigned int digestLen;
269 HMAC_CTX ctx;
271 HMAC_setup(ctx, key, keylen);
272 HMAC_crunch(ctx, message, messageLen);
273 HMAC_finish(ctx, digest, digestLen);
275 assert(digestLen == 32);
278 static void
279 CalculateDigest(unsigned int digestPos, uint8_t *handshakeMessage,
280 const uint8_t *key, size_t keyLen, uint8_t *digest)
282 const int messageLen = RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH;
283 uint8_t message[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH];
285 memcpy(message, handshakeMessage, digestPos);
286 memcpy(message + digestPos,
287 &handshakeMessage[digestPos + SHA256_DIGEST_LENGTH],
288 messageLen - digestPos);
290 HMACsha256(message, messageLen, key, keyLen, digest);
293 static int
294 VerifyDigest(unsigned int digestPos, uint8_t *handshakeMessage, const uint8_t *key,
295 size_t keyLen)
297 uint8_t calcDigest[SHA256_DIGEST_LENGTH];
299 CalculateDigest(digestPos, handshakeMessage, key, keyLen, calcDigest);
301 return memcmp(&handshakeMessage[digestPos], calcDigest,
302 SHA256_DIGEST_LENGTH) == 0;
305 /* handshake
307 * Type = [1 bytes] plain: 0x03, encrypted: 0x06, 0x08, 0x09
308 * -------------------------------------------------------------------- [1536 bytes]
309 * Uptime = [4 bytes] big endian unsigned number, uptime
310 * Version = [4 bytes] each byte represents a version number, e.g. 9.0.124.0
311 * ...
315 static const uint32_t rtmpe8_keys[16][4] = {
316 {0xbff034b2, 0x11d9081f, 0xccdfb795, 0x748de732},
317 {0x086a5eb6, 0x1743090e, 0x6ef05ab8, 0xfe5a39e2},
318 {0x7b10956f, 0x76ce0521, 0x2388a73a, 0x440149a1},
319 {0xa943f317, 0xebf11bb2, 0xa691a5ee, 0x17f36339},
320 {0x7a30e00a, 0xb529e22c, 0xa087aea5, 0xc0cb79ac},
321 {0xbdce0c23, 0x2febdeff, 0x1cfaae16, 0x1123239d},
322 {0x55dd3f7b, 0x77e7e62e, 0x9bb8c499, 0xc9481ee4},
323 {0x407bb6b4, 0x71e89136, 0xa7aebf55, 0xca33b839},
324 {0xfcf6bdc3, 0xb63c3697, 0x7ce4f825, 0x04d959b2},
325 {0x28e091fd, 0x41954c4c, 0x7fb7db00, 0xe3a066f8},
326 {0x57845b76, 0x4f251b03, 0x46d45bcd, 0xa2c30d29},
327 {0x0acceef8, 0xda55b546, 0x03473452, 0x5863713b},
328 {0xb82075dc, 0xa75f1fee, 0xd84268e8, 0xa72a44cc},
329 {0x07cf6e9e, 0xa16d7b25, 0x9fa7ae6c, 0xd92f5629},
330 {0xfeb1eae4, 0x8c8c3ce1, 0x4e0064a7, 0x6a387c2a},
331 {0x893a9427, 0xcc3013a2, 0xf106385b, 0xa829f927}
334 /* RTMPE type 8 uses XTEA on the regular signature
335 * http://en.wikipedia.org/wiki/XTEA
337 static void rtmpe8_sig(uint8_t *in, uint8_t *out, int keyid)
339 unsigned int i, num_rounds = 32;
340 uint32_t v0, v1, sum=0, delta=0x9E3779B9;
341 uint32_t const *k;
343 v0 = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24);
344 v1 = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24);
345 k = rtmpe8_keys[keyid];
347 for (i=0; i < num_rounds; i++) {
348 v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
349 sum += delta;
350 v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
353 out[0] = v0; v0 >>= 8;
354 out[1] = v0; v0 >>= 8;
355 out[2] = v0; v0 >>= 8;
356 out[3] = v0;
358 out[4] = v1; v1 >>= 8;
359 out[5] = v1; v1 >>= 8;
360 out[6] = v1; v1 >>= 8;
361 out[7] = v1;
364 /* RTMPE type 9 uses Blowfish on the regular signature
365 * http://en.wikipedia.org/wiki/Blowfish_(cipher)
367 #define BF_ROUNDS 16
368 typedef struct bf_key {
369 uint32_t s[4][256];
370 uint32_t p[BF_ROUNDS+2];
371 } bf_key;
373 static const uint32_t bf_sinit[][256] = {
375 /* S-Box 0 */
376 { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
377 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
378 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
379 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
380 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
381 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
382 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
383 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
384 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
385 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
386 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
387 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
388 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
389 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
390 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
391 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
392 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
393 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
394 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
395 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
396 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
397 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
398 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
399 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
400 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
401 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
402 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
403 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
404 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
405 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
406 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
407 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
408 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
409 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
410 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
411 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
412 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
413 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
414 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
415 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
416 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
417 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
418 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, },
420 /* S-Box 1 */
421 { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
422 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
423 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
424 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
425 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
426 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
427 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
428 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
429 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
430 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
431 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
432 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
433 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
434 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
435 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
436 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
437 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
438 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
439 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
440 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
441 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
442 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
443 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
444 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
445 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
446 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
447 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
448 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
449 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
450 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
451 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
452 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
453 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
454 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
455 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
456 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
457 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
458 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
459 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
460 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
461 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
462 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
463 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, },
465 /* S-Box 2 */
466 { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
467 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
468 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
469 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
470 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
471 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
472 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
473 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
474 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
475 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
476 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
477 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
478 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
479 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
480 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
481 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
482 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
483 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
484 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
485 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
486 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
487 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
488 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
489 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
490 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
491 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
492 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
493 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
494 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
495 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
496 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
497 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
498 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
499 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
500 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
501 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
502 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
503 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
504 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
505 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
506 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
507 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
508 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, },
510 /* S-Box 3 */
511 { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
512 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
513 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
514 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
515 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
516 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
517 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
518 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
519 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
520 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
521 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
522 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
523 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
524 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
525 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
526 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
527 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
528 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
529 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
530 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
531 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
532 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
533 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
534 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
535 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
536 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
537 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
538 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
539 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
540 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
541 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
542 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
543 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
544 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
545 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
546 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
547 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
548 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
549 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
550 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
551 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
552 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
553 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, },
556 static const uint32_t bf_pinit[] = {
557 /* P-Box */
558 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
559 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
560 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
563 #define KEYBYTES 24
565 static const unsigned char rtmpe9_keys[16][KEYBYTES] = {
566 { 0x79, 0x34, 0x77, 0x4c, 0x67, 0xd1, 0x38, 0x3a, 0xdf, 0xb3, 0x56, 0xbe,
567 0x8b, 0x7b, 0xd0, 0x24, 0x38, 0xe0, 0x73, 0x58, 0x41, 0x5d, 0x69, 0x67, },
568 { 0x46, 0xf6, 0xb4, 0xcc, 0x01, 0x93, 0xe3, 0xa1, 0x9e, 0x7d, 0x3c, 0x65,
569 0x55, 0x86, 0xfd, 0x09, 0x8f, 0xf7, 0xb3, 0xc4, 0x6f, 0x41, 0xca, 0x5c, },
570 { 0x1a, 0xe7, 0xe2, 0xf3, 0xf9, 0x14, 0x79, 0x94, 0xc0, 0xd3, 0x97, 0x43,
571 0x08, 0x7b, 0xb3, 0x84, 0x43, 0x2f, 0x9d, 0x84, 0x3f, 0x21, 0x01, 0x9b, },
572 { 0xd3, 0xe3, 0x54, 0xb0, 0xf7, 0x1d, 0xf6, 0x2b, 0x5a, 0x43, 0x4d, 0x04,
573 0x83, 0x64, 0x3e, 0x0d, 0x59, 0x2f, 0x61, 0xcb, 0xb1, 0x6a, 0x59, 0x0d, },
574 { 0xc8, 0xc1, 0xe9, 0xb8, 0x16, 0x56, 0x99, 0x21, 0x7b, 0x5b, 0x36, 0xb7,
575 0xb5, 0x9b, 0xdf, 0x06, 0x49, 0x2c, 0x97, 0xf5, 0x95, 0x48, 0x85, 0x7e, },
576 { 0xeb, 0xe5, 0xe6, 0x2e, 0xa4, 0xba, 0xd4, 0x2c, 0xf2, 0x16, 0xe0, 0x8f,
577 0x66, 0x23, 0xa9, 0x43, 0x41, 0xce, 0x38, 0x14, 0x84, 0x95, 0x00, 0x53, },
578 { 0x66, 0xdb, 0x90, 0xf0, 0x3b, 0x4f, 0xf5, 0x6f, 0xe4, 0x9c, 0x20, 0x89,
579 0x35, 0x5e, 0xd2, 0xb2, 0xc3, 0x9e, 0x9f, 0x7f, 0x63, 0xb2, 0x28, 0x81, },
580 { 0xbb, 0x20, 0xac, 0xed, 0x2a, 0x04, 0x6a, 0x19, 0x94, 0x98, 0x9b, 0xc8,
581 0xff, 0xcd, 0x93, 0xef, 0xc6, 0x0d, 0x56, 0xa7, 0xeb, 0x13, 0xd9, 0x30, },
582 { 0xbc, 0xf2, 0x43, 0x82, 0x09, 0x40, 0x8a, 0x87, 0x25, 0x43, 0x6d, 0xe6,
583 0xbb, 0xa4, 0xb9, 0x44, 0x58, 0x3f, 0x21, 0x7c, 0x99, 0xbb, 0x3f, 0x24, },
584 { 0xec, 0x1a, 0xaa, 0xcd, 0xce, 0xbd, 0x53, 0x11, 0xd2, 0xfb, 0x83, 0xb6,
585 0xc3, 0xba, 0xab, 0x4f, 0x62, 0x79, 0xe8, 0x65, 0xa9, 0x92, 0x28, 0x76, },
586 { 0xc6, 0x0c, 0x30, 0x03, 0x91, 0x18, 0x2d, 0x7b, 0x79, 0xda, 0xe1, 0xd5,
587 0x64, 0x77, 0x9a, 0x12, 0xc5, 0xb1, 0xd7, 0x91, 0x4f, 0x96, 0x4c, 0xa3, },
588 { 0xd7, 0x7c, 0x2a, 0xbf, 0xa6, 0xe7, 0x85, 0x7c, 0x45, 0xad, 0xff, 0x12,
589 0x94, 0xd8, 0xde, 0xa4, 0x5c, 0x3d, 0x79, 0xa4, 0x44, 0x02, 0x5d, 0x22, },
590 { 0x16, 0x19, 0x0d, 0x81, 0x6a, 0x4c, 0xc7, 0xf8, 0xb8, 0xf9, 0x4e, 0xcd,
591 0x2c, 0x9e, 0x90, 0x84, 0xb2, 0x08, 0x25, 0x60, 0xe1, 0x1e, 0xae, 0x18, },
592 { 0xe9, 0x7c, 0x58, 0x26, 0x1b, 0x51, 0x9e, 0x49, 0x82, 0x60, 0x61, 0xfc,
593 0xa0, 0xa0, 0x1b, 0xcd, 0xf5, 0x05, 0xd6, 0xa6, 0x6d, 0x07, 0x88, 0xa3, },
594 { 0x2b, 0x97, 0x11, 0x8b, 0xd9, 0x4e, 0xd9, 0xdf, 0x20, 0xe3, 0x9c, 0x10,
595 0xe6, 0xa1, 0x35, 0x21, 0x11, 0xf9, 0x13, 0x0d, 0x0b, 0x24, 0x65, 0xb2, },
596 { 0x53, 0x6a, 0x4c, 0x54, 0xac, 0x8b, 0x9b, 0xb8, 0x97, 0x29, 0xfc, 0x60,
597 0x2c, 0x5b, 0x3a, 0x85, 0x68, 0xb5, 0xaa, 0x6a, 0x44, 0xcd, 0x3f, 0xa7, },
600 #define BF_ENC(X,S) \
601 (((S[0][X>>24] + S[1][X>>16 & 0xff]) ^ S[2][(X>>8) & 0xff]) + S[3][X & 0xff])
603 static void bf_enc(uint32_t *x, bf_key *key)
605 uint32_t Xl;
606 uint32_t Xr;
607 uint32_t temp;
608 int i;
610 Xl = x[0];
611 Xr = x[1];
613 for (i = 0; i < BF_ROUNDS; ++i) {
614 Xl ^= key->p[i];
615 Xr ^= BF_ENC(Xl,key->s);
617 temp = Xl;
618 Xl = Xr;
619 Xr = temp;
622 Xl ^= key->p[BF_ROUNDS];
623 Xr ^= key->p[BF_ROUNDS + 1];
625 x[0] = Xr;
626 x[1] = Xl;
629 static void bf_setkey(const unsigned char *kp, int keybytes, bf_key *key)
631 int i;
632 int j;
633 int k;
634 uint32_t data;
635 uint32_t d[2];
637 memcpy(key->p, bf_pinit, sizeof(key->p));
638 memcpy(key->s, bf_sinit, sizeof(key->s));
640 j = 0;
641 for (i = 0; i < BF_ROUNDS + 2; ++i) {
642 data = 0x00000000;
643 for (k = 0; k < 4; ++k) {
644 data = (data << 8) | kp[j];
645 j = j + 1;
646 if (j >= keybytes) {
647 j = 0;
650 key->p[i] ^= data;
653 d[0] = 0x00000000;
654 d[1] = 0x00000000;
656 for (i = 0; i < BF_ROUNDS + 2; i += 2) {
657 bf_enc(d, key);
659 key->p[i] = d[0];
660 key->p[i + 1] = d[1];
663 for (i = 0; i < 4; ++i) {
664 for (j = 0; j < 256; j += 2) {
666 bf_enc(d, key);
668 key->s[i][j] = d[0];
669 key->s[i][j + 1] = d[1];
674 static void rtmpe9_sig(uint8_t *in, uint8_t *out, int keyid)
676 uint32_t d[2];
677 bf_key key;
679 bf_setkey(rtmpe9_keys[keyid], KEYBYTES, &key);
681 /* input is little-endian */
682 d[0] = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24);
683 d[1] = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24);
684 bf_enc(d, &key);
685 out[0] = d[0] & 0xff;
686 out[1] = (d[0] >> 8) & 0xff;
687 out[2] = (d[0] >> 16) & 0xff;
688 out[3] = (d[0] >> 24) & 0xff;
689 out[4] = d[1] & 0xff;
690 out[5] = (d[1] >> 8) & 0xff;
691 out[6] = (d[1] >> 16) & 0xff;
692 out[7] = (d[1] >> 24) & 0xff;
695 static int
696 HandShake(RTMP * r, int FP9HandShake)
698 int i, offalg = 0;
699 int dhposClient = 0;
700 int digestPosClient = 0;
701 int encrypted = r->Link.protocol & RTMP_FEATURE_ENC;
703 RC4_handle keyIn = 0;
704 RC4_handle keyOut = 0;
706 int32_t *ip;
707 uint32_t uptime;
709 uint8_t clientbuf[RTMP_SIG_SIZE + 4], *clientsig=clientbuf+4;
710 uint8_t serversig[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply;
711 uint8_t type;
712 getoff *getdh = NULL, *getdig = NULL;
714 if (encrypted || r->Link.SWFSize)
715 FP9HandShake = TRUE;
716 else
717 FP9HandShake = FALSE;
719 r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
721 if (encrypted)
723 clientsig[-1] = 0x06; /* 0x08 is RTMPE as well */
724 offalg = 1;
726 else
727 clientsig[-1] = 0x03;
729 uptime = htonl(RTMP_GetTime());
730 memcpy(clientsig, &uptime, 4);
732 if (FP9HandShake)
734 /* set version to at least 9.0.115.0 */
735 if (encrypted)
737 clientsig[4] = 128;
738 clientsig[6] = 3;
740 else
742 clientsig[4] = 10;
743 clientsig[6] = 45;
745 clientsig[5] = 0;
746 clientsig[7] = 2;
748 RTMP_Log(RTMP_LOGDEBUG, "%s: Client type: %02X", __FUNCTION__, clientsig[-1]);
749 getdig = digoff[offalg];
750 getdh = dhoff[offalg];
752 else
754 memset(&clientsig[4], 0, 4);
757 /* generate random data */
758 #ifdef _DEBUG
759 memset(clientsig+8, 0, RTMP_SIG_SIZE-8);
760 #else
761 ip = (int32_t *)(clientsig+8);
762 for (i = 2; i < RTMP_SIG_SIZE/4; i++)
763 *ip++ = rand();
764 #endif
766 /* set handshake digest */
767 if (FP9HandShake)
769 if (encrypted)
771 /* generate Diffie-Hellmann parameters */
772 r->Link.dh = DHInit(1024);
773 if (!r->Link.dh)
775 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
776 __FUNCTION__);
777 return FALSE;
780 dhposClient = getdh(clientsig, RTMP_SIG_SIZE);
781 RTMP_Log(RTMP_LOGDEBUG, "%s: DH pubkey position: %d", __FUNCTION__, dhposClient);
783 if (!DHGenerateKey(r->Link.dh))
785 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't generate Diffie-Hellmann public key!",
786 __FUNCTION__);
787 return FALSE;
790 if (!DHGetPublicKey(r->Link.dh, &clientsig[dhposClient], 128))
792 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
793 return FALSE;
797 digestPosClient = getdig(clientsig, RTMP_SIG_SIZE); /* reuse this value in verification */
798 RTMP_Log(RTMP_LOGDEBUG, "%s: Client digest offset: %d", __FUNCTION__,
799 digestPosClient);
801 CalculateDigest(digestPosClient, clientsig, GenuineFPKey, 30,
802 &clientsig[digestPosClient]);
804 RTMP_Log(RTMP_LOGDEBUG, "%s: Initial client digest: ", __FUNCTION__);
805 RTMP_LogHex(RTMP_LOGDEBUG, clientsig + digestPosClient,
806 SHA256_DIGEST_LENGTH);
809 #ifdef _DEBUG
810 RTMP_Log(RTMP_LOGDEBUG, "Clientsig: ");
811 RTMP_LogHex(RTMP_LOGDEBUG, clientsig, RTMP_SIG_SIZE);
812 #endif
814 if (!WriteN(r, (char *)clientsig-1, RTMP_SIG_SIZE + 1))
815 return FALSE;
817 if (ReadN(r, (char *)&type, 1) != 1) /* 0x03 or 0x06 */
818 return FALSE;
820 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
822 if (type != clientsig[-1])
823 RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
824 __FUNCTION__, clientsig[-1], type);
826 if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
827 return FALSE;
829 /* decode server response */
830 memcpy(&uptime, serversig, 4);
831 uptime = ntohl(uptime);
833 RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, uptime);
834 RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4],
835 serversig[5], serversig[6], serversig[7]);
837 if (FP9HandShake && type == 3 && !serversig[4])
838 FP9HandShake = FALSE;
840 #ifdef _DEBUG
841 RTMP_Log(RTMP_LOGDEBUG, "Server signature:");
842 RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE);
843 #endif
845 if (FP9HandShake)
847 uint8_t digestResp[SHA256_DIGEST_LENGTH];
848 uint8_t *signatureResp = NULL;
850 /* we have to use this signature now to find the correct algorithms for getting the digest and DH positions */
851 int digestPosServer = getdig(serversig, RTMP_SIG_SIZE);
853 if (!VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36))
855 RTMP_Log(RTMP_LOGWARNING, "Trying different position for server digest!");
856 offalg ^= 1;
857 getdig = digoff[offalg];
858 getdh = dhoff[offalg];
859 digestPosServer = getdig(serversig, RTMP_SIG_SIZE);
861 if (!VerifyDigest(digestPosServer, serversig, GenuineFMSKey, 36))
863 RTMP_Log(RTMP_LOGERROR, "Couldn't verify the server digest"); /* continuing anyway will probably fail */
864 return FALSE;
868 /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
869 if (r->Link.SWFSize)
871 const char swfVerify[] = { 0x01, 0x01 };
872 char *vend = r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);
874 memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
875 AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], vend, r->Link.SWFSize);
876 AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], vend, r->Link.SWFSize);
877 HMACsha256(r->Link.SWFHash, SHA256_DIGEST_LENGTH,
878 &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
879 SHA256_DIGEST_LENGTH,
880 (uint8_t *)&r->Link.SWFVerificationResponse[10]);
883 /* do Diffie-Hellmann Key exchange for encrypted RTMP */
884 if (encrypted)
886 /* compute secret key */
887 uint8_t secretKey[128] = { 0 };
888 int len, dhposServer;
890 dhposServer = getdh(serversig, RTMP_SIG_SIZE);
891 RTMP_Log(RTMP_LOGDEBUG, "%s: Server DH public key offset: %d", __FUNCTION__,
892 dhposServer);
893 len = DHComputeSharedSecretKey(r->Link.dh, &serversig[dhposServer],
894 128, secretKey);
895 if (len < 0)
897 RTMP_Log(RTMP_LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
898 return FALSE;
901 RTMP_Log(RTMP_LOGDEBUG, "%s: Secret key: ", __FUNCTION__);
902 RTMP_LogHex(RTMP_LOGDEBUG, secretKey, 128);
904 InitRC4Encryption(secretKey,
905 (uint8_t *) & serversig[dhposServer],
906 (uint8_t *) & clientsig[dhposClient],
907 &keyIn, &keyOut);
911 reply = client2;
912 #ifdef _DEBUG
913 memset(reply, 0xff, RTMP_SIG_SIZE);
914 #else
915 ip = (int32_t *)reply;
916 for (i = 0; i < RTMP_SIG_SIZE/4; i++)
917 *ip++ = rand();
918 #endif
919 /* calculate response now */
920 signatureResp = reply+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH;
922 HMACsha256(&serversig[digestPosServer], SHA256_DIGEST_LENGTH,
923 GenuineFPKey, sizeof(GenuineFPKey), digestResp);
924 HMACsha256(reply, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digestResp,
925 SHA256_DIGEST_LENGTH, signatureResp);
927 /* some info output */
928 RTMP_Log(RTMP_LOGDEBUG,
929 "%s: Calculated digest key from secure key and server digest: ",
930 __FUNCTION__);
931 RTMP_LogHex(RTMP_LOGDEBUG, digestResp, SHA256_DIGEST_LENGTH);
933 #ifdef FP10
934 if (type == 8 )
936 uint8_t *dptr = digestResp;
937 uint8_t *sig = signatureResp;
938 /* encrypt signatureResp */
939 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
940 rtmpe8_sig(sig+i, sig+i, dptr[i] % 15);
942 else if (type == 9)
944 uint8_t *dptr = digestResp;
945 uint8_t *sig = signatureResp;
946 /* encrypt signatureResp */
947 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
948 rtmpe9_sig(sig+i, sig+i, dptr[i] % 15);
950 #endif
951 RTMP_Log(RTMP_LOGDEBUG, "%s: Client signature calculated:", __FUNCTION__);
952 RTMP_LogHex(RTMP_LOGDEBUG, signatureResp, SHA256_DIGEST_LENGTH);
954 else
956 reply = serversig;
957 #if 0
958 uptime = htonl(RTMP_GetTime());
959 memcpy(reply+4, &uptime, 4);
960 #endif
963 #ifdef _DEBUG
964 RTMP_Log(RTMP_LOGDEBUG, "%s: Sending handshake response: ",
965 __FUNCTION__);
966 RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE);
967 #endif
968 if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE))
969 return FALSE;
971 /* 2nd part of handshake */
972 if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
973 return FALSE;
975 #ifdef _DEBUG
976 RTMP_Log(RTMP_LOGDEBUG, "%s: 2nd handshake: ", __FUNCTION__);
977 RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE);
978 #endif
980 if (FP9HandShake)
982 uint8_t signature[SHA256_DIGEST_LENGTH];
983 uint8_t digest[SHA256_DIGEST_LENGTH];
985 if (serversig[4] == 0 && serversig[5] == 0 && serversig[6] == 0
986 && serversig[7] == 0)
988 RTMP_Log(RTMP_LOGDEBUG,
989 "%s: Wait, did the server just refuse signed authentication?",
990 __FUNCTION__);
992 RTMP_Log(RTMP_LOGDEBUG, "%s: Server sent signature:", __FUNCTION__);
993 RTMP_LogHex(RTMP_LOGDEBUG, &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
994 SHA256_DIGEST_LENGTH);
996 /* verify server response */
997 HMACsha256(&clientsig[digestPosClient], SHA256_DIGEST_LENGTH,
998 GenuineFMSKey, sizeof(GenuineFMSKey), digest);
999 HMACsha256(serversig, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest,
1000 SHA256_DIGEST_LENGTH, signature);
1002 /* show some information */
1003 RTMP_Log(RTMP_LOGDEBUG, "%s: Digest key: ", __FUNCTION__);
1004 RTMP_LogHex(RTMP_LOGDEBUG, digest, SHA256_DIGEST_LENGTH);
1006 #ifdef FP10
1007 if (type == 8 )
1009 uint8_t *dptr = digest;
1010 uint8_t *sig = signature;
1011 /* encrypt signature */
1012 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
1013 rtmpe8_sig(sig+i, sig+i, dptr[i] % 15);
1015 else if (type == 9)
1017 uint8_t *dptr = digest;
1018 uint8_t *sig = signature;
1019 /* encrypt signatureResp */
1020 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
1021 rtmpe9_sig(sig+i, sig+i, dptr[i] % 15);
1023 #endif
1024 RTMP_Log(RTMP_LOGDEBUG, "%s: Signature calculated:", __FUNCTION__);
1025 RTMP_LogHex(RTMP_LOGDEBUG, signature, SHA256_DIGEST_LENGTH);
1026 if (memcmp
1027 (signature, &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
1028 SHA256_DIGEST_LENGTH) != 0)
1030 RTMP_Log(RTMP_LOGWARNING, "%s: Server not genuine Adobe!", __FUNCTION__);
1031 return FALSE;
1033 else
1035 RTMP_Log(RTMP_LOGDEBUG, "%s: Genuine Adobe Flash Media Server", __FUNCTION__);
1038 if (encrypted)
1040 char buff[RTMP_SIG_SIZE];
1041 /* set keys for encryption from now on */
1042 r->Link.rc4keyIn = keyIn;
1043 r->Link.rc4keyOut = keyOut;
1046 /* update the keystreams */
1047 if (r->Link.rc4keyIn)
1049 RC4_encrypt(r->Link.rc4keyIn, RTMP_SIG_SIZE, (uint8_t *) buff);
1052 if (r->Link.rc4keyOut)
1054 RC4_encrypt(r->Link.rc4keyOut, RTMP_SIG_SIZE, (uint8_t *) buff);
1058 else
1060 if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0)
1062 RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!",
1063 __FUNCTION__);
1067 RTMP_Log(RTMP_LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
1068 return TRUE;
1071 static int
1072 SHandShake(RTMP * r)
1074 int i, offalg = 0;
1075 int dhposServer = 0;
1076 int digestPosServer = 0;
1077 RC4_handle keyIn = 0;
1078 RC4_handle keyOut = 0;
1079 int FP9HandShake = FALSE;
1080 int encrypted;
1081 int32_t *ip;
1083 uint8_t clientsig[RTMP_SIG_SIZE];
1084 uint8_t serverbuf[RTMP_SIG_SIZE + 4], *serversig = serverbuf+4;
1085 uint8_t type;
1086 uint32_t uptime;
1087 getoff *getdh = NULL, *getdig = NULL;
1089 if (ReadN(r, (char *)&type, 1) != 1) /* 0x03 or 0x06 */
1090 return FALSE;
1092 if (ReadN(r, (char *)clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
1093 return FALSE;
1095 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Requested : %02X", __FUNCTION__, type);
1096 RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
1098 if (type == 3)
1100 encrypted = FALSE;
1102 else if (type == 6 || type == 8)
1104 offalg = 1;
1105 encrypted = TRUE;
1106 FP9HandShake = TRUE;
1107 r->Link.protocol |= RTMP_FEATURE_ENC;
1108 /* use FP10 if client is capable */
1109 if (clientsig[4] == 128)
1110 type = 8;
1112 else
1114 RTMP_Log(RTMP_LOGERROR, "%s: Unknown version %02x",
1115 __FUNCTION__, type);
1116 return FALSE;
1119 if (!FP9HandShake && clientsig[4])
1120 FP9HandShake = TRUE;
1122 serversig[-1] = type;
1124 r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
1126 uptime = htonl(RTMP_GetTime());
1127 memcpy(serversig, &uptime, 4);
1129 if (FP9HandShake)
1131 /* Server version */
1132 serversig[4] = 3;
1133 serversig[5] = 5;
1134 serversig[6] = 1;
1135 serversig[7] = 1;
1137 getdig = digoff[offalg];
1138 getdh = dhoff[offalg];
1140 else
1142 memset(&serversig[4], 0, 4);
1145 /* generate random data */
1146 #ifdef _DEBUG
1147 memset(serversig+8, 0, RTMP_SIG_SIZE-8);
1148 #else
1149 ip = (int32_t *)(serversig+8);
1150 for (i = 2; i < RTMP_SIG_SIZE/4; i++)
1151 *ip++ = rand();
1152 #endif
1154 /* set handshake digest */
1155 if (FP9HandShake)
1157 if (encrypted)
1159 /* generate Diffie-Hellmann parameters */
1160 r->Link.dh = DHInit(1024);
1161 if (!r->Link.dh)
1163 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
1164 __FUNCTION__);
1165 return FALSE;
1168 dhposServer = getdh(serversig, RTMP_SIG_SIZE);
1169 RTMP_Log(RTMP_LOGDEBUG, "%s: DH pubkey position: %d", __FUNCTION__, dhposServer);
1171 if (!DHGenerateKey(r->Link.dh))
1173 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't generate Diffie-Hellmann public key!",
1174 __FUNCTION__);
1175 return FALSE;
1178 if (!DHGetPublicKey
1179 (r->Link.dh, (uint8_t *) &serversig[dhposServer], 128))
1181 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
1182 return FALSE;
1186 digestPosServer = getdig(serversig, RTMP_SIG_SIZE); /* reuse this value in verification */
1187 RTMP_Log(RTMP_LOGDEBUG, "%s: Server digest offset: %d", __FUNCTION__,
1188 digestPosServer);
1190 CalculateDigest(digestPosServer, serversig, GenuineFMSKey, 36,
1191 &serversig[digestPosServer]);
1193 RTMP_Log(RTMP_LOGDEBUG, "%s: Initial server digest: ", __FUNCTION__);
1194 RTMP_LogHex(RTMP_LOGDEBUG, serversig + digestPosServer,
1195 SHA256_DIGEST_LENGTH);
1198 RTMP_Log(RTMP_LOGDEBUG2, "Serversig: ");
1199 RTMP_LogHex(RTMP_LOGDEBUG2, serversig, RTMP_SIG_SIZE);
1201 if (!WriteN(r, (char *)serversig-1, RTMP_SIG_SIZE + 1))
1202 return FALSE;
1204 /* decode client response */
1205 memcpy(&uptime, clientsig, 4);
1206 uptime = ntohl(uptime);
1208 RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
1209 RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__, clientsig[4],
1210 clientsig[5], clientsig[6], clientsig[7]);
1212 if (FP9HandShake)
1214 uint8_t digestResp[SHA256_DIGEST_LENGTH];
1215 uint8_t *signatureResp = NULL;
1217 /* we have to use this signature now to find the correct algorithms for getting the digest and DH positions */
1218 int digestPosClient = getdig(clientsig, RTMP_SIG_SIZE);
1220 if (!VerifyDigest(digestPosClient, clientsig, GenuineFPKey, 30))
1222 RTMP_Log(RTMP_LOGWARNING, "Trying different position for client digest!");
1223 offalg ^= 1;
1224 getdig = digoff[offalg];
1225 getdh = dhoff[offalg];
1227 digestPosClient = getdig(clientsig, RTMP_SIG_SIZE);
1229 if (!VerifyDigest(digestPosClient, clientsig, GenuineFPKey, 30))
1231 RTMP_Log(RTMP_LOGERROR, "Couldn't verify the client digest"); /* continuing anyway will probably fail */
1232 return FALSE;
1236 /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
1237 if (r->Link.SWFSize)
1239 const char swfVerify[] = { 0x01, 0x01 };
1240 char *vend = r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);
1242 memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
1243 AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], vend, r->Link.SWFSize);
1244 AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], vend, r->Link.SWFSize);
1245 HMACsha256(r->Link.SWFHash, SHA256_DIGEST_LENGTH,
1246 &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
1247 SHA256_DIGEST_LENGTH,
1248 (uint8_t *)&r->Link.SWFVerificationResponse[10]);
1251 /* do Diffie-Hellmann Key exchange for encrypted RTMP */
1252 if (encrypted)
1254 int dhposClient, len;
1255 /* compute secret key */
1256 uint8_t secretKey[128] = { 0 };
1258 dhposClient = getdh(clientsig, RTMP_SIG_SIZE);
1259 RTMP_Log(RTMP_LOGDEBUG, "%s: Client DH public key offset: %d", __FUNCTION__,
1260 dhposClient);
1261 len =
1262 DHComputeSharedSecretKey(r->Link.dh,
1263 (uint8_t *) &clientsig[dhposClient], 128,
1264 secretKey);
1265 if (len < 0)
1267 RTMP_Log(RTMP_LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
1268 return FALSE;
1271 RTMP_Log(RTMP_LOGDEBUG, "%s: Secret key: ", __FUNCTION__);
1272 RTMP_LogHex(RTMP_LOGDEBUG, secretKey, 128);
1274 InitRC4Encryption(secretKey,
1275 (uint8_t *) &clientsig[dhposClient],
1276 (uint8_t *) &serversig[dhposServer],
1277 &keyIn, &keyOut);
1281 /* calculate response now */
1282 signatureResp = clientsig+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH;
1284 HMACsha256(&clientsig[digestPosClient], SHA256_DIGEST_LENGTH,
1285 GenuineFMSKey, sizeof(GenuineFMSKey), digestResp);
1286 HMACsha256(clientsig, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digestResp,
1287 SHA256_DIGEST_LENGTH, signatureResp);
1288 #ifdef FP10
1289 if (type == 8 )
1291 uint8_t *dptr = digestResp;
1292 uint8_t *sig = signatureResp;
1293 /* encrypt signatureResp */
1294 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
1295 rtmpe8_sig(sig+i, sig+i, dptr[i] % 15);
1297 else if (type == 9)
1299 uint8_t *dptr = digestResp;
1300 uint8_t *sig = signatureResp;
1301 /* encrypt signatureResp */
1302 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
1303 rtmpe9_sig(sig+i, sig+i, dptr[i] % 15);
1305 #endif
1307 /* some info output */
1308 RTMP_Log(RTMP_LOGDEBUG,
1309 "%s: Calculated digest key from secure key and server digest: ",
1310 __FUNCTION__);
1311 RTMP_LogHex(RTMP_LOGDEBUG, digestResp, SHA256_DIGEST_LENGTH);
1313 RTMP_Log(RTMP_LOGDEBUG, "%s: Server signature calculated:", __FUNCTION__);
1314 RTMP_LogHex(RTMP_LOGDEBUG, signatureResp, SHA256_DIGEST_LENGTH);
1316 #if 0
1317 else
1319 uptime = htonl(RTMP_GetTime());
1320 memcpy(clientsig+4, &uptime, 4);
1322 #endif
1324 RTMP_Log(RTMP_LOGDEBUG2, "%s: Sending handshake response: ",
1325 __FUNCTION__);
1326 RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
1328 if (!WriteN(r, (char *)clientsig, RTMP_SIG_SIZE))
1329 return FALSE;
1331 /* 2nd part of handshake */
1332 if (ReadN(r, (char *)clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
1333 return FALSE;
1335 RTMP_Log(RTMP_LOGDEBUG2, "%s: 2nd handshake: ", __FUNCTION__);
1336 RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
1338 if (FP9HandShake)
1340 uint8_t signature[SHA256_DIGEST_LENGTH];
1341 uint8_t digest[SHA256_DIGEST_LENGTH];
1343 RTMP_Log(RTMP_LOGDEBUG, "%s: Client sent signature:", __FUNCTION__);
1344 RTMP_LogHex(RTMP_LOGDEBUG, &clientsig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
1345 SHA256_DIGEST_LENGTH);
1347 /* verify client response */
1348 HMACsha256(&serversig[digestPosServer], SHA256_DIGEST_LENGTH,
1349 GenuineFPKey, sizeof(GenuineFPKey), digest);
1350 HMACsha256(clientsig, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest,
1351 SHA256_DIGEST_LENGTH, signature);
1352 #ifdef FP10
1353 if (type == 8 )
1355 uint8_t *dptr = digest;
1356 uint8_t *sig = signature;
1357 /* encrypt signatureResp */
1358 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
1359 rtmpe8_sig(sig+i, sig+i, dptr[i] % 15);
1361 else if (type == 9)
1363 uint8_t *dptr = digest;
1364 uint8_t *sig = signature;
1365 /* encrypt signatureResp */
1366 for (i=0; i<SHA256_DIGEST_LENGTH; i+=8)
1367 rtmpe9_sig(sig+i, sig+i, dptr[i] % 15);
1369 #endif
1371 /* show some information */
1372 RTMP_Log(RTMP_LOGDEBUG, "%s: Digest key: ", __FUNCTION__);
1373 RTMP_LogHex(RTMP_LOGDEBUG, digest, SHA256_DIGEST_LENGTH);
1375 RTMP_Log(RTMP_LOGDEBUG, "%s: Signature calculated:", __FUNCTION__);
1376 RTMP_LogHex(RTMP_LOGDEBUG, signature, SHA256_DIGEST_LENGTH);
1377 if (memcmp
1378 (signature, &clientsig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
1379 SHA256_DIGEST_LENGTH) != 0)
1381 RTMP_Log(RTMP_LOGWARNING, "%s: Client not genuine Adobe!", __FUNCTION__);
1382 return FALSE;
1384 else
1386 RTMP_Log(RTMP_LOGDEBUG, "%s: Genuine Adobe Flash Player", __FUNCTION__);
1389 if (encrypted)
1391 char buff[RTMP_SIG_SIZE];
1392 /* set keys for encryption from now on */
1393 r->Link.rc4keyIn = keyIn;
1394 r->Link.rc4keyOut = keyOut;
1396 /* update the keystreams */
1397 if (r->Link.rc4keyIn)
1399 RC4_encrypt(r->Link.rc4keyIn, RTMP_SIG_SIZE, (uint8_t *) buff);
1402 if (r->Link.rc4keyOut)
1404 RC4_encrypt(r->Link.rc4keyOut, RTMP_SIG_SIZE, (uint8_t *) buff);
1408 else
1410 if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0)
1412 RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!",
1413 __FUNCTION__);
1417 RTMP_Log(RTMP_LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
1418 return TRUE;