1 /***************************************************************************
2  * This code is based on public domain Szymon Stefanek AES implementation: *
3  * http://www.pragmaware.net/software/rijndael/index.php                   *
4  *                                                                         *
5  * Dynamic tables generation is based on the Brian Gladman work:           *
6  * http://fp.gladman.plus.com/cryptography_technology/rijndael             *
7  ***************************************************************************/
8 #include "rar.hpp"
9 
10 #ifndef OPENSSL_AES
11 
12 #ifdef USE_SSE
13 #include <wmmintrin.h>
14 #endif
15 
16 static byte S[256],S5[256],rcon[30];
17 static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4];
18 static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4];
19 static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4];
20 
21 
Xor128(void * dest,const void * arg1,const void * arg2)22 inline void Xor128(void *dest,const void *arg1,const void *arg2)
23 {
24 #ifdef ALLOW_MISALIGNED
25   ((uint32*)dest)[0]=((uint32*)arg1)[0]^((uint32*)arg2)[0];
26   ((uint32*)dest)[1]=((uint32*)arg1)[1]^((uint32*)arg2)[1];
27   ((uint32*)dest)[2]=((uint32*)arg1)[2]^((uint32*)arg2)[2];
28   ((uint32*)dest)[3]=((uint32*)arg1)[3]^((uint32*)arg2)[3];
29 #else
30   for (int I=0;I<16;I++)
31     ((byte*)dest)[I]=((byte*)arg1)[I]^((byte*)arg2)[I];
32 #endif
33 }
34 
35 
Xor128(byte * dest,const byte * arg1,const byte * arg2,const byte * arg3,const byte * arg4)36 inline void Xor128(byte *dest,const byte *arg1,const byte *arg2,
37                    const byte *arg3,const byte *arg4)
38 {
39 #ifdef ALLOW_MISALIGNED
40   (*(uint32*)dest)=(*(uint32*)arg1)^(*(uint32*)arg2)^(*(uint32*)arg3)^(*(uint32*)arg4);
41 #else
42   for (int I=0;I<4;I++)
43     dest[I]=arg1[I]^arg2[I]^arg3[I]^arg4[I];
44 #endif
45 }
46 
47 
Copy128(byte * dest,const byte * src)48 inline void Copy128(byte *dest,const byte *src)
49 {
50 #ifdef ALLOW_MISALIGNED
51   ((uint32*)dest)[0]=((uint32*)src)[0];
52   ((uint32*)dest)[1]=((uint32*)src)[1];
53   ((uint32*)dest)[2]=((uint32*)src)[2];
54   ((uint32*)dest)[3]=((uint32*)src)[3];
55 #else
56   for (int I=0;I<16;I++)
57     dest[I]=src[I];
58 #endif
59 }
60 
61 #endif // OPENSSL_AES
62 
63 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
64 // API
65 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
66 
Rijndael()67 Rijndael::Rijndael()
68 {
69 #ifndef OPENSSL_AES
70   if (S[0]==0)
71     GenerateTables();
72 #endif // OPENSSL_AES
73   CBCMode = true; // Always true for RAR.
74 }
75 
76 
Init(bool Encrypt,const byte * key,uint keyLen,const byte * initVector)77 void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVector)
78 {
79 #ifdef OPENSSL_AES
80   const EVP_CIPHER *cipher;
81   switch(keyLen)
82   {
83     case 128:
84       cipher = EVP_aes_128_cbc();
85       break;
86     case 192:
87       cipher = EVP_aes_192_cbc();
88       break;
89     case 256:
90       cipher = EVP_aes_256_cbc();
91       break;
92   }
93 
94 #if OPENSSL_VERSION_NUMBER < 0x10100000L
95   EVP_CIPHER_CTX_init(&ctx);
96   EVP_CipherInit_ex(&ctx, cipher, NULL, key, initVector, Encrypt);
97   EVP_CIPHER_CTX_set_padding(&ctx, 0);
98 #else
99   EVP_CIPHER_CTX_init(ctx);
100   EVP_CipherInit_ex(ctx, cipher, NULL, key, initVector, Encrypt);
101   EVP_CIPHER_CTX_set_padding(ctx, 0);
102 #endif
103 #else // OPENSSL_AES
104 #ifdef USE_SSE
105   // Check SSE here instead of constructor, so if object is a part of some
106   // structure memset'ed before use, this variable is not lost.
107   int CPUInfo[4];
108   __cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function.
109   if ((CPUInfo[0] & 0x7fffffff)>=1)
110   {
111     __cpuid(CPUInfo, 1);
112     AES_NI=(CPUInfo[2] & 0x2000000)!=0;
113   }
114   else
115     AES_NI=0;
116 #endif
117 
118   // Other developers asked us to initialize it to suppress "may be used
119   // uninitialized" warning in code below in some compilers.
120   uint uKeyLenInBytes=0;
121 
122   switch(keyLen)
123   {
124     case 128:
125       uKeyLenInBytes = 16;
126       m_uRounds = 10;
127       break;
128     case 192:
129       uKeyLenInBytes = 24;
130       m_uRounds = 12;
131       break;
132     case 256:
133       uKeyLenInBytes = 32;
134       m_uRounds = 14;
135       break;
136   }
137 
138   byte keyMatrix[_MAX_KEY_COLUMNS][4];
139 
140   for(uint i = 0; i < uKeyLenInBytes; i++)
141     keyMatrix[i >> 2][i & 3] = key[i];
142 
143   if (initVector==NULL)
144     memset(m_initVector, 0, sizeof(m_initVector));
145   else
146     for(int i = 0; i < MAX_IV_SIZE; i++)
147       m_initVector[i] = initVector[i];
148 
149   keySched(keyMatrix);
150 
151   if(!Encrypt)
152     keyEncToDec();
153 #endif // OPENSSL_AES
154 }
155 
blockEncrypt(const byte * input,size_t inputLen,byte * outBuffer)156 void Rijndael::blockEncrypt(const byte *input,size_t inputLen,byte *outBuffer)
157 {
158   if (inputLen <= 0)
159     return;
160 
161 #ifdef OPENSSL_AES
162   int outLen;
163 #if OPENSSL_VERSION_NUMBER < 0x10100000L
164   EVP_CipherUpdate(&ctx, outBuffer, &outLen, input, inputLen);
165 #else
166   EVP_CipherUpdate(ctx, outBuffer, &outLen, input, inputLen);
167 #endif
168   return;
169 #else // OPENSSL_AES
170   size_t numBlocks = inputLen/16;
171 #ifdef USE_SSE
172   if (AES_NI)
173   {
174     blockEncryptSSE(input,numBlocks,outBuffer);
175     return;
176   }
177 #endif
178 
179   byte *prevBlock = m_initVector;
180   for(size_t i = numBlocks;i > 0;i--)
181   {
182     byte block[16];
183     if (CBCMode)
184       Xor128(block,prevBlock,input);
185     else
186       Copy128(block,input);
187 
188     byte temp[4][4];
189 
190     Xor128(temp,block,m_expandedKey[0]);
191     Xor128(outBuffer,   T1[temp[0][0]],T2[temp[1][1]],T3[temp[2][2]],T4[temp[3][3]]);
192     Xor128(outBuffer+4, T1[temp[1][0]],T2[temp[2][1]],T3[temp[3][2]],T4[temp[0][3]]);
193     Xor128(outBuffer+8, T1[temp[2][0]],T2[temp[3][1]],T3[temp[0][2]],T4[temp[1][3]]);
194     Xor128(outBuffer+12,T1[temp[3][0]],T2[temp[0][1]],T3[temp[1][2]],T4[temp[2][3]]);
195 
196     for(int r = 1; r < m_uRounds-1; r++)
197     {
198       Xor128(temp,outBuffer,m_expandedKey[r]);
199       Xor128(outBuffer,   T1[temp[0][0]],T2[temp[1][1]],T3[temp[2][2]],T4[temp[3][3]]);
200       Xor128(outBuffer+4, T1[temp[1][0]],T2[temp[2][1]],T3[temp[3][2]],T4[temp[0][3]]);
201       Xor128(outBuffer+8, T1[temp[2][0]],T2[temp[3][1]],T3[temp[0][2]],T4[temp[1][3]]);
202       Xor128(outBuffer+12,T1[temp[3][0]],T2[temp[0][1]],T3[temp[1][2]],T4[temp[2][3]]);
203     }
204     Xor128(temp,outBuffer,m_expandedKey[m_uRounds-1]);
205     outBuffer[ 0] = T1[temp[0][0]][1];
206     outBuffer[ 1] = T1[temp[1][1]][1];
207     outBuffer[ 2] = T1[temp[2][2]][1];
208     outBuffer[ 3] = T1[temp[3][3]][1];
209     outBuffer[ 4] = T1[temp[1][0]][1];
210     outBuffer[ 5] = T1[temp[2][1]][1];
211     outBuffer[ 6] = T1[temp[3][2]][1];
212     outBuffer[ 7] = T1[temp[0][3]][1];
213     outBuffer[ 8] = T1[temp[2][0]][1];
214     outBuffer[ 9] = T1[temp[3][1]][1];
215     outBuffer[10] = T1[temp[0][2]][1];
216     outBuffer[11] = T1[temp[1][3]][1];
217     outBuffer[12] = T1[temp[3][0]][1];
218     outBuffer[13] = T1[temp[0][1]][1];
219     outBuffer[14] = T1[temp[1][2]][1];
220     outBuffer[15] = T1[temp[2][3]][1];
221     Xor128(outBuffer,outBuffer,m_expandedKey[m_uRounds]);
222     prevBlock=outBuffer;
223 
224     outBuffer += 16;
225     input += 16;
226   }
227   Copy128(m_initVector,prevBlock);
228 #endif // OPENSSL_AES
229 }
230 
231 
232 #ifdef USE_SSE
blockEncryptSSE(const byte * input,size_t numBlocks,byte * outBuffer)233 void Rijndael::blockEncryptSSE(const byte *input,size_t numBlocks,byte *outBuffer)
234 {
235   __m128i v = _mm_loadu_si128((__m128i*)m_initVector);
236   __m128i *src=(__m128i*)input;
237   __m128i *dest=(__m128i*)outBuffer;
238   __m128i *rkey=(__m128i*)m_expandedKey;
239   while (numBlocks > 0)
240   {
241     __m128i d = _mm_loadu_si128(src++);
242     if (CBCMode)
243       v = _mm_xor_si128(v, d);
244     else
245       v = d;
246     __m128i r0 = _mm_loadu_si128(rkey);
247     v = _mm_xor_si128(v, r0);
248 
249     for (int i=1; i<m_uRounds; i++)
250     {
251       __m128i ri = _mm_loadu_si128(rkey + i);
252       v = _mm_aesenc_si128(v, ri);
253     }
254 
255     __m128i rl = _mm_loadu_si128(rkey + m_uRounds);
256     v = _mm_aesenclast_si128(v, rl);
257     _mm_storeu_si128(dest++,v);
258     numBlocks--;
259   }
260   _mm_storeu_si128((__m128i*)m_initVector,v);
261 }
262 #endif
263 
264 
blockDecrypt(const byte * input,size_t inputLen,byte * outBuffer)265 void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer)
266 {
267   if (inputLen <= 0)
268     return;
269 
270 #ifdef OPENSSL_AES
271   int outLen;
272 #if OPENSSL_VERSION_NUMBER < 0x10100000L
273   EVP_CipherUpdate(&ctx, outBuffer, &outLen, input, inputLen);
274 #else
275   EVP_CipherUpdate(ctx, outBuffer, &outLen, input, inputLen);
276 #endif
277   return;
278 #else // OPENSSL_AES
279   size_t numBlocks=inputLen/16;
280 #ifdef USE_SSE
281   if (AES_NI)
282   {
283     blockDecryptSSE(input,numBlocks,outBuffer);
284     return;
285   }
286 #endif
287 
288   byte block[16], iv[4][4];
289   memcpy(iv,m_initVector,16);
290 
291   for (size_t i = numBlocks; i > 0; i--)
292   {
293     byte temp[4][4];
294 
295     Xor128(temp,input,m_expandedKey[m_uRounds]);
296 
297     Xor128(block,   T5[temp[0][0]],T6[temp[3][1]],T7[temp[2][2]],T8[temp[1][3]]);
298     Xor128(block+4, T5[temp[1][0]],T6[temp[0][1]],T7[temp[3][2]],T8[temp[2][3]]);
299     Xor128(block+8, T5[temp[2][0]],T6[temp[1][1]],T7[temp[0][2]],T8[temp[3][3]]);
300     Xor128(block+12,T5[temp[3][0]],T6[temp[2][1]],T7[temp[1][2]],T8[temp[0][3]]);
301 
302     for(int r = m_uRounds-1; r > 1; r--)
303     {
304       Xor128(temp,block,m_expandedKey[r]);
305       Xor128(block,   T5[temp[0][0]],T6[temp[3][1]],T7[temp[2][2]],T8[temp[1][3]]);
306       Xor128(block+4, T5[temp[1][0]],T6[temp[0][1]],T7[temp[3][2]],T8[temp[2][3]]);
307       Xor128(block+8, T5[temp[2][0]],T6[temp[1][1]],T7[temp[0][2]],T8[temp[3][3]]);
308       Xor128(block+12,T5[temp[3][0]],T6[temp[2][1]],T7[temp[1][2]],T8[temp[0][3]]);
309     }
310 
311     Xor128(temp,block,m_expandedKey[1]);
312     block[ 0] = S5[temp[0][0]];
313     block[ 1] = S5[temp[3][1]];
314     block[ 2] = S5[temp[2][2]];
315     block[ 3] = S5[temp[1][3]];
316     block[ 4] = S5[temp[1][0]];
317     block[ 5] = S5[temp[0][1]];
318     block[ 6] = S5[temp[3][2]];
319     block[ 7] = S5[temp[2][3]];
320     block[ 8] = S5[temp[2][0]];
321     block[ 9] = S5[temp[1][1]];
322     block[10] = S5[temp[0][2]];
323     block[11] = S5[temp[3][3]];
324     block[12] = S5[temp[3][0]];
325     block[13] = S5[temp[2][1]];
326     block[14] = S5[temp[1][2]];
327     block[15] = S5[temp[0][3]];
328     Xor128(block,block,m_expandedKey[0]);
329 
330     if (CBCMode)
331       Xor128(block,block,iv);
332 
333     Copy128((byte*)iv,input);
334     Copy128(outBuffer,block);
335 
336     input += 16;
337     outBuffer += 16;
338   }
339 
340   memcpy(m_initVector,iv,16);
341 
342 #endif // OPENSSL_AES
343 }
344 
345 
346 #ifdef USE_SSE
blockDecryptSSE(const byte * input,size_t numBlocks,byte * outBuffer)347 void Rijndael::blockDecryptSSE(const byte *input, size_t numBlocks, byte *outBuffer)
348 {
349   __m128i initVector = _mm_loadu_si128((__m128i*)m_initVector);
350   __m128i *src=(__m128i*)input;
351   __m128i *dest=(__m128i*)outBuffer;
352   __m128i *rkey=(__m128i*)m_expandedKey;
353   while (numBlocks > 0)
354   {
355     __m128i rl = _mm_loadu_si128(rkey + m_uRounds);
356     __m128i d = _mm_loadu_si128(src++);
357     __m128i v = _mm_xor_si128(rl, d);
358 
359     for (int i=m_uRounds-1; i>0; i--)
360     {
361       __m128i ri = _mm_loadu_si128(rkey + i);
362       v = _mm_aesdec_si128(v, ri);
363     }
364 
365     __m128i r0 = _mm_loadu_si128(rkey);
366     v = _mm_aesdeclast_si128(v, r0);
367 
368     if (CBCMode)
369       v = _mm_xor_si128(v, initVector);
370     initVector = d;
371     _mm_storeu_si128(dest++,v);
372     numBlocks--;
373   }
374   _mm_storeu_si128((__m128i*)m_initVector,initVector);
375 }
376 #endif
377 
378 #ifndef OPENSSL_AES
379 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
380 // ALGORITHM
381 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
382 
383 
keySched(byte key[_MAX_KEY_COLUMNS][4])384 void Rijndael::keySched(byte key[_MAX_KEY_COLUMNS][4])
385 {
386   int j,rconpointer = 0;
387 
388   // Calculate the necessary round keys
389   // The number of calculations depends on keyBits and blockBits
390   int uKeyColumns = m_uRounds - 6;
391 
392   byte tempKey[_MAX_KEY_COLUMNS][4];
393 
394   // Copy the input key to the temporary key matrix
395 
396   memcpy(tempKey,key,sizeof(tempKey));
397 
398   int r = 0;
399   int t = 0;
400 
401   // copy values into round key array
402   for(j = 0;(j < uKeyColumns) && (r <= m_uRounds); )
403   {
404     for(;(j < uKeyColumns) && (t < 4); j++, t++)
405       for (int k=0;k<4;k++)
406         m_expandedKey[r][t][k]=tempKey[j][k];
407 
408     if(t == 4)
409     {
410       r++;
411       t = 0;
412     }
413   }
414 
415   while(r <= m_uRounds)
416   {
417     tempKey[0][0] ^= S[tempKey[uKeyColumns-1][1]];
418     tempKey[0][1] ^= S[tempKey[uKeyColumns-1][2]];
419     tempKey[0][2] ^= S[tempKey[uKeyColumns-1][3]];
420     tempKey[0][3] ^= S[tempKey[uKeyColumns-1][0]];
421     tempKey[0][0] ^= rcon[rconpointer++];
422 
423     if (uKeyColumns != 8)
424       for(j = 1; j < uKeyColumns; j++)
425         for (int k=0;k<4;k++)
426           tempKey[j][k] ^= tempKey[j-1][k];
427     else
428     {
429       for(j = 1; j < uKeyColumns/2; j++)
430         for (int k=0;k<4;k++)
431           tempKey[j][k] ^= tempKey[j-1][k];
432 
433       tempKey[uKeyColumns/2][0] ^= S[tempKey[uKeyColumns/2 - 1][0]];
434       tempKey[uKeyColumns/2][1] ^= S[tempKey[uKeyColumns/2 - 1][1]];
435       tempKey[uKeyColumns/2][2] ^= S[tempKey[uKeyColumns/2 - 1][2]];
436       tempKey[uKeyColumns/2][3] ^= S[tempKey[uKeyColumns/2 - 1][3]];
437       for(j = uKeyColumns/2 + 1; j < uKeyColumns; j++)
438         for (int k=0;k<4;k++)
439           tempKey[j][k] ^= tempKey[j-1][k];
440     }
441     for(j = 0; (j < uKeyColumns) && (r <= m_uRounds); )
442     {
443       for(; (j < uKeyColumns) && (t < 4); j++, t++)
444         for (int k=0;k<4;k++)
445           m_expandedKey[r][t][k] = tempKey[j][k];
446       if(t == 4)
447       {
448         r++;
449         t = 0;
450       }
451     }
452   }
453 }
454 
keyEncToDec()455 void Rijndael::keyEncToDec()
456 {
457   for(int r = 1; r < m_uRounds; r++)
458   {
459     byte n_expandedKey[4][4];
460     for (int i = 0; i < 4; i++)
461       for (int j = 0; j < 4; j++)
462       {
463         byte *w=m_expandedKey[r][j];
464         n_expandedKey[j][i]=U1[w[0]][i]^U2[w[1]][i]^U3[w[2]][i]^U4[w[3]][i];
465       }
466     memcpy(m_expandedKey[r],n_expandedKey,sizeof(m_expandedKey[0]));
467   }
468 }
469 
470 
471 #define ff_poly 0x011b
472 #define ff_hi   0x80
473 
474 #define FFinv(x)    ((x) ? pow[255 - log[x]]: 0)
475 
476 #define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
477 #define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
478 #define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
479 #define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
480 #define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
481 #define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
482 #define fwd_affine(x) \
483     (w = (uint)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), (byte)(0x63^(w^(w>>8))))
484 
485 #define inv_affine(x) \
486     (w = (uint)x, w = (w<<1)^(w<<3)^(w<<6), (byte)(0x05^(w^(w>>8))))
487 
GenerateTables()488 void Rijndael::GenerateTables()
489 {
490   unsigned char pow[512],log[256];
491   int i = 0, w = 1;
492   do
493   {
494     pow[i] = (byte)w;
495     pow[i + 255] = (byte)w;
496     log[w] = (byte)i++;
497     w ^=  (w << 1) ^ (w & ff_hi ? ff_poly : 0);
498   } while (w != 1);
499 
500   for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++)
501   {
502     rcon[i] = w;
503     w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
504   }
505   for(int i = 0; i < 256; ++i)
506   {
507     unsigned char b=S[i]=fwd_affine(FFinv((byte)i));
508     T1[i][1]=T1[i][2]=T2[i][2]=T2[i][3]=T3[i][0]=T3[i][3]=T4[i][0]=T4[i][1]=b;
509     T1[i][0]=T2[i][1]=T3[i][2]=T4[i][3]=FFmul02(b);
510     T1[i][3]=T2[i][0]=T3[i][1]=T4[i][2]=FFmul03(b);
511     S5[i] = b = FFinv(inv_affine((byte)i));
512     U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[i][3]=T6[i][0]=T7[i][1]=T8[i][2]=FFmul0b(b);
513     U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[i][1]=T6[i][2]=T7[i][3]=T8[i][0]=FFmul09(b);
514     U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[i][2]=T6[i][3]=T7[i][0]=T8[i][1]=FFmul0d(b);
515     U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[i][0]=T6[i][1]=T7[i][2]=T8[i][3]=FFmul0e(b);
516   }
517 }
518 #endif // OPENSSL_AES
519 
520 #if 0
521 static void TestRijndael();
522 struct TestRij {TestRij() {TestRijndael();exit(0);}} GlobalTestRij;
523 
524 // Test CBC encryption according to NIST 800-38A.
525 void TestRijndael()
526 {
527   byte IV[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
528   byte PT[64]={
529     0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
530     0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
531     0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef,
532     0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10,
533   };
534 
535   byte Key128[16]={0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c};
536   byte Chk128[16]={0x3f,0xf1,0xca,0xa1,0x68,0x1f,0xac,0x09,0x12,0x0e,0xca,0x30,0x75,0x86,0xe1,0xa7};
537   byte Key192[24]={0x8e,0x73,0xb0,0xf7,0xda,0x0e,0x64,0x52,0xc8,0x10,0xf3,0x2b,0x80,0x90,0x79,0xe5,0x62,0xf8,0xea,0xd2,0x52,0x2c,0x6b,0x7b};
538   byte Chk192[16]={0x08,0xb0,0xe2,0x79,0x88,0x59,0x88,0x81,0xd9,0x20,0xa9,0xe6,0x4f,0x56,0x15,0xcd};
539   byte Key256[32]={0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4};
540   byte Chk256[16]={0xb2,0xeb,0x05,0xe2,0xc3,0x9b,0xe9,0xfc,0xda,0x6c,0x19,0x07,0x8c,0x6a,0x9d,0x1b};
541   byte *Key[3]={Key128,Key192,Key256};
542   byte *Chk[3]={Chk128,Chk192,Chk256};
543 
544   Rijndael rij; // Declare outside of loop to test re-initialization.
545   for (uint L=0;L<3;L++)
546   {
547     byte Out[16];
548     wchar Str[sizeof(Out)*2+1];
549 
550     uint KeyLength=128+L*64;
551     rij.Init(true,Key[L],KeyLength,IV);
552     for (uint I=0;I<sizeof(PT);I+=16)
553       rij.blockEncrypt(PT+I,16,Out);
554     BinToHex(Chk[L],16,NULL,Str,ASIZE(Str));
555     mprintf(L"\nAES-%d expected: %s",KeyLength,Str);
556     BinToHex(Out,sizeof(Out),NULL,Str,ASIZE(Str));
557     mprintf(L"\nAES-%d result:   %s",KeyLength,Str);
558     if (memcmp(Out,Chk[L],16)==0)
559       mprintf(L" OK");
560     else
561     {
562       mprintf(L" FAILED");
563       getchar();
564     }
565   }
566 }
567 #endif
568