"Fossies" - the Fresh Open Source Software Archive

Member "unrar/rijndael.cpp" (4 May 2022, 16116 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rijndael.cpp" see the Fossies "Dox" file reference documentation.

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