1/**
2 * \file mtpz.c
3 *
4 * Copyright (C) 2011-2012 Sajid Anwar <sajidanwar94@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 *
21 * This file provides mtp zune cryptographic setup interfaces.
22 * It is also used with Windows Phone 7, but Microsoft/Nokiad seem
23 * to have discontinued MTPZ on Windows Phone 8.
24 *
25 * DISCLAIMER:
26 *
27 * The intention of this implementation is for users to be able
28 * to interoperate with their devices, i.e. copy music to them in
29 * operating systems other than Microsoft Windows, so it can be
30 * played back on the device. We do not provide encryption keys
31 * and constants in libmtp, we never will. You have to have these
32 * on file in your home directory in $HOME/.mtpz-data, and we suggest
33 * that you talk to Microsoft about providing the proper numbers if
34 * you want to use this facility.
35 */
36#include "config.h"
37#include "libmtp.h"
38#include "unicode.h"
39#include "ptp.h"
40#include "libusb-glue.h"
41#include "device-flags.h"
42#include "playlist-spl.h"
43#include "util.h"
44#include "mtpz.h"
45
46#include <gcrypt.h>
47
48#include <stdlib.h>
49#include <unistd.h>
50#include <string.h>
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <time.h>
54#include <errno.h>
55
56
57/* Microsoft MTPZ extensions */
58
59/*
60 * The ~/.mtpz-data file contains all four necessary pieces of data:
61 *
62 *   encryption key
63 *   public exponent
64 *   modulus
65 *   private key
66 *   certificate data
67 *
68 * These four pieces of data are each stored in hex representation,
69 * separated by newline characters.
70 *
71 * If you know of a published, public reference for one of these
72 * arrays of data, please inform us, so we can include it here and
73 * drop it from the external file. Even better is if you convince
74 * Microsoft to officially provide keys to this project.
75 */
76
77static unsigned char *MTPZ_ENCRYPTION_KEY;
78static unsigned char *MTPZ_PUBLIC_EXPONENT;
79static unsigned char *MTPZ_MODULUS;
80static unsigned char *MTPZ_PRIVATE_KEY;
81static char *MTPZ_CERTIFICATES;
82
83// Strip the trailing newline from fgets().
84static char *fgets_strip(char * str, int num, FILE * stream)
85{
86	char *result = str;
87
88	if ((result = fgets(str, num, stream)))
89	{
90		size_t newlen = strlen(result);
91
92		if (result[newlen - 1] == '\n')
93			result[newlen - 1] = '\0';
94	}
95
96	return result;
97}
98
99static char *hex_to_bytes(char *hex, size_t len)
100{
101	if (len % 2)
102		return NULL;
103
104	char *bytes = malloc(len / 2);
105	unsigned int u;
106	int i = 0;
107
108	while (i < len && sscanf(hex + i, "%2x", &u) == 1)
109	{
110		bytes[i / 2] = u;
111		i += 2;
112	}
113
114	return bytes;
115}
116
117int mtpz_loaddata()
118{
119	char *home = getenv("HOME");
120	int ret = -1;
121	if (!home)
122	{
123		LIBMTP_ERROR("Unable to determine user's home directory, MTPZ disabled.\n");
124		return -1;
125	}
126
127	int plen = strlen(home) + strlen("/.mtpz-data") + 1;
128	char path[plen];
129	sprintf(path, "%s/.mtpz-data", home);
130
131	FILE *fdata = fopen(path, "r");
132	if (!fdata)
133		return ret;
134
135	// Should only be six characters in length, but fgets will encounter a newline and stop.
136	MTPZ_PUBLIC_EXPONENT = (unsigned char *)fgets_strip((char *)malloc(8), 8, fdata);
137	if (!MTPZ_PUBLIC_EXPONENT)
138	{
139		LIBMTP_ERROR("Unable to read MTPZ public exponent from ~/.mtpz-data, MTPZ disabled.\n");
140		goto cleanup;
141	}
142
143	// Should only be 33 characters in length, but fgets will encounter a newline and stop.
144	char *hexenckey = fgets_strip((char *)malloc(35), 35, fdata);
145	if (!hexenckey)
146	{
147		LIBMTP_ERROR("Unable to read MTPZ encryption key from ~/.mtpz-data, MTPZ disabled.\n");
148		goto cleanup;
149	}
150
151	MTPZ_ENCRYPTION_KEY = hex_to_bytes(hexenckey, strlen(hexenckey));
152	if (!MTPZ_ENCRYPTION_KEY)
153	{
154		LIBMTP_ERROR("Unable to read MTPZ encryption key from ~/.mtpz-data, MTPZ disabled.\n");
155		goto cleanup;
156	}
157
158	// Should only be 256 characters in length, but fgets will encounter a newline and stop.
159	MTPZ_MODULUS = (unsigned char *)fgets_strip((char *)malloc(260), 260, fdata);
160	if (!MTPZ_MODULUS)
161	{
162		LIBMTP_ERROR("Unable to read MTPZ modulus from ~/.mtpz-data, MTPZ disabled.\n");
163		goto cleanup;
164	}
165
166	// Should only be 256 characters in length, but fgets will encounter a newline and stop.
167	MTPZ_PRIVATE_KEY = (unsigned char *)fgets_strip((char *)malloc(260), 260, fdata);
168	if (!MTPZ_PRIVATE_KEY)
169	{
170		LIBMTP_ERROR("Unable to read MTPZ private key from ~/.mtpz-data, MTPZ disabled.\n");
171		goto cleanup;
172	}
173
174	// Should only be 1258 characters in length, but fgets will encounter the end of the file and stop.
175	char *hexcerts = fgets_strip((char *)malloc(1260), 1260, fdata);
176	if (!hexcerts)
177	{
178		LIBMTP_ERROR("Unable to read MTPZ certificates from ~/.mtpz-data, MTPZ disabled.\n");
179		goto cleanup;
180	}
181
182	MTPZ_CERTIFICATES = hex_to_bytes(hexcerts, strlen(hexcerts));
183	if (!MTPZ_CERTIFICATES)
184	{
185		LIBMTP_ERROR("Unable to parse MTPZ certificates from ~/.mtpz-data, MTPZ disabled.\n");
186		goto cleanup;
187	}
188	// If all done without errors, drop the fail
189	ret = 0;
190cleanup:
191	fclose(fdata);
192	return ret;
193}
194/* MTPZ RSA */
195
196typedef struct mtpz_rsa_struct
197{
198	gcry_sexp_t privkey;
199	gcry_sexp_t pubkey;
200} mtpz_rsa_t;
201
202mtpz_rsa_t *mtpz_rsa_init(const unsigned char *modulus, const unsigned char *priv_key, const unsigned char *pub_exp);
203void mtpz_rsa_free(mtpz_rsa_t *);
204int mtpz_rsa_decrypt(int flen, unsigned char *from, int tlen, unsigned char *to, mtpz_rsa_t *rsa);
205int mtpz_rsa_sign(int flen, unsigned char *from, int tlen, unsigned char *to, mtpz_rsa_t *rsa);
206
207/* MTPZ hashing */
208
209#define MTPZ_HASHSTATE_84 5
210#define MTPZ_HASHSTATE_88 6
211
212static char *mtpz_hash_init_state();
213static void mtpz_hash_reset_state(char *);
214static void mtpz_hash_transform_hash(char *, char *, int);
215static void mtpz_hash_finalize_hash(char *, char *);
216static char *mtpz_hash_custom6A5DC(char *, char *, int, int);
217
218static void mtpz_hash_compute_hash(char *, char *, int);
219static unsigned int mtpz_hash_f(int s, unsigned int x, unsigned int y, unsigned int z);
220static unsigned int mtpz_hash_rotate_left(unsigned int x, int n);
221
222/* MTPZ encryption */
223
224unsigned char mtpz_aes_rcon[];
225unsigned char mtpz_aes_sbox[];
226unsigned char mtpz_aes_invsbox[];
227unsigned int mtpz_aes_ft1[];
228unsigned int mtpz_aes_ft2[];
229unsigned int mtpz_aes_ft3[];
230unsigned int mtpz_aes_ft4[];
231unsigned int mtpz_aes_rt1[];
232unsigned int mtpz_aes_rt2[];
233unsigned int mtpz_aes_rt3[];
234unsigned int mtpz_aes_rt4[];
235unsigned int mtpz_aes_gb11[];
236unsigned int mtpz_aes_gb14[];
237unsigned int mtpz_aes_gb13[];
238unsigned int mtpz_aes_gb9[];
239
240#define MTPZ_ENCRYPTIONLOBYTE(val) (((val) >> 24) & 0xFF)
241#define MTPZ_ENCRYPTIONBYTE1(val) (((val) >> 16) & 0xFF)
242#define MTPZ_ENCRYPTIONBYTE2(val) (((val) >>  8) & 0xFF)
243#define MTPZ_ENCRYPTIONBYTE3(val) (((val) >>  0) & 0xFF)
244
245#define MTPZ_SWAP(x) mtpz_bswap32(x)
246
247void mtpz_encryption_cipher(unsigned char *data, unsigned int len, char encrypt);
248void mtpz_encryption_cipher_advanced(unsigned char *key, unsigned int key_len, unsigned char *data, unsigned int data_len, char encrypt);
249unsigned char *mtpz_encryption_expand_key(unsigned char *constant, int key_len, int count, int *out_len);
250void mtpz_encryption_expand_key_inner(unsigned char *constant, int key_len, unsigned char **out, int *out_len);
251void mtpz_encryption_inv_mix_columns(unsigned char *expanded, int offset, int rounds);
252void mtpz_encryption_decrypt_custom(unsigned char *data, unsigned char *seed, unsigned char *expanded);
253void mtpz_encryption_encrypt_custom(unsigned char *data, unsigned char *seed, unsigned char *expanded);
254void mtpz_encryption_encrypt_mac(unsigned char *hash, unsigned int hash_length, unsigned char *seed, unsigned int seed_len, unsigned char *out);
255
256
257static inline uint32_t mtpz_bswap32(uint32_t x)
258{
259#if defined __GNUC__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) || defined(__clang__)
260	return __builtin_bswap32(x);
261#else
262	return (x >> 24) |
263	       ((x >> 8) & 0x0000ff00) |
264	       ((x << 8) & 0x00ff0000) |
265	       (x << 24);
266#endif
267}
268
269
270/* MTPZ RSA implementation */
271mtpz_rsa_t *mtpz_rsa_init(const unsigned char *str_modulus, const unsigned char *str_privkey, const unsigned char *str_pubexp)
272{
273	mtpz_rsa_t *rsa = calloc(1, sizeof(mtpz_rsa_t));
274	if (rsa == NULL)
275		return NULL;
276
277	gcry_mpi_t mpi_modulus, mpi_privkey, mpi_pubexp;
278
279	gcry_mpi_scan(&mpi_modulus, GCRYMPI_FMT_HEX, str_modulus, 0, NULL);
280	gcry_mpi_scan(&mpi_privkey, GCRYMPI_FMT_HEX, str_privkey, 0, NULL);
281	gcry_mpi_scan(&mpi_pubexp, GCRYMPI_FMT_HEX, str_pubexp, 0, NULL);
282
283	gcry_sexp_build(&rsa->privkey, NULL, "(private-key (rsa (n %m) (e %m) (d %m)))", mpi_modulus, mpi_pubexp, mpi_privkey);
284	gcry_sexp_build(&rsa->pubkey, NULL, "(public-key (rsa (n %m) (e %m)))", mpi_modulus, mpi_pubexp);
285
286	gcry_mpi_release(mpi_modulus);
287	gcry_mpi_release(mpi_privkey);
288	gcry_mpi_release(mpi_pubexp);
289
290	return rsa;
291}
292
293void mtpz_rsa_free(mtpz_rsa_t *rsa)
294{
295	gcry_sexp_release(rsa->privkey);
296	gcry_sexp_release(rsa->pubkey);
297}
298
299int mtpz_rsa_decrypt(int flen, unsigned char *from, int tlen, unsigned char *to, mtpz_rsa_t *rsa)
300{
301	gcry_mpi_t mpi_from;
302	gcry_mpi_scan(&mpi_from, GCRYMPI_FMT_USG, from, flen, NULL);
303
304	gcry_sexp_t sexp_data;
305	gcry_sexp_build(&sexp_data, NULL, "(enc-val (flags raw) (rsa (a %m)))", mpi_from);
306
307	gcry_sexp_t sexp_plain;
308	gcry_pk_decrypt(&sexp_plain, sexp_data, rsa->privkey);
309
310	gcry_mpi_t mpi_value = gcry_sexp_nth_mpi(sexp_plain, 1, GCRYMPI_FMT_USG);
311
312	// Lame workaround. GCRYMPI_FMT_USG gets rid of any leading zeroes which we do need,
313	// so we'll count how many bits are being used, and subtract that from how many bits actually
314	// should be there, and then write into our output array shifted over however many bits/8.
315	int bitshift = (tlen * 8) - gcry_mpi_get_nbits(mpi_value);
316	size_t written;
317
318	if (bitshift / 8)
319	{
320		memset(to, 0, bitshift / 8);
321		to += bitshift / 8;
322		tlen -= bitshift / 8;
323	}
324
325	gcry_mpi_print(GCRYMPI_FMT_USG, to, tlen, &written, mpi_value);
326
327	gcry_mpi_release(mpi_from);
328	gcry_mpi_release(mpi_value);
329	gcry_sexp_release(sexp_data);
330	gcry_sexp_release(sexp_plain);
331
332	return (int)written;
333}
334
335int mtpz_rsa_sign(int flen, unsigned char *from, int tlen, unsigned char *to, mtpz_rsa_t *rsa)
336{
337	return mtpz_rsa_decrypt(flen, from, tlen, to, rsa);
338}
339
340/* MTPZ hashing implementation */
341
342static char *mtpz_hash_init_state()
343{
344	char *s = (char *)malloc(92);
345
346	if (s != NULL)
347		memset(s, 0, 92);
348
349	return s;
350}
351
352void mtpz_hash_reset_state(char *state)
353{
354	int *state_box = (int *)(state + 64);
355
356	/*
357	 * Constants from
358	 * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
359	 * Page 13, section 5.3.1
360	 */
361	state_box[0] = 0x67452301;
362	state_box[1] = 0xefcdab89;
363	state_box[2] = 0x98badcfe;
364	state_box[3] = 0x10325476;
365	state_box[4] = 0xc3d2e1f0;
366	state_box[MTPZ_HASHSTATE_84] = 0;
367	state_box[MTPZ_HASHSTATE_88] = 0;
368}
369
370void mtpz_hash_transform_hash(char *state, char *msg, int len)
371{
372	int *state_box = (int *)(state + 64);
373
374	int x = state_box[MTPZ_HASHSTATE_88] & 0x3F;
375	int v5 = len + state_box[MTPZ_HASHSTATE_88];
376	state_box[MTPZ_HASHSTATE_88] = v5;
377
378	int i = len, j = 0;
379	int a1 = 0;
380	int c = 0;
381
382	if (len > v5)
383		state_box[MTPZ_HASHSTATE_84] += 1;
384
385	if (x)
386	{
387		if (len + x > 0x3F)
388		{
389			for (a1 = 0; a1 < 64 - x; a1++)
390			{
391				state[x + a1] = msg[a1];
392			}
393
394			i = len + x - 64;
395			j = 64 - x;
396
397			mtpz_hash_compute_hash(state, state, 64);
398		}
399	}
400
401	while (i > 63)
402	{
403		mtpz_hash_compute_hash(state, msg + j, 64);
404		j += 64;
405		i -= 64;
406	}
407
408	if (i != 0)
409	{
410		for (c = 0; c < i; c++)
411		{
412			state[x + c] = msg[j + c];
413		}
414	}
415}
416
417// out has at least 20 bytes of space
418void mtpz_hash_finalize_hash(char *state, char *out)
419{
420	int *state_box = (int *)(state + 64);
421
422	int v2 = 64 - (state_box[MTPZ_HASHSTATE_88] & 0x3F);
423	int v6, v7;
424
425	if (v2 <= 8)
426		v2 += 64;
427
428	char *v5 = (char *)malloc(72);
429	memset(v5, 0, 72);
430
431	v5[0] = '\x80';
432	v6 = 8 * state_box[MTPZ_HASHSTATE_84] | (state_box[MTPZ_HASHSTATE_88] >> 29);
433	v7 = 8 * state_box[MTPZ_HASHSTATE_88];
434
435	v6 = MTPZ_SWAP(v6);
436	v7 = MTPZ_SWAP(v7);
437
438	*(int *)(v5 + v2 - 8) = v6;
439	*(int *)(v5 + v2 - 4) = v7;
440
441	mtpz_hash_transform_hash(state, v5, v2);
442
443	int *out_int = (int *)out;
444	out_int[0] = MTPZ_SWAP(state_box[0]);
445	out_int[1] = MTPZ_SWAP(state_box[1]);
446	out_int[2] = MTPZ_SWAP(state_box[2]);
447	out_int[3] = MTPZ_SWAP(state_box[3]);
448	out_int[4] = MTPZ_SWAP(state_box[4]);
449
450	memset(state, 0, 64);
451	mtpz_hash_reset_state(state);
452}
453
454char *mtpz_hash_custom6A5DC(char *state, char *msg, int len, int a4)
455{
456	int v11 = (a4 / 20) + 1;
457	char *v13 = (char *)malloc(v11 * 20);
458	char *v5 = (char *)malloc(len + 4);
459	int i;
460	int k;
461
462	memset(v13, 0, v11 * 20);
463	memset(v5, 0, len + 4);
464	memcpy(v5, msg, len);
465
466	for (i = 0; i < v11; i++)
467	{
468		k = MTPZ_SWAP(i);
469		*(int *)(v5 + len) = k;
470
471		mtpz_hash_reset_state(state);
472		mtpz_hash_transform_hash(state, v5, len + 4);
473		mtpz_hash_finalize_hash(state, v13 + i * 20);
474	}
475
476	free(v5); v5 = NULL;
477
478	return v13;
479}
480
481void mtpz_hash_compute_hash(char *state, char *msg, int len)
482{
483	int *state_box = (int *)(state + 64);
484
485	const unsigned int K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
486
487	if (len != 64)
488		return;
489
490	int *M = (int *)msg;
491
492	// HASH COMPUTATION
493	unsigned int W[80];
494	unsigned int a, b, c, d, e;
495	int i, s;
496	unsigned int T;
497
498	// 1 - prepare message schedule 'W'.
499	for (i = 0; i < 16; i++) W[i] = MTPZ_SWAP(M[i]);
500	for (i = 16; i < 80; i++) W[i] = mtpz_hash_rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
501
502	// 2 - initialize five working variables a, b, c, d, e with previous hash value
503	a = state_box[0];
504	b = state_box[1];
505	c = state_box[2];
506	d = state_box[3];
507	e = state_box[4];
508
509	// 3 - main loop
510	for (i = 0; i < 80; i++)
511	{
512		s = i / 20;
513		T = (mtpz_hash_rotate_left(a, 5) + mtpz_hash_f(s, b, c, d) + e + K[s] + W[i]) & 0xFFFFFFFF;
514		e = d;
515		d = c;
516		c = mtpz_hash_rotate_left(b, 30);
517		b = a;
518		a = T;
519	}
520
521	state_box[0] = (state_box[0] + a) & 0xFFFFFFFF;
522	state_box[1] = (state_box[1] + b) & 0xFFFFFFFF;
523	state_box[2] = (state_box[2] + c) & 0xFFFFFFFF;
524	state_box[3] = (state_box[3] + d) & 0xFFFFFFFF;
525	state_box[4] = (state_box[4] + e) & 0xFFFFFFFF;
526}
527
528unsigned int mtpz_hash_f(int s, unsigned int x, unsigned int y, unsigned int z)
529{
530	switch (s)
531	{
532	case 0:
533		return (x & y) ^ (~x & z); // Ch()
534	case 1:
535		return x ^ y ^ z; // Parity()
536	case 2:
537		return (x & y) ^ (x & z) ^ (y & z); // Maj()
538	case 3:
539		return x ^ y ^ z; // Parity()
540	}
541
542	return 0;
543}
544
545unsigned int mtpz_hash_rotate_left(unsigned int x, int n)
546{
547	return (x << n) | (x >> (32 - n));
548}
549
550/* MTPZ encryption implementation */
551
552void mtpz_encryption_cipher(unsigned char *data, unsigned int len, char encrypt)
553{
554	unsigned char *expanded = NULL;
555
556	int offset = 0, count = len;
557
558	if ((count & 0x0F) == 0)
559	{
560		int exp_len = 0;
561		expanded = mtpz_encryption_expand_key((unsigned char *)MTPZ_ENCRYPTION_KEY, 16, 10, &exp_len);
562
563		if (count != 0)
564		{
565			do
566			{
567				if (encrypt)
568					mtpz_encryption_encrypt_custom(data + offset, NULL, expanded);
569				else
570					mtpz_encryption_decrypt_custom(data + offset, NULL, expanded);
571
572				count -= 16;
573				offset += 16;
574			}
575			while (count != 0);
576		}
577	}
578}
579
580void mtpz_encryption_cipher_advanced(unsigned char *key, unsigned int key_len, unsigned char *data, unsigned int data_len, char encrypt)
581{
582	int len = (key_len == 16) ? 10 :
583			  (key_len == 24) ? 12 : 32;
584	int exp_len;
585	unsigned char *expanded = mtpz_encryption_expand_key(key, key_len, len, &exp_len);
586
587	int offset = 0, count = data_len;
588	unsigned char *out = (unsigned char *)malloc(16);
589	unsigned int *out_int = (unsigned int *)out;
590	unsigned int *data_int = (unsigned int *)data;
591	unsigned int *dtf = (unsigned int *)malloc(16);
592	memset((unsigned char *)dtf, 0, 16);
593
594	while (count != 0)
595	{
596		int chunk = 16;
597
598		if (count < 16)
599		{
600			memset(out, 0, 16);
601			chunk = count;
602		}
603
604		memcpy(out, data + offset, chunk);
605
606		if (encrypt)
607		{
608			out_int[0] ^= MTPZ_SWAP(dtf[0]);
609			out_int[1] ^= MTPZ_SWAP(dtf[1]);
610			out_int[2] ^= MTPZ_SWAP(dtf[2]);
611			out_int[3] ^= MTPZ_SWAP(dtf[3]);
612
613			mtpz_encryption_encrypt_custom(data + offset, out, expanded);
614
615			dtf[0] = MTPZ_SWAP(data_int[(offset / 4) + 0]);
616            dtf[1] = MTPZ_SWAP(data_int[(offset / 4) + 1]);
617            dtf[2] = MTPZ_SWAP(data_int[(offset / 4) + 2]);
618            dtf[3] = MTPZ_SWAP(data_int[(offset / 4) + 3]);
619		}
620		else
621		{
622			mtpz_encryption_decrypt_custom(data + offset, out, expanded);
623
624			data_int[(offset / 4) + 0] ^= MTPZ_SWAP(dtf[0]);
625			data_int[(offset / 4) + 1] ^= MTPZ_SWAP(dtf[1]);
626			data_int[(offset / 4) + 2] ^= MTPZ_SWAP(dtf[2]);
627			data_int[(offset / 4) + 3] ^= MTPZ_SWAP(dtf[3]);
628
629			dtf[0] = MTPZ_SWAP(out_int[0]);
630			dtf[1] = MTPZ_SWAP(out_int[1]);
631			dtf[2] = MTPZ_SWAP(out_int[2]);
632			dtf[3] = MTPZ_SWAP(out_int[3]);
633		}
634
635		offset += chunk;
636		count -= chunk;
637	}
638
639	free(out);
640	free(dtf);
641	free(expanded);
642}
643
644unsigned char *mtpz_encryption_expand_key(unsigned char *constant, int key_len, int count, int *out_len)
645{
646	int i = 0;
647	int seek = 0;
648	unsigned char *back = (unsigned char *)malloc(484);
649	memset(back, 0, 484);
650	*out_len = 484;
651
652	unsigned char *inner;
653	int inner_len;
654	mtpz_encryption_expand_key_inner(constant, key_len, &inner, &inner_len);
655
656	back[i] = (unsigned char)(count % 0xFF);
657	i += 4;
658
659	memcpy(back + i, inner, inner_len);
660	i += inner_len;
661	memcpy(back + i, inner, inner_len);
662	i += inner_len;
663
664	switch (count)
665	{
666	case 10:
667		seek = 0xB4;
668		break;
669
670	case 12:
671		seek = 0xD4;
672		break;
673
674	case 14:
675	default:
676		seek = 0xF4;
677		break;
678	}
679
680	mtpz_encryption_inv_mix_columns(back, seek, count);
681
682	return back;
683}
684
685void mtpz_encryption_expand_key_inner(unsigned char *constant, int key_len, unsigned char **out, int *out_len)
686{
687	int ks = -1;
688	int rcon_i = 0;
689	int i = 0, j = 0;
690
691	switch (key_len)
692	{
693	case 16:
694		ks = 16 * (10 + 1);
695		break;
696
697	case 24:
698		ks = 16 * (12 + 1);
699		break;
700
701	case 32:
702		ks = 16 * (14 + 1);
703		break;
704
705	default:
706		*out = NULL;
707		*out_len = 0;
708		return;
709	}
710
711	unsigned char *key = (unsigned char *)malloc(ks);
712	unsigned char *temp = (unsigned char *)malloc(4);
713	memcpy(key, constant, key_len);
714	unsigned char t0, t1, t2, t3;
715
716	for (i = key_len; i < ks; i += 4)
717	{
718		temp[0] = t0 = key[i - 4];
719		temp[1] = t1 = key[i - 3];
720		temp[2] = t2 = key[i - 2];
721		temp[3] = t3 = key[i - 1];
722
723		if (i % key_len == 0)
724		{
725			temp[0] = (mtpz_aes_sbox[t1] ^ mtpz_aes_rcon[rcon_i]) & 0xFF;
726			temp[1] = mtpz_aes_sbox[t2];
727			temp[2] = mtpz_aes_sbox[t3];
728			temp[3] = mtpz_aes_sbox[t0];
729			rcon_i++;
730		}
731		else if ((key_len > 24) && (i % key_len == 16))
732		{
733			temp[0] = mtpz_aes_sbox[t0];
734			temp[1] = mtpz_aes_sbox[t1];
735			temp[2] = mtpz_aes_sbox[t2];
736			temp[3] = mtpz_aes_sbox[t3];
737		}
738
739		for (j = 0; j < 4; j++)
740		{
741			key[i + j] = (unsigned char)((key[i + j - key_len] ^ temp[j]) & 0xFF);
742		}
743	}
744
745	free(temp);
746
747	*out = key;
748	*out_len = ks;
749}
750
751void mtpz_encryption_inv_mix_columns(unsigned char *expanded, int offset, int rounds)
752{
753	int v8 = 1, o = offset;
754	unsigned int *exp_int = NULL;
755
756	for (v8 = 1; v8 < rounds; v8++)
757	{
758		exp_int = (unsigned int *)(expanded + o + 16);
759
760		exp_int[0] = MTPZ_SWAP(mtpz_aes_gb9[expanded[o + 19]] ^ mtpz_aes_gb13[expanded[o + 18]] ^ mtpz_aes_gb11[expanded[o + 17]] ^ mtpz_aes_gb14[expanded[o + 16]]);
761		exp_int[1] = MTPZ_SWAP(mtpz_aes_gb9[expanded[o + 23]] ^ mtpz_aes_gb13[expanded[o + 22]] ^ mtpz_aes_gb11[expanded[o + 21]] ^ mtpz_aes_gb14[expanded[o + 20]]);
762		exp_int[2] = MTPZ_SWAP(mtpz_aes_gb9[expanded[o + 27]] ^ mtpz_aes_gb13[expanded[o + 26]] ^ mtpz_aes_gb11[expanded[o + 25]] ^ mtpz_aes_gb14[expanded[o + 24]]);
763		exp_int[3] = MTPZ_SWAP(mtpz_aes_gb9[expanded[o + 31]] ^ mtpz_aes_gb13[expanded[o + 30]] ^ mtpz_aes_gb11[expanded[o + 29]] ^ mtpz_aes_gb14[expanded[o + 28]]);
764		o += 16;
765	}
766}
767
768void mtpz_encryption_decrypt_custom(unsigned char *data, unsigned char *seed, unsigned char *expanded)
769{
770	unsigned int *u_data = (unsigned int *)data;
771	unsigned int *u_expanded = (unsigned int *)expanded;
772	int keyOffset = 0xB4 + 0xA0;
773
774	unsigned int *u_seed;
775
776	if (seed == NULL)
777		u_seed = u_data;
778	else
779		u_seed = (unsigned int *)seed;
780
781	unsigned int v14 = MTPZ_SWAP(u_seed[0]) ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]);
782	unsigned int v15 = MTPZ_SWAP(u_seed[1]) ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]);
783	unsigned int v16 = MTPZ_SWAP(u_seed[2]) ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]);
784	unsigned int v17 = MTPZ_SWAP(u_seed[3]) ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]);
785
786	unsigned int v18 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v15)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v16)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v14)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v17)];
787	unsigned int v19 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v16)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v17)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v15)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v14)];
788	unsigned int v20 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v17)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v14)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v16)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v15)];
789	unsigned int v21 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v14)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v15)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v17)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v16)];
790
791	keyOffset -= 16;
792	int rounds = 9;
793
794	do
795	{
796		v14 = v18 ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]);
797		v15 = v19 ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]);
798		v16 = v20 ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]);
799		v17 = v21 ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]);
800
801		v18 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v15)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v16)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v14)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v17)];
802		v19 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v16)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v17)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v15)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v14)];
803		v20 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v17)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v14)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v16)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v15)];
804		v21 = mtpz_aes_rt1[MTPZ_ENCRYPTIONBYTE3(v14)] ^ mtpz_aes_rt2[MTPZ_ENCRYPTIONBYTE2(v15)] ^ mtpz_aes_rt3[MTPZ_ENCRYPTIONLOBYTE(v17)] ^ mtpz_aes_rt4[MTPZ_ENCRYPTIONBYTE1(v16)];
805
806		rounds--;
807		keyOffset -= 16;
808	}
809	while (rounds != 1);
810
811	v14 = v18 ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]);
812	v15 = v19 ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]);
813	v16 = v20 ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]);
814	v17 = v21 ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]);
815	keyOffset -= 16;
816
817	v18 = ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONLOBYTE(v14)]) << 24) |
818		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE1 (v17)]) << 16) |
819		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE2 (v16)]) <<  8) |
820		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE3 (v15)]) <<  0);
821
822	v19 = ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONLOBYTE(v15)]) << 24) |
823		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE1 (v14)]) << 16) |
824		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE2 (v17)]) <<  8) |
825		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE3 (v16)]) <<  0);
826
827	v20 = ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONLOBYTE(v16)]) << 24) |
828		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE1 (v15)]) << 16) |
829		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE2 (v14)]) <<  8) |
830		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE3 (v17)]) <<  0);
831
832	v21 = ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONLOBYTE(v17)]) << 24) |
833		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE1 (v16)]) << 16) |
834		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE2 (v15)]) <<  8) |
835		  ((mtpz_aes_invsbox[MTPZ_ENCRYPTIONBYTE3 (v14)]) <<  0);
836
837	u_data[0] = MTPZ_SWAP(v18 ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]));
838	u_data[1] = MTPZ_SWAP(v19 ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]));
839	u_data[2] = MTPZ_SWAP(v20 ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]));
840	u_data[3] = MTPZ_SWAP(v21 ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]));
841};
842
843void mtpz_encryption_encrypt_custom(unsigned char *data, unsigned char *seed, unsigned char *expanded)
844{
845	unsigned int *u_data = (unsigned int *)data;
846	unsigned int *u_expanded = (unsigned int *)expanded;
847	int keyOffset = 0x04;
848
849	unsigned int *u_seed;
850
851	if (seed == NULL)
852		u_seed = u_data;
853	else
854		u_seed = (unsigned int *)seed;
855
856	unsigned int v14 = MTPZ_SWAP(u_seed[0]) ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]);
857	unsigned int v15 = MTPZ_SWAP(u_seed[1]) ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]);
858	unsigned int v16 = MTPZ_SWAP(u_seed[2]) ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]);
859	unsigned int v17 = MTPZ_SWAP(u_seed[3]) ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]);
860
861	unsigned int v18 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v17)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v16)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v14)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v15)];
862	unsigned int v19 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v14)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v17)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v15)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v16)];
863	unsigned int v20 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v15)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v14)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v16)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v17)];
864	unsigned int v21 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v16)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v15)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v17)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v14)];
865
866	keyOffset += 16;
867	int rounds = 1;
868
869	do
870	{
871
872		v14 = v18 ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]);
873		v15 = v19 ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]);
874		v16 = v20 ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]);
875		v17 = v21 ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]);
876
877		v18 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v17)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v16)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v14)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v15)];
878		v19 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v14)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v17)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v15)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v16)];
879		v20 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v15)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v14)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v16)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v17)];
880		v21 = mtpz_aes_ft1[MTPZ_ENCRYPTIONBYTE3(v16)] ^ mtpz_aes_ft2[MTPZ_ENCRYPTIONBYTE2(v15)] ^ mtpz_aes_ft3[MTPZ_ENCRYPTIONLOBYTE(v17)] ^ mtpz_aes_ft4[MTPZ_ENCRYPTIONBYTE1(v14)];
881
882		rounds++;
883		keyOffset += 16;
884	}
885	while (rounds != 9);
886
887	v14 = v18 ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]);
888	v15 = v19 ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]);
889	v16 = v20 ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]);
890	v17 = v21 ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]);
891	keyOffset += 16;
892
893	unsigned char *FT3_Bytes = (unsigned char *)mtpz_aes_ft3;
894
895	v18 = ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONLOBYTE(v14)]) << 24) |
896		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE1 (v15)]) << 16) |
897		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE2 (v16)]) <<  8) |
898		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE3 (v17)]) <<  0);
899
900	v19 = ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONLOBYTE(v15)]) << 24) |
901		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE1 (v16)]) << 16) |
902		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE2 (v17)]) <<  8) |
903		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE3 (v14)]) <<  0);
904
905	v20 = ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONLOBYTE(v16)]) << 24) |
906		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE1 (v17)]) << 16) |
907		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE2 (v14)]) <<  8) |
908		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE3 (v15)]) <<  0);
909
910	v21 = ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONLOBYTE(v17)]) << 24) |
911		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE1 (v14)]) << 16) |
912		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE2 (v15)]) <<  8) |
913		  ((FT3_Bytes[1 + 4 * MTPZ_ENCRYPTIONBYTE3 (v16)]) <<  0);
914
915	u_data[0] = MTPZ_SWAP(v18 ^ MTPZ_SWAP(u_expanded[(keyOffset     ) / 4]));
916	u_data[1] = MTPZ_SWAP(v19 ^ MTPZ_SWAP(u_expanded[(keyOffset +  4) / 4]));
917	u_data[2] = MTPZ_SWAP(v20 ^ MTPZ_SWAP(u_expanded[(keyOffset +  8) / 4]));
918	u_data[3] = MTPZ_SWAP(v21 ^ MTPZ_SWAP(u_expanded[(keyOffset + 12) / 4]));
919}
920
921void mtpz_encryption_encrypt_mac(unsigned char *hash, unsigned int hash_length, unsigned char *seed, unsigned int seed_len, unsigned char *out)
922{
923	if (hash == NULL || hash_length != 16)
924		return;
925
926	unsigned char *loop1 = (unsigned char *)malloc(17);
927	memset(loop1, 0, 17);
928	unsigned char *loop2 = (unsigned char *)malloc(17);
929	memset(loop2, 0, 17);
930	int i = 0;
931
932	{
933		unsigned char *enc_hash = (unsigned char *)malloc(17);
934		memset(enc_hash, 0, 17);
935		mtpz_encryption_cipher_advanced(hash, hash_length, enc_hash, 16, 1);
936
937		for (i = 0; i < 16; i++)
938			loop1[i] = (unsigned char)((2 * enc_hash[i]) | (enc_hash[i + 1] >> 7));
939
940		if (enc_hash[0] >= (unsigned char)128)
941			loop1[15] ^= (unsigned char)0x87;
942
943		for (i = 0; i < 16; i++)
944			loop2[i] = (unsigned char)((2 * loop1[i]) | (loop1[i + 1] >> 7));
945
946		if (loop1[0] >= (unsigned char)128)
947			loop2[15] ^= (unsigned char)0x87;
948
949		free(enc_hash);
950	}
951
952	{
953		int len = 	(hash_length == 16) ? 10 :
954					(hash_length == 24) ? 12 : 32;
955		int exp_len;
956		unsigned char *expanded = mtpz_encryption_expand_key(hash, hash_length, len, &exp_len);
957
958		unsigned char *actual_seed = (unsigned char *)malloc(16);
959		memset(actual_seed, 0, 16);
960
961		int i = 0;
962
963		if (seed_len == 16)
964		{
965			for (i = 0; i < 16; i++)
966				actual_seed[i] ^= seed[i];
967
968			for (i = 0; i < 16; i++)
969				actual_seed[i] ^= loop1[i];
970		}
971		else
972		{
973			for (i = 0; i < seed_len; i++)
974				actual_seed[i] ^= seed[i];
975
976			actual_seed[seed_len] = (unsigned char)128;
977
978			for (i = 0; i < 16; i++)
979				actual_seed[i] ^= loop2[i];
980		}
981
982		mtpz_encryption_encrypt_custom(out, actual_seed, expanded);
983
984		free(expanded);
985		free(actual_seed);
986	}
987
988	free(loop1);
989	free(loop2);
990}
991
992
993/* ENCRYPTION CONSTANTS */
994/*
995 * These tables can also be found in Mozilla's Network Security Services:
996 *     http://www.mozilla.org/projects/security/pki/nss/
997 *
998 * <rijndael32.tab>:
999 *     https://hg.mozilla.org/mozilla-central/raw-file/90828ac18dcf/security/nss/lib/freebl/rijndael32.tab
1000 *
1001 * Each of the following constant tables will also identify the corresponding
1002 * table in the <rijndael32.tab> link.
1003 */
1004
1005/* Corresponds to Rcon[30] (seems to be truncated to include only the used constants) */
1006unsigned char mtpz_aes_rcon[] =
1007{
1008	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a
1009};
1010
1011/* Corresponds to _S[256] (in hex) */
1012unsigned char mtpz_aes_sbox[] =
1013{
1014	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01,
1015	0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d,
1016	0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4,
1017	0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
1018	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7,
1019	0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
1020	0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e,
1021	0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
1022	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
1023	0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb,
1024	0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
1025	0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
1026	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
1027	0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d,
1028	0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a,
1029	0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
1030	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3,
1031	0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
1032	0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a,
1033	0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
1034	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e,
1035	0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
1036	0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9,
1037	0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
1038	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99,
1039	0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
1040};
1041
1042/* Corresponds to _SInv[256] (in hex) */
1043unsigned char mtpz_aes_invsbox[] =
1044{
1045	0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,  0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
1046	0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,  0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
1047	0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,  0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
1048	0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,  0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
1049	0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,  0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
1050	0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,  0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
1051	0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,  0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
1052	0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,  0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
1053	0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,  0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
1054	0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,  0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
1055	0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,  0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
1056	0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,  0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
1057	0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,  0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
1058	0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,  0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1059	0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,  0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1060	0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,  0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1061};
1062
1063/* Corresponds to _T3[256] */
1064unsigned int mtpz_aes_ft1[] =
1065{
1066	0x6363A5C6, 0x7C7C84F8,  0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6,  0x6F6FB1DE, 0xC5C55491,
1067	0x30305060, 0x01010302,  0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5,  0xABABE64D, 0x76769AEC,
1068	0xCACA458F, 0x82829D1F,  0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2,  0x4747C98E, 0xF0F00BFB,
1069	0xADADEC41, 0xD4D467B3,  0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753,  0x727296E4, 0xC0C05B9B,
1070	0xB7B7C275, 0xFDFD1CE1,  0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E,  0xF7F702F5, 0xCCCC4F83,
1071	0x34345C68, 0xA5A5F451,  0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB,  0x31315362, 0x15153F2A,
1072	0x04040C08, 0xC7C75295,  0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137,  0x05050F0A, 0x9A9AB52F,
1073	0x0707090E, 0x12123624,  0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E,  0xB2B2CD7F, 0x75759FEA,
1074	0x09091B12, 0x83839E1D,  0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC,  0x5A5AEEB4, 0xA0A0FB5B,
1075	0x5252F6A4, 0x3B3B4D76,  0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD,  0x2F2F715E, 0x84849713,
1076	0x5353F5A6, 0xD1D168B9,  0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3,  0xB1B1C879, 0x5B5BEDB6,
1077	0x6A6ABED4, 0xCBCB468D,  0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498,  0x5858E8B0, 0xCFCF4A85,
1078	0xD0D06BBB, 0xEFEF2AC5,  0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A,  0x33335566, 0x85859411,
1079	0x4545CF8A, 0xF9F910E9,  0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478,  0x9F9FBA25, 0xA8A8E34B,
1080	0x5151F3A2, 0xA3A3FE5D,  0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21,  0x38384870, 0xF5F504F1,
1081	0xBCBCDF63, 0xB6B6C177,  0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5,  0xF3F30EFD, 0xD2D26DBF,
1082	0xCDCD4C81, 0x0C0C1418,  0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235,  0x4444CC88, 0x1717392E,
1083	0xC4C45793, 0xA7A7F255,  0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA,  0x19192B32, 0x737395E6,
1084	0x6060A0C0, 0x81819819,  0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54,  0x9090AB3B, 0x8888830B,
1085	0x4646CA8C, 0xEEEE29C7,  0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC,  0x0B0B1D16, 0xDBDB76AD,
1086	0xE0E03BDB, 0x32325664,  0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C,  0x24246C48, 0x5C5CE4B8,
1087	0xC2C25D9F, 0xD3D36EBD,  0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431,  0xE4E437D3, 0x79798BF2,
1088	0xE7E732D5, 0xC8C8438B,  0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1,  0x4E4ED29C, 0xA9A9E049,
1089	0x6C6CB4D8, 0x5656FAAC,  0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4,  0xAEAEE947, 0x08081810,
1090	0xBABAD56F, 0x787888F0,  0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157,  0xB4B4C773, 0xC6C65197,
1091	0xE8E823CB, 0xDDDD7CA1,  0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61,  0x8B8B860D, 0x8A8A850F,
1092	0x707090E0, 0x3E3E427C,  0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506,  0xF6F601F7, 0x0E0E121C,
1093	0x6161A3C2, 0x35355F6A,  0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899,  0x1D1D273A, 0x9E9EB927,
1094	0xE1E138D9, 0xF8F813EB,  0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9,  0x8E8E8907, 0x9494A733,
1095	0x9B9BB62D, 0x1E1E223C,  0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA,  0x28287850, 0xDFDF7AA5,
1096	0x8C8C8F03, 0xA1A1F859,  0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7,  0x4242C684, 0x6868B8D0,
1097	0x4141C382, 0x9999B029,  0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8,  0xBBBBD66D, 0x16163A2C,
1098};
1099
1100/* Corresponds to _T2[256] */
1101unsigned int mtpz_aes_ft2[] =
1102{
1103	0x63A5C663, 0x7C84F87C,  0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B,  0x6FB1DE6F, 0xC55491C5,
1104	0x30506030, 0x01030201,  0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7,  0xABE64DAB, 0x769AEC76,
1105	0xCA458FCA, 0x829D1F82,  0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259,  0x47C98E47, 0xF00BFBF0,
1106	0xADEC41AD, 0xD467B3D4,  0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4,  0x7296E472, 0xC05B9BC0,
1107	0xB7C275B7, 0xFD1CE1FD,  0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F,  0xF702F5F7, 0xCC4F83CC,
1108	0x345C6834, 0xA5F451A5,  0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8,  0x31536231, 0x153F2A15,
1109	0x040C0804, 0xC75295C7,  0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796,  0x050F0A05, 0x9AB52F9A,
1110	0x07090E07, 0x12362412,  0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27,  0xB2CD7FB2, 0x759FEA75,
1111	0x091B1209, 0x839E1D83,  0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E,  0x5AEEB45A, 0xA0FB5BA0,
1112	0x52F6A452, 0x3B4D763B,  0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3,  0x2F715E2F, 0x84971384,
1113	0x53F5A653, 0xD168B9D1,  0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC,  0xB1C879B1, 0x5BEDB65B,
1114	0x6ABED46A, 0xCB468DCB,  0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C,  0x58E8B058, 0xCF4A85CF,
1115	0xD06BBBD0, 0xEF2AC5EF,  0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D,  0x33556633, 0x85941185,
1116	0x45CF8A45, 0xF910E9F9,  0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C,  0x9FBA259F, 0xA8E34BA8,
1117	0x51F3A251, 0xA3FE5DA3,  0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D,  0x38487038, 0xF504F1F5,
1118	0xBCDF63BC, 0xB6C177B6,  0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF,  0xF30EFDF3, 0xD26DBFD2,
1119	0xCD4C81CD, 0x0C14180C,  0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597,  0x44CC8844, 0x17392E17,
1120	0xC45793C4, 0xA7F255A7,  0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D,  0x192B3219, 0x7395E673,
1121	0x60A0C060, 0x81981981,  0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A,  0x90AB3B90, 0x88830B88,
1122	0x46CA8C46, 0xEE29C7EE,  0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E,  0x0B1D160B, 0xDB76ADDB,
1123	0xE03BDBE0, 0x32566432,  0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06,  0x246C4824, 0x5CE4B85C,
1124	0xC25D9FC2, 0xD36EBDD3,  0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195,  0xE437D3E4, 0x798BF279,
1125	0xE732D5E7, 0xC8438BC8,  0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5,  0x4ED29C4E, 0xA9E049A9,
1126	0x6CB4D86C, 0x56FAAC56,  0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A,  0xAEE947AE, 0x08181008,
1127	0xBAD56FBA, 0x7888F078,  0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6,  0xB4C773B4, 0xC65197C6,
1128	0xE823CBE8, 0xDD7CA1DD,  0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD,  0x8B860D8B, 0x8A850F8A,
1129	0x7090E070, 0x3E427C3E,  0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603,  0xF601F7F6, 0x0E121C0E,
1130	0x61A3C261, 0x355F6A35,  0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1,  0x1D273A1D, 0x9EB9279E,
1131	0xE138D9E1, 0xF813EBF8,  0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9,  0x8E89078E, 0x94A73394,
1132	0x9BB62D9B, 0x1E223C1E,  0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55,  0x28785028, 0xDF7AA5DF,
1133	0x8C8F038C, 0xA1F859A1,  0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6,  0x42C68442, 0x68B8D068,
1134	0x41C38241, 0x99B02999,  0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854,  0xBBD66DBB, 0x163A2C16,
1135};
1136
1137/* Corresponds to _T0[256] */
1138unsigned int mtpz_aes_ft3[] =
1139{
1140	0xC66363A5, 0xF87C7C84,  0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD,  0xDE6F6FB1, 0x91C5C554,
1141	0x60303050, 0x02010103,  0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762,  0x4DABABE6, 0xEC76769A,
1142	0x8FCACA45, 0x1F82829D,  0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB,  0x8E4747C9, 0xFBF0F00B,
1143	0x41ADADEC, 0xB3D4D467,  0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7,  0xE4727296, 0x9BC0C05B,
1144	0x75B7B7C2, 0xE1FDFD1C,  0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41,  0xF5F7F702, 0x83CCCC4F,
1145	0x6834345C, 0x51A5A5F4,  0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873,  0x62313153, 0x2A15153F,
1146	0x0804040C, 0x95C7C752,  0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1,  0x0A05050F, 0x2F9A9AB5,
1147	0x0E070709, 0x24121236,  0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769,  0x7FB2B2CD, 0xEA75759F,
1148	0x1209091B, 0x1D83839E,  0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2,  0xB45A5AEE, 0x5BA0A0FB,
1149	0xA45252F6, 0x763B3B4D,  0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E,  0x5E2F2F71, 0x13848497,
1150	0xA65353F5, 0xB9D1D168,  0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F,  0x79B1B1C8, 0xB65B5BED,
1151	0xD46A6ABE, 0x8DCBCB46,  0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4,  0xB05858E8, 0x85CFCF4A,
1152	0xBBD0D06B, 0xC5EFEF2A,  0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7,  0x66333355, 0x11858594,
1153	0x8A4545CF, 0xE9F9F910,  0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44,  0x259F9FBA, 0x4BA8A8E3,
1154	0xA25151F3, 0x5DA3A3FE,  0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC,  0x70383848, 0xF1F5F504,
1155	0x63BCBCDF, 0x77B6B6C1,  0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A,  0xFDF3F30E, 0xBFD2D26D,
1156	0x81CDCD4C, 0x180C0C14,  0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2,  0x884444CC, 0x2E171739,
1157	0x93C4C457, 0x55A7A7F2,  0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7,  0x3219192B, 0xE6737395,
1158	0xC06060A0, 0x19818198,  0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E,  0x3B9090AB, 0x0B888883,
1159	0x8C4646CA, 0xC7EEEE29,  0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2,  0x160B0B1D, 0xADDBDB76,
1160	0xDBE0E03B, 0x64323256,  0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A,  0x4824246C, 0xB85C5CE4,
1161	0x9FC2C25D, 0xBDD3D36E,  0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4,  0xD3E4E437, 0xF279798B,
1162	0xD5E7E732, 0x8BC8C843,  0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564,  0x9C4E4ED2, 0x49A9A9E0,
1163	0xD86C6CB4, 0xAC5656FA,  0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E,  0x47AEAEE9, 0x10080818,
1164	0x6FBABAD5, 0xF0787888,  0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1,  0x73B4B4C7, 0x97C6C651,
1165	0xCBE8E823, 0xA1DDDD7C,  0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC,  0x0D8B8B86, 0x0F8A8A85,
1166	0xE0707090, 0x7C3E3E42,  0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305,  0xF7F6F601, 0x1C0E0E12,
1167	0xC26161A3, 0x6A35355F,  0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158,  0x3A1D1D27, 0x279E9EB9,
1168	0xD9E1E138, 0xEBF8F813,  0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970,  0x078E8E89, 0x339494A7,
1169	0x2D9B9BB6, 0x3C1E1E22,  0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF,  0x50282878, 0xA5DFDF7A,
1170	0x038C8C8F, 0x59A1A1F8,  0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631,  0x844242C6, 0xD06868B8,
1171	0x824141C3, 0x299999B0,  0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC,  0x6DBBBBD6, 0x2C16163A,
1172};
1173
1174/* Corresponds to _T1[256] */
1175unsigned int mtpz_aes_ft4[] =
1176{
1177	0xA5C66363, 0x84F87C7C,  0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B,  0xB1DE6F6F, 0x5491C5C5,
1178	0x50603030, 0x03020101,  0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7,  0xE64DABAB, 0x9AEC7676,
1179	0x458FCACA, 0x9D1F8282,  0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959,  0xC98E4747, 0x0BFBF0F0,
1180	0xEC41ADAD, 0x67B3D4D4,  0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4,  0x96E47272, 0x5B9BC0C0,
1181	0xC275B7B7, 0x1CE1FDFD,  0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F,  0x02F5F7F7, 0x4F83CCCC,
1182	0x5C683434, 0xF451A5A5,  0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8,  0x53623131, 0x3F2A1515,
1183	0x0C080404, 0x5295C7C7,  0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696,  0x0F0A0505, 0xB52F9A9A,
1184	0x090E0707, 0x36241212,  0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727,  0xCD7FB2B2, 0x9FEA7575,
1185	0x1B120909, 0x9E1D8383,  0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E,  0xEEB45A5A, 0xFB5BA0A0,
1186	0xF6A45252, 0x4D763B3B,  0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3,  0x715E2F2F, 0x97138484,
1187	0xF5A65353, 0x68B9D1D1,  0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC,  0xC879B1B1, 0xEDB65B5B,
1188	0xBED46A6A, 0x468DCBCB,  0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C,  0xE8B05858, 0x4A85CFCF,
1189	0x6BBBD0D0, 0x2AC5EFEF,  0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D,  0x55663333, 0x94118585,
1190	0xCF8A4545, 0x10E9F9F9,  0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C,  0xBA259F9F, 0xE34BA8A8,
1191	0xF3A25151, 0xFE5DA3A3,  0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D,  0x48703838, 0x04F1F5F5,
1192	0xDF63BCBC, 0xC177B6B6,  0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF,  0x0EFDF3F3, 0x6DBFD2D2,
1193	0x4C81CDCD, 0x14180C0C,  0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797,  0xCC884444, 0x392E1717,
1194	0x5793C4C4, 0xF255A7A7,  0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D,  0x2B321919, 0x95E67373,
1195	0xA0C06060, 0x98198181,  0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A,  0xAB3B9090, 0x830B8888,
1196	0xCA8C4646, 0x29C7EEEE,  0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E,  0x1D160B0B, 0x76ADDBDB,
1197	0x3BDBE0E0, 0x56643232,  0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606,  0x6C482424, 0xE4B85C5C,
1198	0x5D9FC2C2, 0x6EBDD3D3,  0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595,  0x37D3E4E4, 0x8BF27979,
1199	0x32D5E7E7, 0x438BC8C8,  0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5,  0xD29C4E4E, 0xE049A9A9,
1200	0xB4D86C6C, 0xFAAC5656,  0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A,  0xE947AEAE, 0x18100808,
1201	0xD56FBABA, 0x88F07878,  0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6,  0xC773B4B4, 0x5197C6C6,
1202	0x23CBE8E8, 0x7CA1DDDD,  0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD,  0x860D8B8B, 0x850F8A8A,
1203	0x90E07070, 0x427C3E3E,  0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303,  0x01F7F6F6, 0x121C0E0E,
1204	0xA3C26161, 0x5F6A3535,  0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1,  0x273A1D1D, 0xB9279E9E,
1205	0x38D9E1E1, 0x13EBF8F8,  0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9,  0x89078E8E, 0xA7339494,
1206	0xB62D9B9B, 0x223C1E1E,  0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555,  0x78502828, 0x7AA5DFDF,
1207	0x8F038C8C, 0xF859A1A1,  0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6,  0xC6844242, 0xB8D06868,
1208	0xC3824141, 0xB0299999,  0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454,  0xD66DBBBB, 0x3A2C1616,
1209};
1210
1211/* Corresponds to _TInv3[256] */
1212unsigned int mtpz_aes_rt1[] =
1213{
1214	0xF4A75051, 0x4165537E,  0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F,  0xFA58ABAC, 0xE303934B,
1215	0x30FA5520, 0x766DF6AD,  0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5,  0x35448026, 0x62A38FB5,
1216	0xB15A49DE, 0xBA1B6725,  0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281,  0x4697A38D, 0xD3F9C66B,
1217	0x8F5FE703, 0x929C9515,  0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358,  0xE0692949, 0xC9C8448E,
1218	0xC2896A75, 0x8E7978F4,  0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0,  0x20AC66C9, 0xCE3AB47D,
1219	0xDF4A1863, 0x1A3182E5,  0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB,  0x81A01CFE, 0x082B94F9,
1220	0x48685870, 0x45FD198F,  0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272,  0x1F8F57E3, 0x55AB2A66,
1221	0xEB2807B2, 0xB5C2032F,  0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223,  0x036ABA02, 0x16825CED,
1222	0xCF1C2B8A, 0x79B492A7,  0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506,  0x34621FD1, 0xA6FE8AC4,
1223	0x2E539D34, 0xF355A0A2,  0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40,  0x719F065E, 0x6E1051BD,
1224	0x218AF93E, 0xDD063D96,  0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571,  0x06D46F04, 0x5015FF60,
1225	0x98FB2419, 0xBDE997D6,  0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807,  0x195B38E7, 0xC8EEDB79,
1226	0x7C0A47A1, 0x420FE97C,  0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832,  0x1170AC1E, 0x5A724E6C,
1227	0x0EFFFBFD, 0x8538560F,  0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168,  0x5B54D19B, 0x362E3A24,
1228	0x0A67B10C, 0x57E70F93,  0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261,  0x774B695A, 0x121A161C,
1229	0x93BA0AE2, 0xA02AE5C0,  0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2,  0xB6A8B92D, 0x1EA9C814,
1230	0xF1198557, 0x75074CAF,  0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C,  0x663BC544, 0xFB7E345B,
1231	0x4329768B, 0x23C6DCCB,  0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042,  0x97224013, 0xC6112084,
1232	0x4A247D85, 0xBB3DF8D2,  0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC,  0x8652EC0D, 0xC1E3D077,
1233	0xB3166C2B, 0x70B999A9,  0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0,  0x7D2CD856, 0x3390EF22,
1234	0x494EC787, 0x38D1C1D9,  0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5,  0xB78E26DA, 0xADBFA43F,
1235	0x3A9DE42C, 0x78920D50,  0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890,  0x39F75E2E, 0xC3AFF582,
1236	0x5D80BE9F, 0xD0937C69,  0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710,  0x9C636EE8, 0x3BBB7BDB,
1237	0x267809CD, 0x5918F46E,  0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA,  0xBCCF0821, 0x15E8E6EF,
1238	0xE79BD9BA, 0x6F36CE4A,  0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A,  0xA59430C6, 0xA266C035,
1239	0x4EBC3774, 0x82CAA6FC,  0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741,  0xCD500E7F, 0x91F62F17,
1240	0x4DD68D76, 0xEFB04D43,  0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C,  0x2C1FB8C1, 0x65517F46,
1241	0x5EEA049D, 0x8C355D01,  0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292,  0x105633E9, 0xD647136D,
1242	0xD7618C9A, 0xA10C7A37,  0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7,  0x1CE5EDE1, 0x47B13C7A,
1243	0xD2DF599C, 0xF2733F55,  0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F,  0x3D6F14DF, 0x44DB8678,
1244	0xAFF381CA, 0x68C43EB9,  0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC,  0x3C498B28, 0x0D9541FF,
1245	0xA8017139, 0x0CB3DE08,  0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5,  0x6C5C7448, 0xB85742D0
1246};
1247
1248/* Corresponds to _TInv2[256] */
1249unsigned int mtpz_aes_rt2[] =
1250{
1251	0xA75051F4, 0x65537E41,  0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D,  0x58ABACFA, 0x03934BE3,
1252	0xFA552030, 0x6DF6AD76,  0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A,  0x44802635, 0xA38FB562,
1253	0x5A49DEB1, 0x1B6725BA,  0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C,  0x97A38D46, 0xF9C66BD3,
1254	0x5FE7038F, 0x9C951592,  0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874,  0x692949E0, 0xC8448EC9,
1255	0x896A75C2, 0x7978F48E,  0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088,  0xAC66C920, 0x3AB47DCE,
1256	0x4A1863DF, 0x3182E51A,  0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B,  0xA01CFE81, 0x2B94F908,
1257	0x68587048, 0xFD198F45,  0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B,  0x8F57E31F, 0xAB2A6655,
1258	0x2807B2EB, 0xC2032FB5,  0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF,  0x6ABA0203, 0x825CED16,
1259	0x1C2B8ACF, 0xB492A779,  0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605,  0x621FD134, 0xFE8AC4A6,
1260	0x539D342E, 0x55A0A2F3,  0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060,  0x9F065E71, 0x1051BD6E,
1261	0x8AF93E21, 0x063D96DD,  0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4,  0xD46F0406, 0x15FF6050,
1262	0xFB241998, 0xE997D6BD,  0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789,  0x5B38E719, 0xEEDB79C8,
1263	0x0A47A17C, 0x0FE97C42,  0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B,  0x70AC1E11, 0x724E6C5A,
1264	0xFFFBFD0E, 0x38560F85,  0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C,  0x54D19B5B, 0x2E3A2436,
1265	0x67B10C0A, 0xE70F9357,  0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC,  0x4B695A77, 0x1A161C12,
1266	0xBA0AE293, 0x2AE5C0A0,  0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B,  0xA8B92DB6, 0xA9C8141E,
1267	0x198557F1, 0x074CAF75,  0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72,  0x3BC54466, 0x7E345BFB,
1268	0x29768B43, 0xC6DCCB23,  0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263,  0x22401397, 0x112084C6,
1269	0x247D854A, 0x3DF8D2BB,  0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2,  0x52EC0D86, 0xE3D077C1,
1270	0x166C2BB3, 0xB999A970,  0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0,  0x2CD8567D, 0x90EF2233,
1271	0x4EC78749, 0xD1C1D938,  0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A,  0x8E26DAB7, 0xBFA43FAD,
1272	0x9DE42C3A, 0x920D5078,  0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8,  0xF75E2E39, 0xAFF582C3,
1273	0x80BE9F5D, 0x937C69D0,  0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018,  0x636EE89C, 0xBB7BDB3B,
1274	0x7809CD26, 0x18F46E59,  0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF,  0xCF0821BC, 0xE8E6EF15,
1275	0x9BD9BAE7, 0x36CE4A6F,  0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F,  0x9430C6A5, 0x66C035A2,
1276	0xBC37744E, 0xCAA6FC82,  0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC,  0x500E7FCD, 0xF62F1791,
1277	0xD68D764D, 0xB04D43EF,  0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A,  0x1FB8C12C, 0x517F4665,
1278	0xEA049D5E, 0x355D018C,  0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB,  0x5633E910, 0x47136DD6,
1279	0x618C9AD7, 0x0C7A37A1,  0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761,  0xE5EDE11C, 0xB13C7A47,
1280	0xDF599CD2, 0x733F55F2,  0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD,  0x6F14DF3D, 0xDB867844,
1281	0xF381CAAF, 0xC43EB968,  0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2,  0x498B283C, 0x9541FF0D,
1282	0x017139A8, 0xB3DE080C,  0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532,  0x5C74486C, 0x5742D0B8
1283};
1284
1285/* Corresponds to _TInv0[256] */
1286unsigned int mtpz_aes_rt3[] =
1287{
1288	0x51F4A750, 0x7E416553,  0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1,  0xACFA58AB, 0x4BE30393,
1289	0x2030FA55, 0xAD766DF6,  0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7,  0x26354480, 0xB562A38F,
1290	0xDEB15A49, 0x25BA1B67,  0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012,  0x8D4697A3, 0x6BD3F9C6,
1291	0x038F5FE7, 0x15929C95,  0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3,  0x49E06929, 0x8EC9C844,
1292	0x75C2896A, 0xF48E7978,  0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17,  0xC920AC66, 0x7DCE3AB4,
1293	0x63DF4A18, 0xE51A3182,  0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84,  0xFE81A01C, 0xF9082B94,
1294	0x70486858, 0x8F45FD19,  0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2,  0xE31F8F57, 0x6655AB2A,
1295	0xB2EB2807, 0x2FB5C203,  0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2,  0x02036ABA, 0xED16825C,
1296	0x8ACF1C2B, 0xA779B492,  0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5,  0xD134621F, 0xC4A6FE8A,
1297	0x342E539D, 0xA2F355A0,  0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA,  0x5E719F06, 0xBD6E1051,
1298	0x3E218AF9, 0x96DD063D,  0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05,  0x0406D46F, 0x605015FF,
1299	0x1998FB24, 0xD6BDE997,  0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88,  0xE7195B38, 0x79C8EEDB,
1300	0xA17C0A47, 0x7C420FE9,  0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48,  0x1E1170AC, 0x6C5A724E,
1301	0xFD0EFFFB, 0x0F853856,  0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621,  0x9B5B54D1, 0x24362E3A,
1302	0x0C0A67B1, 0x9357E70F,  0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2,  0x5A774B69, 0x1C121A16,
1303	0xE293BA0A, 0xC0A02AE5,  0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD,  0x2DB6A8B9, 0x141EA9C8,
1304	0x57F11985, 0xAF75074C,  0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC,  0x44663BC5, 0x5BFB7E34,
1305	0x8B432976, 0xCB23C6DC,  0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510,  0x13972240, 0x84C61120,
1306	0x854A247D, 0xD2BB3DF8,  0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3,  0x0D8652EC, 0x77C1E3D0,
1307	0x2BB3166C, 0xA970B999,  0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A,  0x567D2CD8, 0x223390EF,
1308	0x87494EC7, 0xD938D1C1,  0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28,  0xDAB78E26, 0x3FADBFA4,
1309	0x2C3A9DE4, 0x5078920D,  0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8,  0x2E39F75E, 0x82C3AFF5,
1310	0x9F5D80BE, 0x69D0937C,  0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7,  0xE89C636E, 0xDB3BBB7B,
1311	0xCD267809, 0x6E5918F4,  0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E,  0x21BCCF08, 0xEF15E8E6,
1312	0xBAE79BD9, 0x4A6F36CE,  0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331,  0xC6A59430, 0x35A266C0,
1313	0x744EBC37, 0xFC82CAA6,  0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7,  0x7FCD500E, 0x1791F62F,
1314	0x764DD68D, 0x43EFB04D,  0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B,  0xC12C1FB8, 0x4665517F,
1315	0x9D5EEA04, 0x018C355D,  0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252,  0xE9105633, 0x6DD64713,
1316	0x9AD7618C, 0x37A10C7A,  0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935,  0xE11CE5ED, 0x7A47B13C,
1317	0x9CD2DF59, 0x55F2733F,  0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B,  0xDF3D6F14, 0x7844DB86,
1318	0xCAAFF381, 0xB968C43E,  0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C,  0x283C498B, 0xFF0D9541,
1319	0x39A80171, 0x080CB3DE,  0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670,  0x486C5C74, 0xD0B85742
1320};
1321
1322/* Corresponds to _TInv1[256] */
1323unsigned int mtpz_aes_rt4[] =
1324{
1325	0x5051F4A7, 0x537E4165,  0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45,  0xABACFA58, 0x934BE303,
1326	0x552030FA, 0xF6AD766D,  0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB,  0x80263544, 0x8FB562A3,
1327	0x49DEB15A, 0x6725BA1B,  0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0,  0xA38D4697, 0xC66BD3F9,
1328	0xE7038F5F, 0x9515929C,  0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421,  0x2949E069, 0x448EC9C8,
1329	0x6A75C289, 0x78F48E79,  0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD,  0x66C920AC, 0xB47DCE3A,
1330	0x1863DF4A, 0x82E51A31,  0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE,  0x1CFE81A0, 0x94F9082B,
1331	0x58704868, 0x198F45FD,  0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02,  0x57E31F8F, 0x2A6655AB,
1332	0x07B2EB28, 0x032FB5C2,  0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5,  0xBA02036A, 0x5CED1682,
1333	0x2B8ACF1C, 0x92A779B4,  0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE,  0x1FD13462, 0x8AC4A6FE,
1334	0x9D342E53, 0xA0A2F355,  0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF,  0x065E719F, 0x51BD6E10,
1335	0xF93E218A, 0x3D96DD06,  0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D,  0x6F0406D4, 0xFF605015,
1336	0x241998FB, 0x97D6BDE9,  0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B,  0x38E7195B, 0xDB79C8EE,
1337	0x47A17C0A, 0xE97C420F,  0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED,  0xAC1E1170, 0x4E6C5A72,
1338	0xFBFD0EFF, 0x560F8538,  0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6,  0xD19B5B54, 0x3A24362E,
1339	0xB10C0A67, 0x0F9357E7,  0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20,  0x695A774B, 0x161C121A,
1340	0x0AE293BA, 0xE5C0A02A,  0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7,  0xB92DB6A8, 0xC8141EA9,
1341	0x8557F119, 0x4CAF7507,  0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5,  0xC544663B, 0x345BFB7E,
1342	0x768B4329, 0xDCCB23C6,  0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385,  0x40139722, 0x2084C611,
1343	0x7D854A24, 0xF8D2BB3D,  0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230,  0xEC0D8652, 0xD077C1E3,
1344	0x6C2BB316, 0x99A970B9,  0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F,  0xD8567D2C, 0xEF223390,
1345	0xC787494E, 0xC1D938D1,  0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE,  0x26DAB78E, 0xA43FADBF,
1346	0xE42C3A9D, 0x0D507892,  0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8,  0x5E2E39F7, 0xF582C3AF,
1347	0xBE9F5D80, 0x7C69D093,  0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D,  0x6EE89C63, 0x7BDB3BBB,
1348	0x09CD2678, 0xF46E5918,  0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6,  0x0821BCCF, 0xE6EF15E8,
1349	0xD9BAE79B, 0xCE4A6F36,  0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23,  0x30C6A594, 0xC035A266,
1350	0x37744EBC, 0xA6FC82CA,  0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA,  0x0E7FCD50, 0x2F1791F6,
1351	0x8D764DD6, 0x4D43EFB0,  0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88,  0xB8C12C1F, 0x7F466551,
1352	0x049D5EEA, 0x5D018C35,  0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2,  0x33E91056, 0x136DD647,
1353	0x8C9AD761, 0x7A37A10C,  0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9,  0xEDE11CE5, 0x3C7A47B1,
1354	0x599CD2DF, 0x3F55F273,  0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA,  0x14DF3D6F, 0x867844DB,
1355	0x81CAAFF3, 0x3EB968C4,  0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225,  0x8B283C49, 0x41FF0D95,
1356	0x7139A801, 0xDE080CB3,  0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6,  0x74486C5C, 0x42D0B857
1357};
1358
1359/* Corresponds to _IMXC1[256] */
1360unsigned int mtpz_aes_gb11[] =
1361{
1362	0x00000000, 0x0B0E090D,  0x161C121A, 0x1D121B17, 0x2C382434, 0x27362D39,  0x3A24362E, 0x312A3F23,
1363	0x58704868, 0x537E4165,  0x4E6C5A72, 0x4562537F, 0x74486C5C, 0x7F466551,  0x62547E46, 0x695A774B,
1364	0xB0E090D0, 0xBBEE99DD,  0xA6FC82CA, 0xADF28BC7, 0x9CD8B4E4, 0x97D6BDE9,  0x8AC4A6FE, 0x81CAAFF3,
1365	0xE890D8B8, 0xE39ED1B5,  0xFE8CCAA2, 0xF582C3AF, 0xC4A8FC8C, 0xCFA6F581,  0xD2B4EE96, 0xD9BAE79B,
1366	0x7BDB3BBB, 0x70D532B6,  0x6DC729A1, 0x66C920AC, 0x57E31F8F, 0x5CED1682,  0x41FF0D95, 0x4AF10498,
1367	0x23AB73D3, 0x28A57ADE,  0x35B761C9, 0x3EB968C4, 0x0F9357E7, 0x049D5EEA,  0x198F45FD, 0x12814CF0,
1368	0xCB3BAB6B, 0xC035A266,  0xDD27B971, 0xD629B07C, 0xE7038F5F, 0xEC0D8652,  0xF11F9D45, 0xFA119448,
1369	0x934BE303, 0x9845EA0E,  0x8557F119, 0x8E59F814, 0xBF73C737, 0xB47DCE3A,  0xA96FD52D, 0xA261DC20,
1370	0xF6AD766D, 0xFDA37F60,  0xE0B16477, 0xEBBF6D7A, 0xDA955259, 0xD19B5B54,  0xCC894043, 0xC787494E,
1371	0xAEDD3E05, 0xA5D33708,  0xB8C12C1F, 0xB3CF2512, 0x82E51A31, 0x89EB133C,  0x94F9082B, 0x9FF70126,
1372	0x464DE6BD, 0x4D43EFB0,  0x5051F4A7, 0x5B5FFDAA, 0x6A75C289, 0x617BCB84,  0x7C69D093, 0x7767D99E,
1373	0x1E3DAED5, 0x1533A7D8,  0x0821BCCF, 0x032FB5C2, 0x32058AE1, 0x390B83EC,  0x241998FB, 0x2F1791F6,
1374	0x8D764DD6, 0x867844DB,  0x9B6A5FCC, 0x906456C1, 0xA14E69E2, 0xAA4060EF,  0xB7527BF8, 0xBC5C72F5,
1375	0xD50605BE, 0xDE080CB3,  0xC31A17A4, 0xC8141EA9, 0xF93E218A, 0xF2302887,  0xEF223390, 0xE42C3A9D,
1376	0x3D96DD06, 0x3698D40B,  0x2B8ACF1C, 0x2084C611, 0x11AEF932, 0x1AA0F03F,  0x07B2EB28, 0x0CBCE225,
1377	0x65E6956E, 0x6EE89C63,  0x73FA8774, 0x78F48E79, 0x49DEB15A, 0x42D0B857,  0x5FC2A340, 0x54CCAA4D,
1378	0xF741ECDA, 0xFC4FE5D7,  0xE15DFEC0, 0xEA53F7CD, 0xDB79C8EE, 0xD077C1E3,  0xCD65DAF4, 0xC66BD3F9,
1379	0xAF31A4B2, 0xA43FADBF,  0xB92DB6A8, 0xB223BFA5, 0x83098086, 0x8807898B,  0x9515929C, 0x9E1B9B91,
1380	0x47A17C0A, 0x4CAF7507,  0x51BD6E10, 0x5AB3671D, 0x6B99583E, 0x60975133,  0x7D854A24, 0x768B4329,
1381	0x1FD13462, 0x14DF3D6F,  0x09CD2678, 0x02C32F75, 0x33E91056, 0x38E7195B,  0x25F5024C, 0x2EFB0B41,
1382	0x8C9AD761, 0x8794DE6C,  0x9A86C57B, 0x9188CC76, 0xA0A2F355, 0xABACFA58,  0xB6BEE14F, 0xBDB0E842,
1383	0xD4EA9F09, 0xDFE49604,  0xC2F68D13, 0xC9F8841E, 0xF8D2BB3D, 0xF3DCB230,  0xEECEA927, 0xE5C0A02A,
1384	0x3C7A47B1, 0x37744EBC,  0x2A6655AB, 0x21685CA6, 0x10426385, 0x1B4C6A88,  0x065E719F, 0x0D507892,
1385	0x640A0FD9, 0x6F0406D4,  0x72161DC3, 0x791814CE, 0x48322BED, 0x433C22E0,  0x5E2E39F7, 0x552030FA,
1386	0x01EC9AB7, 0x0AE293BA,  0x17F088AD, 0x1CFE81A0, 0x2DD4BE83, 0x26DAB78E,  0x3BC8AC99, 0x30C6A594,
1387	0x599CD2DF, 0x5292DBD2,  0x4F80C0C5, 0x448EC9C8, 0x75A4F6EB, 0x7EAAFFE6,  0x63B8E4F1, 0x68B6EDFC,
1388	0xB10C0A67, 0xBA02036A,  0xA710187D, 0xAC1E1170, 0x9D342E53, 0x963A275E,  0x8B283C49, 0x80263544,
1389	0xE97C420F, 0xE2724B02,  0xFF605015, 0xF46E5918, 0xC544663B, 0xCE4A6F36,  0xD3587421, 0xD8567D2C,
1390	0x7A37A10C, 0x7139A801,  0x6C2BB316, 0x6725BA1B, 0x560F8538, 0x5D018C35,  0x40139722, 0x4B1D9E2F,
1391	0x2247E964, 0x2949E069,  0x345BFB7E, 0x3F55F273, 0x0E7FCD50, 0x0571C45D,  0x1863DF4A, 0x136DD647,
1392	0xCAD731DC, 0xC1D938D1,  0xDCCB23C6, 0xD7C52ACB, 0xE6EF15E8, 0xEDE11CE5,  0xF0F307F2, 0xFBFD0EFF,
1393	0x92A779B4, 0x99A970B9,  0x84BB6BAE, 0x8FB562A3, 0xBE9F5D80, 0xB591548D,  0xA8834F9A, 0xA38D4697,
1394};
1395
1396/* Corresponds to _IMXC0[256] */
1397unsigned int mtpz_aes_gb14[] =
1398{
1399	0x00000000,  0x0E090D0B,   0x1C121A16,  0x121B171D,  0x3824342C,  0x362D3927,   0x24362E3A,  0x2A3F2331,
1400	0x70486858,  0x7E416553,   0x6C5A724E,  0x62537F45,  0x486C5C74,  0x4665517F,   0x547E4662,  0x5A774B69,
1401	0xE090D0B0,  0xEE99DDBB,   0xFC82CAA6,  0xF28BC7AD,  0xD8B4E49C,  0xD6BDE997,   0xC4A6FE8A,  0xCAAFF381,
1402	0x90D8B8E8,  0x9ED1B5E3,   0x8CCAA2FE,  0x82C3AFF5,  0xA8FC8CC4,  0xA6F581CF,   0xB4EE96D2,  0xBAE79BD9,
1403	0xDB3BBB7B,  0xD532B670,   0xC729A16D,  0xC920AC66,  0xE31F8F57,  0xED16825C,   0xFF0D9541,  0xF104984A,
1404	0xAB73D323,  0xA57ADE28,   0xB761C935,  0xB968C43E,  0x9357E70F,  0x9D5EEA04,   0x8F45FD19,  0x814CF012,
1405	0x3BAB6BCB,  0x35A266C0,   0x27B971DD,  0x29B07CD6,  0x038F5FE7,  0x0D8652EC,   0x1F9D45F1,  0x119448FA,
1406	0x4BE30393,  0x45EA0E98,   0x57F11985,  0x59F8148E,  0x73C737BF,  0x7DCE3AB4,   0x6FD52DA9,  0x61DC20A2,
1407	0xAD766DF6,  0xA37F60FD,   0xB16477E0,  0xBF6D7AEB,  0x955259DA,  0x9B5B54D1,   0x894043CC,  0x87494EC7,
1408	0xDD3E05AE,  0xD33708A5,   0xC12C1FB8,  0xCF2512B3,  0xE51A3182,  0xEB133C89,   0xF9082B94,  0xF701269F,
1409	0x4DE6BD46,  0x43EFB04D,   0x51F4A750,  0x5FFDAA5B,  0x75C2896A,  0x7BCB8461,   0x69D0937C,  0x67D99E77,
1410	0x3DAED51E,  0x33A7D815,   0x21BCCF08,  0x2FB5C203,  0x058AE132,  0x0B83EC39,   0x1998FB24,  0x1791F62F,
1411	0x764DD68D,  0x7844DB86,   0x6A5FCC9B,  0x6456C190,  0x4E69E2A1,  0x4060EFAA,   0x527BF8B7,  0x5C72F5BC,
1412	0x0605BED5,  0x080CB3DE,   0x1A17A4C3,  0x141EA9C8,  0x3E218AF9,  0x302887F2,   0x223390EF,  0x2C3A9DE4,
1413	0x96DD063D,  0x98D40B36,   0x8ACF1C2B,  0x84C61120,  0xAEF93211,  0xA0F03F1A,   0xB2EB2807,  0xBCE2250C,
1414	0xE6956E65,  0xE89C636E,   0xFA877473,  0xF48E7978,  0xDEB15A49,  0xD0B85742,   0xC2A3405F,  0xCCAA4D54,
1415	0x41ECDAF7,  0x4FE5D7FC,   0x5DFEC0E1,  0x53F7CDEA,  0x79C8EEDB,  0x77C1E3D0,   0x65DAF4CD,  0x6BD3F9C6,
1416	0x31A4B2AF,  0x3FADBFA4,   0x2DB6A8B9,  0x23BFA5B2,  0x09808683,  0x07898B88,   0x15929C95,  0x1B9B919E,
1417	0xA17C0A47,  0xAF75074C,   0xBD6E1051,  0xB3671D5A,  0x99583E6B,  0x97513360,   0x854A247D,  0x8B432976,
1418	0xD134621F,  0xDF3D6F14,   0xCD267809,  0xC32F7502,  0xE9105633,  0xE7195B38,   0xF5024C25,  0xFB0B412E,
1419	0x9AD7618C,  0x94DE6C87,   0x86C57B9A,  0x88CC7691,  0xA2F355A0,  0xACFA58AB,   0xBEE14FB6,  0xB0E842BD,
1420	0xEA9F09D4,  0xE49604DF,   0xF68D13C2,  0xF8841EC9,  0xD2BB3DF8,  0xDCB230F3,   0xCEA927EE,  0xC0A02AE5,
1421	0x7A47B13C,  0x744EBC37,   0x6655AB2A,  0x685CA621,  0x42638510,  0x4C6A881B,   0x5E719F06,  0x5078920D,
1422	0x0A0FD964,  0x0406D46F,   0x161DC372,  0x1814CE79,  0x322BED48,  0x3C22E043,   0x2E39F75E,  0x2030FA55,
1423	0xEC9AB701,  0xE293BA0A,   0xF088AD17,  0xFE81A01C,  0xD4BE832D,  0xDAB78E26,   0xC8AC993B,  0xC6A59430,
1424	0x9CD2DF59,  0x92DBD252,   0x80C0C54F,  0x8EC9C844,  0xA4F6EB75,  0xAAFFE67E,   0xB8E4F163,  0xB6EDFC68,
1425	0x0C0A67B1,  0x02036ABA,   0x10187DA7,  0x1E1170AC,  0x342E539D,  0x3A275E96,   0x283C498B,  0x26354480,
1426	0x7C420FE9,  0x724B02E2,   0x605015FF,  0x6E5918F4,  0x44663BC5,  0x4A6F36CE,   0x587421D3,  0x567D2CD8,
1427	0x37A10C7A,  0x39A80171,   0x2BB3166C,  0x25BA1B67,  0x0F853856,  0x018C355D,   0x13972240,  0x1D9E2F4B,
1428	0x47E96422,  0x49E06929,   0x5BFB7E34,  0x55F2733F,  0x7FCD500E,  0x71C45D05,   0x63DF4A18,  0x6DD64713,
1429	0xD731DCCA,  0xD938D1C1,   0xCB23C6DC,  0xC52ACBD7,  0xEF15E8E6,  0xE11CE5ED,   0xF307F2F0,  0xFD0EFFFB,
1430	0xA779B492,  0xA970B999,   0xBB6BAE84,  0xB562A38F,  0x9F5D80BE,  0x91548DB5,   0x834F9AA8,  0x8D4697A3,
1431} ;
1432
1433/* Corresponds to _IMXC2[256] */
1434unsigned int mtpz_aes_gb13[] =
1435{
1436	0x00000000,  0x0D0B0E09,   0x1A161C12,  0x171D121B,  0x342C3824,  0x3927362D,   0x2E3A2436,  0x23312A3F,
1437	0x68587048,  0x65537E41,   0x724E6C5A,  0x7F456253,  0x5C74486C,  0x517F4665,   0x4662547E,  0x4B695A77,
1438	0xD0B0E090,  0xDDBBEE99,   0xCAA6FC82,  0xC7ADF28B,  0xE49CD8B4,  0xE997D6BD,   0xFE8AC4A6,  0xF381CAAF,
1439	0xB8E890D8,  0xB5E39ED1,   0xA2FE8CCA,  0xAFF582C3,  0x8CC4A8FC,  0x81CFA6F5,   0x96D2B4EE,  0x9BD9BAE7,
1440	0xBB7BDB3B,  0xB670D532,   0xA16DC729,  0xAC66C920,  0x8F57E31F,  0x825CED16,   0x9541FF0D,  0x984AF104,
1441	0xD323AB73,  0xDE28A57A,   0xC935B761,  0xC43EB968,  0xE70F9357,  0xEA049D5E,   0xFD198F45,  0xF012814C,
1442	0x6BCB3BAB,  0x66C035A2,   0x71DD27B9,  0x7CD629B0,  0x5FE7038F,  0x52EC0D86,   0x45F11F9D,  0x48FA1194,
1443	0x03934BE3,  0x0E9845EA,   0x198557F1,  0x148E59F8,  0x37BF73C7,  0x3AB47DCE,   0x2DA96FD5,  0x20A261DC,
1444	0x6DF6AD76,  0x60FDA37F,   0x77E0B164,  0x7AEBBF6D,  0x59DA9552,  0x54D19B5B,   0x43CC8940,  0x4EC78749,
1445	0x05AEDD3E,  0x08A5D337,   0x1FB8C12C,  0x12B3CF25,  0x3182E51A,  0x3C89EB13,   0x2B94F908,  0x269FF701,
1446	0xBD464DE6,  0xB04D43EF,   0xA75051F4,  0xAA5B5FFD,  0x896A75C2,  0x84617BCB,   0x937C69D0,  0x9E7767D9,
1447	0xD51E3DAE,  0xD81533A7,   0xCF0821BC,  0xC2032FB5,  0xE132058A,  0xEC390B83,   0xFB241998,  0xF62F1791,
1448	0xD68D764D,  0xDB867844,   0xCC9B6A5F,  0xC1906456,  0xE2A14E69,  0xEFAA4060,   0xF8B7527B,  0xF5BC5C72,
1449	0xBED50605,  0xB3DE080C,   0xA4C31A17,  0xA9C8141E,  0x8AF93E21,  0x87F23028,   0x90EF2233,  0x9DE42C3A,
1450	0x063D96DD,  0x0B3698D4,   0x1C2B8ACF,  0x112084C6,  0x3211AEF9,  0x3F1AA0F0,   0x2807B2EB,  0x250CBCE2,
1451	0x6E65E695,  0x636EE89C,   0x7473FA87,  0x7978F48E,  0x5A49DEB1,  0x5742D0B8,   0x405FC2A3,  0x4D54CCAA,
1452	0xDAF741EC,  0xD7FC4FE5,   0xC0E15DFE,  0xCDEA53F7,  0xEEDB79C8,  0xE3D077C1,   0xF4CD65DA,  0xF9C66BD3,
1453	0xB2AF31A4,  0xBFA43FAD,   0xA8B92DB6,  0xA5B223BF,  0x86830980,  0x8B880789,   0x9C951592,  0x919E1B9B,
1454	0x0A47A17C,  0x074CAF75,   0x1051BD6E,  0x1D5AB367,  0x3E6B9958,  0x33609751,   0x247D854A,  0x29768B43,
1455	0x621FD134,  0x6F14DF3D,   0x7809CD26,  0x7502C32F,  0x5633E910,  0x5B38E719,   0x4C25F502,  0x412EFB0B,
1456	0x618C9AD7,  0x6C8794DE,   0x7B9A86C5,  0x769188CC,  0x55A0A2F3,  0x58ABACFA,   0x4FB6BEE1,  0x42BDB0E8,
1457	0x09D4EA9F,  0x04DFE496,   0x13C2F68D,  0x1EC9F884,  0x3DF8D2BB,  0x30F3DCB2,   0x27EECEA9,  0x2AE5C0A0,
1458	0xB13C7A47,  0xBC37744E,   0xAB2A6655,  0xA621685C,  0x85104263,  0x881B4C6A,   0x9F065E71,  0x920D5078,
1459	0xD9640A0F,  0xD46F0406,   0xC372161D,  0xCE791814,  0xED48322B,  0xE0433C22,   0xF75E2E39,  0xFA552030,
1460	0xB701EC9A,  0xBA0AE293,   0xAD17F088,  0xA01CFE81,  0x832DD4BE,  0x8E26DAB7,   0x993BC8AC,  0x9430C6A5,
1461	0xDF599CD2,  0xD25292DB,   0xC54F80C0,  0xC8448EC9,  0xEB75A4F6,  0xE67EAAFF,   0xF163B8E4,  0xFC68B6ED,
1462	0x67B10C0A,  0x6ABA0203,   0x7DA71018,  0x70AC1E11,  0x539D342E,  0x5E963A27,   0x498B283C,  0x44802635,
1463	0x0FE97C42,  0x02E2724B,   0x15FF6050,  0x18F46E59,  0x3BC54466,  0x36CE4A6F,   0x21D35874,  0x2CD8567D,
1464	0x0C7A37A1,  0x017139A8,   0x166C2BB3,  0x1B6725BA,  0x38560F85,  0x355D018C,   0x22401397,  0x2F4B1D9E,
1465	0x642247E9,  0x692949E0,   0x7E345BFB,  0x733F55F2,  0x500E7FCD,  0x5D0571C4,   0x4A1863DF,  0x47136DD6,
1466	0xDCCAD731,  0xD1C1D938,   0xC6DCCB23,  0xCBD7C52A,  0xE8E6EF15,  0xE5EDE11C,   0xF2F0F307,  0xFFFBFD0E,
1467	0xB492A779,  0xB999A970,   0xAE84BB6B,  0xA38FB562,  0x80BE9F5D,  0x8DB59154,   0x9AA8834F,  0x97A38D46,
1468};
1469
1470/* Corresponds to _IMXC3[256] */
1471unsigned int mtpz_aes_gb9[] =
1472{
1473	0x00000000,  0x090D0B0E,   0x121A161C,  0x1B171D12,  0x24342C38,  0x2D392736,   0x362E3A24,  0x3F23312A,
1474	0x48685870,  0x4165537E,   0x5A724E6C,  0x537F4562,  0x6C5C7448,  0x65517F46,   0x7E466254,  0x774B695A,
1475	0x90D0B0E0,  0x99DDBBEE,   0x82CAA6FC,  0x8BC7ADF2,  0xB4E49CD8,  0xBDE997D6,   0xA6FE8AC4,  0xAFF381CA,
1476	0xD8B8E890,  0xD1B5E39E,   0xCAA2FE8C,  0xC3AFF582,  0xFC8CC4A8,  0xF581CFA6,   0xEE96D2B4,  0xE79BD9BA,
1477	0x3BBB7BDB,  0x32B670D5,   0x29A16DC7,  0x20AC66C9,  0x1F8F57E3,  0x16825CED,   0x0D9541FF,  0x04984AF1,
1478	0x73D323AB,  0x7ADE28A5,   0x61C935B7,  0x68C43EB9,  0x57E70F93,  0x5EEA049D,   0x45FD198F,  0x4CF01281,
1479	0xAB6BCB3B,  0xA266C035,   0xB971DD27,  0xB07CD629,  0x8F5FE703,  0x8652EC0D,   0x9D45F11F,  0x9448FA11,
1480	0xE303934B,  0xEA0E9845,   0xF1198557,  0xF8148E59,  0xC737BF73,  0xCE3AB47D,   0xD52DA96F,  0xDC20A261,
1481	0x766DF6AD,  0x7F60FDA3,   0x6477E0B1,  0x6D7AEBBF,  0x5259DA95,  0x5B54D19B,   0x4043CC89,  0x494EC787,
1482	0x3E05AEDD,  0x3708A5D3,   0x2C1FB8C1,  0x2512B3CF,  0x1A3182E5,  0x133C89EB,   0x082B94F9,  0x01269FF7,
1483	0xE6BD464D,  0xEFB04D43,   0xF4A75051,  0xFDAA5B5F,  0xC2896A75,  0xCB84617B,   0xD0937C69,  0xD99E7767,
1484	0xAED51E3D,  0xA7D81533,   0xBCCF0821,  0xB5C2032F,  0x8AE13205,  0x83EC390B,   0x98FB2419,  0x91F62F17,
1485	0x4DD68D76,  0x44DB8678,   0x5FCC9B6A,  0x56C19064,  0x69E2A14E,  0x60EFAA40,   0x7BF8B752,  0x72F5BC5C,
1486	0x05BED506,  0x0CB3DE08,   0x17A4C31A,  0x1EA9C814,  0x218AF93E,  0x2887F230,   0x3390EF22,  0x3A9DE42C,
1487	0xDD063D96,  0xD40B3698,   0xCF1C2B8A,  0xC6112084,  0xF93211AE,  0xF03F1AA0,   0xEB2807B2,  0xE2250CBC,
1488	0x956E65E6,  0x9C636EE8,   0x877473FA,  0x8E7978F4,  0xB15A49DE,  0xB85742D0,   0xA3405FC2,  0xAA4D54CC,
1489	0xECDAF741,  0xE5D7FC4F,   0xFEC0E15D,  0xF7CDEA53,  0xC8EEDB79,  0xC1E3D077,   0xDAF4CD65,  0xD3F9C66B,
1490	0xA4B2AF31,  0xADBFA43F,   0xB6A8B92D,  0xBFA5B223,  0x80868309,  0x898B8807,   0x929C9515,  0x9B919E1B,
1491	0x7C0A47A1,  0x75074CAF,   0x6E1051BD,  0x671D5AB3,  0x583E6B99,  0x51336097,   0x4A247D85,  0x4329768B,
1492	0x34621FD1,  0x3D6F14DF,   0x267809CD,  0x2F7502C3,  0x105633E9,  0x195B38E7,   0x024C25F5,  0x0B412EFB,
1493	0xD7618C9A,  0xDE6C8794,   0xC57B9A86,  0xCC769188,  0xF355A0A2,  0xFA58ABAC,   0xE14FB6BE,  0xE842BDB0,
1494	0x9F09D4EA,  0x9604DFE4,   0x8D13C2F6,  0x841EC9F8,  0xBB3DF8D2,  0xB230F3DC,   0xA927EECE,  0xA02AE5C0,
1495	0x47B13C7A,  0x4EBC3774,   0x55AB2A66,  0x5CA62168,  0x63851042,  0x6A881B4C,   0x719F065E,  0x78920D50,
1496	0x0FD9640A,  0x06D46F04,   0x1DC37216,  0x14CE7918,  0x2BED4832,  0x22E0433C,   0x39F75E2E,  0x30FA5520,
1497	0x9AB701EC,  0x93BA0AE2,   0x88AD17F0,  0x81A01CFE,  0xBE832DD4,  0xB78E26DA,   0xAC993BC8,  0xA59430C6,
1498	0xD2DF599C,  0xDBD25292,   0xC0C54F80,  0xC9C8448E,  0xF6EB75A4,  0xFFE67EAA,   0xE4F163B8,  0xEDFC68B6,
1499	0x0A67B10C,  0x036ABA02,   0x187DA710,  0x1170AC1E,  0x2E539D34,  0x275E963A,   0x3C498B28,  0x35448026,
1500	0x420FE97C,  0x4B02E272,   0x5015FF60,  0x5918F46E,  0x663BC544,  0x6F36CE4A,   0x7421D358,  0x7D2CD856,
1501	0xA10C7A37,  0xA8017139,   0xB3166C2B,  0xBA1B6725,  0x8538560F,  0x8C355D01,   0x97224013,  0x9E2F4B1D,
1502	0xE9642247,  0xE0692949,   0xFB7E345B,  0xF2733F55,  0xCD500E7F,  0xC45D0571,   0xDF4A1863,  0xD647136D,
1503	0x31DCCAD7,  0x38D1C1D9,   0x23C6DCCB,  0x2ACBD7C5,  0x15E8E6EF,  0x1CE5EDE1,   0x07F2F0F3,  0x0EFFFBFD,
1504	0x79B492A7,  0x70B999A9,   0x6BAE84BB,  0x62A38FB5,  0x5D80BE9F,  0x548DB591,   0x4F9AA883,  0x4697A38D,
1505};
1506
1507static uint16_t
1508ptp_mtpz_validatehandshakeresponse (PTPParams* params, unsigned char *random, unsigned char **calculatedHash)
1509{
1510	uint16_t ret;
1511	unsigned int len;
1512	unsigned char* response = NULL;
1513
1514	ret = ptp_mtpz_getwmdrmpdappresponse (params, &response, &len);
1515	if (ret != PTP_RC_OK)
1516	{
1517		LIBMTP_INFO ("(MTPZ) Failure - did not receive device's response.\n");
1518		return ret;
1519	}
1520
1521	char *reader = (char *)response;
1522	int i;
1523
1524	if (*(reader++) != '\x02')
1525	{
1526		return -1;
1527	}
1528
1529	if (*(reader++) != '\x02')
1530	{
1531		return -1;
1532	}
1533
1534	// Message is always 128 bytes.
1535	reader++;
1536	if (*(reader++) != '\x80')
1537	{
1538		return -1;
1539	}
1540
1541	char *message = (char *)malloc(128);
1542	memcpy(message, reader, 128);
1543	reader += 128;
1544
1545	// Decrypt the hash-key-message..
1546	char *msg_dec = (char *)malloc(128);
1547	memset(msg_dec, 0, 128);
1548
1549	mtpz_rsa_t *rsa = mtpz_rsa_init(MTPZ_MODULUS, MTPZ_PRIVATE_KEY, MTPZ_PUBLIC_EXPONENT);
1550	if (!rsa)
1551	{
1552		LIBMTP_INFO ("(MTPZ) Failure - could not instantiate RSA object.\n");
1553		free(message);
1554		free(msg_dec);
1555		return -1;
1556	}
1557
1558	if (mtpz_rsa_decrypt(128, (unsigned char *)message, 128, (unsigned char *)msg_dec, rsa) == 0)
1559	{
1560		LIBMTP_INFO ("(MTPZ) Failure - could not perform RSA decryption.\n");
1561
1562		free(message);
1563		free(msg_dec);
1564		mtpz_rsa_free(rsa);
1565		return -1;
1566	}
1567
1568	mtpz_rsa_free(rsa);
1569	rsa = NULL;
1570
1571	char *state = mtpz_hash_init_state();
1572	char *hash_key = (char *)malloc(16);
1573	char *v10 = mtpz_hash_custom6A5DC(state, msg_dec + 21, 107, 20);
1574
1575	for (i = 0; i < 20; i++)
1576		msg_dec[i + 1] ^= v10[i];
1577
1578	char *v11 = mtpz_hash_custom6A5DC(state, msg_dec + 1, 20, 107);
1579
1580	for (i = 0; i < 107; i++)
1581		msg_dec[i + 21] ^= v11[i];
1582
1583	memcpy(hash_key, msg_dec + 112, 16);
1584
1585	// Encrypted message is 0x340 bytes.
1586	reader += 2;
1587	if (*(reader++) != '\x03' || *(reader++) != '\x40')
1588	{
1589		return -1;
1590	}
1591
1592	unsigned char *act_msg = (unsigned char *)malloc(832);
1593	unsigned char *act_reader = act_msg;
1594	memcpy(act_msg, reader, 832);
1595	reader = NULL;
1596
1597	mtpz_encryption_cipher_advanced((unsigned char *)hash_key, 16, act_msg, 832, 0);
1598
1599	act_reader++;
1600	unsigned int certs_length = MTPZ_SWAP(*(unsigned int *)(act_reader));
1601	act_reader += 4;
1602	act_reader += certs_length;
1603
1604	unsigned int rand_length = MTPZ_SWAP(*(unsigned short *)(act_reader) << 16);
1605	act_reader += 2;
1606	unsigned char *rand_data = (unsigned char *)malloc(rand_length);
1607	memcpy(rand_data, act_reader, rand_length);
1608	if (memcmp(rand_data, random, 16) != 0)
1609	{
1610		free(rand_data);
1611		return -1;
1612	}
1613	free(rand_data);
1614	act_reader += rand_length;
1615
1616	unsigned int dev_rand_length = MTPZ_SWAP(*(unsigned short *)(act_reader) << 16);
1617	act_reader += 2;
1618	act_reader += dev_rand_length;
1619
1620	act_reader++;
1621
1622	unsigned int sig_length = MTPZ_SWAP(*(unsigned short *)(act_reader) << 16);
1623	act_reader += 2;
1624	act_reader += sig_length;
1625
1626	act_reader++;
1627
1628	unsigned int machash_length = MTPZ_SWAP(*(unsigned short *)(act_reader) << 16);
1629	act_reader += 2;
1630	unsigned char *machash_data = (unsigned char *)malloc(machash_length);
1631	memcpy(machash_data, act_reader, machash_length);
1632	act_reader += machash_length;
1633
1634	*calculatedHash = machash_data;
1635
1636	free(message);
1637	free(msg_dec);
1638	free(state);
1639	free(v10);
1640	free(v11);
1641	free(act_msg);
1642
1643	return ret;
1644}
1645
1646static uint16_t
1647ptp_mtpz_opensecuresyncsession (PTPParams* params, unsigned char *hash)
1648{
1649	unsigned char	mch[16];
1650	uint32_t	*hashparams = (unsigned int *)mch;
1651	unsigned int	macCount = *(unsigned int *)(hash + 16);
1652	uint16_t	ret;
1653
1654	mtpz_encryption_encrypt_mac(hash, 16, (unsigned char *)(&macCount), 4, mch);
1655
1656	ret = ptp_mtpz_wmdrmpd_enabletrustedfilesoperations(params,
1657		MTPZ_SWAP(hashparams[0]), MTPZ_SWAP(hashparams[1]),
1658		MTPZ_SWAP(hashparams[2]), MTPZ_SWAP(hashparams[3]));
1659	return ret;
1660};
1661
1662static unsigned char *
1663ptp_mtpz_makeapplicationcertificatemessage (unsigned int *out_len, unsigned char **out_random)
1664{
1665	*out_len = 785;
1666
1667	unsigned char *acm = (unsigned char *)malloc(785);
1668	unsigned char *target = acm;
1669	memset(acm, 0, 785);
1670
1671	unsigned char *random = (unsigned char *)malloc(16);
1672
1673	int i = 0;
1674	int certsLength = 0x275;
1675
1676	// Write the marker bytes, length of certificates, and certificates themselves.
1677	*(target++) = '\x02';
1678	*(target++) = '\x01';
1679	*(target++) = '\x01';
1680	*(target++) = '\x00';
1681	*(target++) = '\x00';
1682	*(target++) = '\x02';
1683	*(target++) = '\x75';
1684	memcpy(target, MTPZ_CERTIFICATES, certsLength);
1685	target += certsLength;
1686
1687	// Write the random bytes.
1688	*(target++) = '\x00';	*(target++) = '\x10';
1689	srand(time(NULL));
1690
1691	for (i = 0; i < 16; i++)
1692		*(random + i) = (unsigned char)(rand() % 256);
1693
1694	*out_random = random;
1695	memcpy(target, random, 16);
1696	target += 16;
1697
1698	char *state = mtpz_hash_init_state();
1699	char *v16 = (char *)malloc(28); memset(v16, 0, 28);
1700	char *hash = (char *)malloc(20); memset(hash, 0, 20);
1701	char *odata = (char *)malloc(128); memset(odata, 0, 128);
1702
1703	mtpz_hash_reset_state(state);
1704	mtpz_hash_transform_hash(state, (char *)acm + 2, (target - acm - 2));
1705	mtpz_hash_finalize_hash(state, v16 + 8);
1706
1707	mtpz_hash_reset_state(state);
1708	mtpz_hash_transform_hash(state, v16, 28);
1709	mtpz_hash_finalize_hash(state, hash);
1710
1711	char *v17 = mtpz_hash_custom6A5DC(state, hash, 20, 107);
1712
1713	for (i = 0; i < 20; i++)
1714		odata[107 + i] = hash[i];
1715
1716	odata[106] = '\x01';
1717
1718	if (v17 != NULL)
1719	{
1720		for (i = 0; i < 107; i++)
1721			odata[i] ^= v17[i];
1722
1723		odata[0] &= 127;
1724		odata[127] = 188;
1725	}
1726
1727	// Free up some jazz.
1728	free(state); state = NULL;
1729	free(v16); v16 = NULL;
1730	free(v17); v17 = NULL;
1731	free(hash); hash = NULL;
1732
1733	// Take care of some RSA jazz.
1734	mtpz_rsa_t *rsa = mtpz_rsa_init(MTPZ_MODULUS, MTPZ_PRIVATE_KEY, MTPZ_PUBLIC_EXPONENT);
1735	if (!rsa)
1736	{
1737		LIBMTP_INFO("(MTPZ) Failure - could not instantiate RSA object.\n");
1738		*out_len = 0;
1739		return NULL;
1740	}
1741
1742	char *signature = (char *)malloc(128);
1743	memset(signature, 0, 128);
1744	mtpz_rsa_sign(128, (unsigned char *)odata, 128, (unsigned char *)signature, rsa);
1745
1746	// Free some more things.
1747	mtpz_rsa_free(rsa); rsa = NULL;
1748	free(odata); odata = NULL;
1749
1750	// Write the signature + bytes.
1751	*(target++) = '\x01'; *(target++) = '\x00'; *(target++) = '\x80';
1752	memcpy(target, signature, 128);
1753
1754	// Kill target.
1755	target = NULL;
1756
1757	return acm;
1758};
1759
1760static unsigned char *
1761ptp_mtpz_makeconfirmationmessage (unsigned char *hash, unsigned int *out_len)
1762{
1763	*out_len = 20;
1764	unsigned char *message = (unsigned char *)malloc(20);
1765	message[0] = (unsigned char)0x02;
1766	message[1] = (unsigned char)0x03;
1767	message[2] = (unsigned char)0x00;
1768	message[3] = (unsigned char)0x10;
1769
1770	unsigned char *seed = (unsigned char *)malloc(16);
1771	memset(seed, 0, 16);
1772	seed[15] = (unsigned char)(0x01);
1773
1774	mtpz_encryption_encrypt_mac(hash, 16u, seed, 16u, message + 4);
1775
1776	free(seed);
1777
1778	return message;
1779}
1780
1781uint16_t ptp_mtpz_handshake (PTPParams* params)
1782{
1783	uint16_t ret = PTP_RC_OK;
1784	uint32_t size;
1785	unsigned char *hash=NULL;
1786	unsigned char *random=NULL;
1787	PTPPropertyValue propval;
1788	unsigned char*	applicationCertificateMessage;
1789	unsigned char*	message;
1790
1791	/* FIXME: do other places of libmtp set it? should we set it? */
1792	LIBMTP_INFO ("(MTPZ) Setting session initiator info.\n");
1793	propval.str = "libmtp/Sajid Anwar - MTPZClassDriver";
1794	ret = ptp_setdevicepropvalue(params,
1795		   PTP_DPC_MTP_SessionInitiatorInfo,
1796		   &propval,
1797		   PTP_DTC_STR);
1798	if (ret != PTP_RC_OK)
1799		return ret;
1800
1801	LIBMTP_INFO ("(MTPZ) Resetting handshake.\n");
1802	ret = ptp_mtpz_resethandshake(params);
1803	if (ret != PTP_RC_OK)
1804		return ret;
1805
1806	LIBMTP_INFO ("(MTPZ) Sending application certificate message.\n");
1807	applicationCertificateMessage = ptp_mtpz_makeapplicationcertificatemessage(&size, &random);
1808	ret = ptp_mtpz_sendwmdrmpdapprequest (params, applicationCertificateMessage, size);
1809	free (applicationCertificateMessage);
1810	if (ret != PTP_RC_OK)
1811		return ret;
1812
1813	LIBMTP_INFO ("(MTPZ) Getting and validating handshake response.\n");
1814	ret = ptp_mtpz_validatehandshakeresponse(params, random, &hash);
1815	if (ret != PTP_RC_OK)
1816		goto free_random;
1817
1818	LIBMTP_INFO ("(MTPZ) Sending confirmation message.\n");
1819	message = ptp_mtpz_makeconfirmationmessage(hash, &size);
1820        ret = ptp_mtpz_sendwmdrmpdapprequest (params, message, size);
1821	if (ret != PTP_RC_OK)
1822		goto free_hash;
1823	free (message);
1824
1825	LIBMTP_INFO ("(MTPZ) Opening secure sync session.\n");
1826	ret = ptp_mtpz_opensecuresyncsession(params, hash);
1827free_hash:
1828	free(hash);
1829free_random:
1830	free(random);
1831	return ret;
1832}
1833