v2.6 changes
[rtmpdump.git] / librtmp / handshake.h
blobac38c880d204664ae56a5f02499b8003e8940a08
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 #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)
77 #else
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)
81 #endif
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)
89 #endif
91 #define FP10
93 #include "dh.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
106 }; /* 68 */
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 */
113 0xF0, 0xEE,
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,
117 0x31, 0xAE
118 }; /* 62 */
120 static void InitRC4Encryption
121 (uint8_t * secretKey,
122 uint8_t * pubKeyIn,
123 uint8_t * pubKeyOut, RC4_handle *rc4keyIn, RC4_handle *rc4keyOut)
125 uint8_t digest[SHA256_DIGEST_LENGTH];
126 unsigned int digestLen = 0;
127 HMAC_CTX ctx;
129 RC4_alloc(rc4keyIn);
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);
153 static unsigned int
154 GetDHOffset2(uint8_t *handshake, unsigned int len)
156 unsigned int offset = 0;
157 uint8_t *ptr = handshake + 768;
158 unsigned int res;
160 assert(RTMP_SIG_SIZE <= len);
162 offset += (*ptr);
163 ptr++;
164 offset += (*ptr);
165 ptr++;
166 offset += (*ptr);
167 ptr++;
168 offset += (*ptr);
170 res = (offset % 632) + 8;
172 if (res + 128 > 767)
174 RTMP_Log(RTMP_LOGERROR,
175 "%s: Couldn't calculate correct DH offset (got %d), exiting!",
176 __FUNCTION__, res);
177 exit(1);
179 return res;
182 static unsigned int
183 GetDigestOffset2(uint8_t *handshake, unsigned int len)
185 unsigned int offset = 0;
186 uint8_t *ptr = handshake + 772;
187 unsigned int res;
189 offset += (*ptr);
190 ptr++;
191 offset += (*ptr);
192 ptr++;
193 offset += (*ptr);
194 ptr++;
195 offset += (*ptr);
197 res = (offset % 728) + 776;
199 if (res + 32 > 1535)
201 RTMP_Log(RTMP_LOGERROR,
202 "%s: Couldn't calculate correct digest offset (got %d), exiting",
203 __FUNCTION__, res);
204 exit(1);
206 return res;
209 static unsigned int
210 GetDHOffset1(uint8_t *handshake, unsigned int len)
212 unsigned int offset = 0;
213 uint8_t *ptr = handshake + 1532;
214 unsigned int res;
216 assert(RTMP_SIG_SIZE <= len);
218 offset += (*ptr);
219 ptr++;
220 offset += (*ptr);
221 ptr++;
222 offset += (*ptr);
223 ptr++;
224 offset += (*ptr);
226 res = (offset % 632) + 772;
228 if (res + 128 > 1531)
230 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't calculate DH offset (got %d), exiting!",
231 __FUNCTION__, res);
232 exit(1);
235 return res;
238 static unsigned int
239 GetDigestOffset1(uint8_t *handshake, unsigned int len)
241 unsigned int offset = 0;
242 uint8_t *ptr = handshake + 8;
243 unsigned int res;
245 assert(12 <= len);
247 offset += (*ptr);
248 ptr++;
249 offset += (*ptr);
250 ptr++;
251 offset += (*ptr);
252 ptr++;
253 offset += (*ptr);
255 res = (offset % 728) + 12;
257 if (res + 32 > 771)
259 RTMP_Log(RTMP_LOGERROR,
260 "%s: Couldn't calculate digest offset (got %d), exiting!",
261 __FUNCTION__, res);
262 exit(1);
265 return res;
268 static getoff *digoff[] = {GetDigestOffset1, GetDigestOffset2};
269 static getoff *dhoff[] = {GetDHOffset1, GetDHOffset2};
271 static void
272 HMACsha256(const uint8_t *message, size_t messageLen, const uint8_t *key,
273 size_t keylen, uint8_t *digest)
275 unsigned int digestLen;
276 HMAC_CTX ctx;
278 HMAC_setup(ctx, key, keylen);
279 HMAC_crunch(ctx, message, messageLen);
280 HMAC_finish(ctx, digest, digestLen);
282 assert(digestLen == 32);
285 static void
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);
300 static int
301 VerifyDigest(unsigned int digestPos, uint8_t *handshakeMessage, const uint8_t *key,
302 size_t keyLen)
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;
312 /* handshake
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
318 * ...
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;
348 uint32_t const *k;
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]);
356 sum += delta;
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;
363 out[3] = v0;
365 out[4] = v1; v1 >>= 8;
366 out[5] = v1; v1 >>= 8;
367 out[6] = v1; v1 >>= 8;
368 out[7] = v1;
371 /* RTMPE type 9 uses Blowfish on the regular signature
372 * http://en.wikipedia.org/wiki/Blowfish_(cipher)
374 #define BF_ROUNDS 16
375 typedef struct bf_key {
376 uint32_t s[4][256];
377 uint32_t p[BF_ROUNDS+2];
378 } bf_key;
380 static const uint32_t bf_sinit[][256] = {
382 /* S-Box 0 */
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, },
427 /* S-Box 1 */
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, },
472 /* S-Box 2 */
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, },
517 /* S-Box 3 */
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[] = {
564 /* P-Box */
565 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
566 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
567 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
570 #define KEYBYTES 24
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)
612 uint32_t Xl;
613 uint32_t Xr;
614 uint32_t temp;
615 int i;
617 Xl = x[0];
618 Xr = x[1];
620 for (i = 0; i < BF_ROUNDS; ++i) {
621 Xl ^= key->p[i];
622 Xr ^= BF_ENC(Xl,key->s);
624 temp = Xl;
625 Xl = Xr;
626 Xr = temp;
629 Xl ^= key->p[BF_ROUNDS];
630 Xr ^= key->p[BF_ROUNDS + 1];
632 x[0] = Xr;
633 x[1] = Xl;
636 static void bf_setkey(const unsigned char *kp, int keybytes, bf_key *key)
638 int i;
639 int j;
640 int k;
641 uint32_t data;
642 uint32_t d[2];
644 memcpy(key->p, bf_pinit, sizeof(key->p));
645 memcpy(key->s, bf_sinit, sizeof(key->s));
647 j = 0;
648 for (i = 0; i < BF_ROUNDS + 2; ++i) {
649 data = 0x00000000;
650 for (k = 0; k < 4; ++k) {
651 data = (data << 8) | kp[j];
652 j = j + 1;
653 if (j >= keybytes) {
654 j = 0;
657 key->p[i] ^= data;
660 d[0] = 0x00000000;
661 d[1] = 0x00000000;
663 for (i = 0; i < BF_ROUNDS + 2; i += 2) {
664 bf_enc(d, key);
666 key->p[i] = d[0];
667 key->p[i + 1] = d[1];
670 for (i = 0; i < 4; ++i) {
671 for (j = 0; j < 256; j += 2) {
673 bf_enc(d, key);
675 key->s[i][j] = d[0];
676 key->s[i][j + 1] = d[1];
681 static void rtmpe9_sig(uint8_t *in, uint8_t *out, int keyid)
683 uint32_t d[2];
684 bf_key key;
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);
691 bf_enc(d, &key);
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;
702 static int
703 HandShake(RTMP * r, int FP9HandShake)
705 int i, offalg = 0;
706 int dhposClient = 0;
707 int digestPosClient = 0;
708 int encrypted = r->Link.protocol & RTMP_FEATURE_ENC;
710 RC4_handle keyIn = 0;
711 RC4_handle keyOut = 0;
713 int32_t *ip;
714 uint32_t uptime;
716 uint8_t clientbuf[RTMP_SIG_SIZE + 4], *clientsig=clientbuf+4;
717 uint8_t serversig[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply;
718 uint8_t type;
719 getoff *getdh = NULL, *getdig = NULL;
721 if (encrypted || r->Link.SWFSize)
722 FP9HandShake = TRUE;
723 else
724 FP9HandShake = FALSE;
726 r->Link.rc4keyIn = r->Link.rc4keyOut = 0;
728 if (encrypted)
730 clientsig[-1] = 0x06; /* 0x08 is RTMPE as well */
731 offalg = 1;
733 else
734 clientsig[-1] = 0x03;
736 uptime = htonl(RTMP_GetTime());
737 memcpy(clientsig, &uptime, 4);
739 if (FP9HandShake)
741 /* set version to at least 9.0.115.0 */
742 if (encrypted)
744 clientsig[4] = 128;
745 clientsig[6] = 3;
747 else
749 clientsig[4] = 10;
750 clientsig[6] = 45;
752 clientsig[5] = 0;
753 clientsig[7] = 2;
755 RTMP_Log(RTMP_LOGDEBUG, "%s: Client type: %02X", __FUNCTION__, clientsig[-1]);
756 getdig = digoff[offalg];
757 getdh = dhoff[offalg];
759 else
761 memset(&clientsig[4], 0, 4);
764 /* generate random data */
765 #ifdef _DEBUG
766 memset(clientsig+8, 0, RTMP_SIG_SIZE-8);
767 #else
768 ip = (int32_t *)(clientsig+8);
769 for (i = 2; i < RTMP_SIG_SIZE/4; i++)
770 *ip++ = rand();
771 #endif
773 /* set handshake digest */
774 if (FP9HandShake)
776 if (encrypted)
778 /* generate Diffie-Hellmann parameters */
779 r->Link.dh = DHInit(1024);
780 if (!r->Link.dh)
782 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
783 __FUNCTION__);
784 return FALSE;
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!",
793 __FUNCTION__);
794 return FALSE;
797 if (!DHGetPublicKey(r->Link.dh, &clientsig[dhposClient], 128))
799 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
800 return FALSE;
804 digestPosClient = getdig(clientsig, RTMP_SIG_SIZE); /* reuse this value in verification */
805 RTMP_Log(RTMP_LOGDEBUG, "%s: Client digest offset: %d", __FUNCTION__,
806 digestPosClient);
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);
816 #ifdef _DEBUG
817 RTMP_Log(RTMP_LOGDEBUG, "Clientsig: ");
818 RTMP_LogHex(RTMP_LOGDEBUG, clientsig, RTMP_SIG_SIZE);
819 #endif
821 if (!WriteN(r, (char *)clientsig-1, RTMP_SIG_SIZE + 1))
822 return FALSE;
824 if (ReadN(r, (char *)&type, 1) != 1) /* 0x03 or 0x06 */
825 return FALSE;
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)
834 return FALSE;
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;
847 #ifdef _DEBUG
848 RTMP_Log(RTMP_LOGDEBUG, "Server signature:");
849 RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE);
850 #endif
852 if (FP9HandShake)
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!");
863 offalg ^= 1;
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 */
871 return FALSE;
875 /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
876 if (r->Link.SWFSize)
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 */
891 if (encrypted)
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__,
899 dhposServer);
900 len = DHComputeSharedSecretKey(r->Link.dh, &serversig[dhposServer],
901 128, secretKey);
902 if (len < 0)
904 RTMP_Log(RTMP_LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
905 return FALSE;
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],
914 &keyIn, &keyOut);
918 reply = client2;
919 #ifdef _DEBUG
920 memset(reply, 0xff, RTMP_SIG_SIZE);
921 #else
922 ip = (int32_t *)reply;
923 for (i = 0; i < RTMP_SIG_SIZE/4; i++)
924 *ip++ = rand();
925 #endif
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: ",
937 __FUNCTION__);
938 RTMP_LogHex(RTMP_LOGDEBUG, digestResp, SHA256_DIGEST_LENGTH);
940 #ifdef FP10
941 if (type == 8 )
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);
949 else if (type == 9)
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);
957 #endif
958 RTMP_Log(RTMP_LOGDEBUG, "%s: Client signature calculated:", __FUNCTION__);
959 RTMP_LogHex(RTMP_LOGDEBUG, signatureResp, SHA256_DIGEST_LENGTH);
961 else
963 reply = serversig;
964 #if 0
965 uptime = htonl(RTMP_GetTime());
966 memcpy(reply+4, &uptime, 4);
967 #endif
970 #ifdef _DEBUG
971 RTMP_Log(RTMP_LOGDEBUG, "%s: Sending handshake response: ",
972 __FUNCTION__);
973 RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE);
974 #endif
975 if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE))
976 return FALSE;
978 /* 2nd part of handshake */
979 if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
980 return FALSE;
982 #ifdef _DEBUG
983 RTMP_Log(RTMP_LOGDEBUG, "%s: 2nd handshake: ", __FUNCTION__);
984 RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE);
985 #endif
987 if (FP9HandShake)
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?",
997 __FUNCTION__);
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);
1013 #ifdef FP10
1014 if (type == 8 )
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);
1022 else if (type == 9)
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);
1030 #endif
1031 RTMP_Log(RTMP_LOGDEBUG, "%s: Signature calculated:", __FUNCTION__);
1032 RTMP_LogHex(RTMP_LOGDEBUG, signature, SHA256_DIGEST_LENGTH);
1033 if (memcmp
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__);
1038 return FALSE;
1040 else
1042 RTMP_Log(RTMP_LOGDEBUG, "%s: Genuine Adobe Flash Media Server", __FUNCTION__);
1045 if (encrypted)
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);
1065 else
1067 if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0)
1069 RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!",
1070 __FUNCTION__);
1074 RTMP_Log(RTMP_LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
1075 return TRUE;
1078 static int
1079 SHandShake(RTMP * r)
1081 int i, offalg = 0;
1082 int dhposServer = 0;
1083 int digestPosServer = 0;
1084 RC4_handle keyIn = 0;
1085 RC4_handle keyOut = 0;
1086 int FP9HandShake = FALSE;
1087 int encrypted;
1088 int32_t *ip;
1090 uint8_t clientsig[RTMP_SIG_SIZE];
1091 uint8_t serverbuf[RTMP_SIG_SIZE + 4], *serversig = serverbuf+4;
1092 uint8_t type;
1093 uint32_t uptime;
1094 getoff *getdh = NULL, *getdig = NULL;
1096 if (ReadN(r, (char *)&type, 1) != 1) /* 0x03 or 0x06 */
1097 return FALSE;
1099 if (ReadN(r, (char *)clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
1100 return FALSE;
1102 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Requested : %02X", __FUNCTION__, type);
1103 RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
1105 if (type == 3)
1107 encrypted = FALSE;
1109 else if (type == 6 || type == 8)
1111 offalg = 1;
1112 encrypted = TRUE;
1113 FP9HandShake = TRUE;
1114 r->Link.protocol |= RTMP_FEATURE_ENC;
1115 /* use FP10 if client is capable */
1116 if (clientsig[4] == 128)
1117 type = 8;
1119 else
1121 RTMP_Log(RTMP_LOGERROR, "%s: Unknown version %02x",
1122 __FUNCTION__, type);
1123 return FALSE;
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);
1136 if (FP9HandShake)
1138 /* Server version */
1139 serversig[4] = 3;
1140 serversig[5] = 5;
1141 serversig[6] = 1;
1142 serversig[7] = 1;
1144 getdig = digoff[offalg];
1145 getdh = dhoff[offalg];
1147 else
1149 memset(&serversig[4], 0, 4);
1152 /* generate random data */
1153 #ifdef _DEBUG
1154 memset(serversig+8, 0, RTMP_SIG_SIZE-8);
1155 #else
1156 ip = (int32_t *)(serversig+8);
1157 for (i = 2; i < RTMP_SIG_SIZE/4; i++)
1158 *ip++ = rand();
1159 #endif
1161 /* set handshake digest */
1162 if (FP9HandShake)
1164 if (encrypted)
1166 /* generate Diffie-Hellmann parameters */
1167 r->Link.dh = DHInit(1024);
1168 if (!r->Link.dh)
1170 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't initialize Diffie-Hellmann!",
1171 __FUNCTION__);
1172 return FALSE;
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!",
1181 __FUNCTION__);
1182 return FALSE;
1185 if (!DHGetPublicKey
1186 (r->Link.dh, (uint8_t *) &serversig[dhposServer], 128))
1188 RTMP_Log(RTMP_LOGERROR, "%s: Couldn't write public key!", __FUNCTION__);
1189 return FALSE;
1193 digestPosServer = getdig(serversig, RTMP_SIG_SIZE); /* reuse this value in verification */
1194 RTMP_Log(RTMP_LOGDEBUG, "%s: Server digest offset: %d", __FUNCTION__,
1195 digestPosServer);
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))
1209 return FALSE;
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]);
1219 if (FP9HandShake)
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!");
1230 offalg ^= 1;
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 */
1239 return FALSE;
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 */
1259 if (encrypted)
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__,
1267 dhposClient);
1268 len =
1269 DHComputeSharedSecretKey(r->Link.dh,
1270 (uint8_t *) &clientsig[dhposClient], 128,
1271 secretKey);
1272 if (len < 0)
1274 RTMP_Log(RTMP_LOGDEBUG, "%s: Wrong secret key position!", __FUNCTION__);
1275 return FALSE;
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],
1284 &keyIn, &keyOut);
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);
1295 #ifdef FP10
1296 if (type == 8 )
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);
1304 else if (type == 9)
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);
1312 #endif
1314 /* some info output */
1315 RTMP_Log(RTMP_LOGDEBUG,
1316 "%s: Calculated digest key from secure key and server digest: ",
1317 __FUNCTION__);
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);
1323 #if 0
1324 else
1326 uptime = htonl(RTMP_GetTime());
1327 memcpy(clientsig+4, &uptime, 4);
1329 #endif
1331 RTMP_Log(RTMP_LOGDEBUG2, "%s: Sending handshake response: ",
1332 __FUNCTION__);
1333 RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
1335 if (!WriteN(r, (char *)clientsig, RTMP_SIG_SIZE))
1336 return FALSE;
1338 /* 2nd part of handshake */
1339 if (ReadN(r, (char *)clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
1340 return FALSE;
1342 RTMP_Log(RTMP_LOGDEBUG2, "%s: 2nd handshake: ", __FUNCTION__);
1343 RTMP_LogHex(RTMP_LOGDEBUG2, clientsig, RTMP_SIG_SIZE);
1345 if (FP9HandShake)
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);
1359 #ifdef FP10
1360 if (type == 8 )
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);
1368 else if (type == 9)
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);
1376 #endif
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);
1384 if (memcmp
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__);
1389 return FALSE;
1391 else
1393 RTMP_Log(RTMP_LOGDEBUG, "%s: Genuine Adobe Flash Player", __FUNCTION__);
1396 if (encrypted)
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);
1415 else
1417 if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0)
1419 RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!",
1420 __FUNCTION__);
1424 RTMP_Log(RTMP_LOGDEBUG, "%s: Handshaking finished....", __FUNCTION__);
1425 return TRUE;