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