| Remote Access Control |

# aes.c

Go to the documentation of this file.

    00001 // This file has been prepared for Doxygen automatic documentation generation.
    00048 #include "aes.h"
    00049 #include "common.h"
    00050 #include "config.h"
    00051
    00052
    00053
    00055 #define BPOLY 0x1b
    00056
    00057
    00058
    00060 const byte __flash sBox[256] = {
    00061         0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
    00062         0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
    00063         0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
    00064         0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
    00065         0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
    00066         0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
    00067         0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
    00068         0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
    00069         0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
    00070         0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
    00071         0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
    00072         0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
    00073         0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
    00074         0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
    00075         0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
    00076         0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
    00077         0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
    00078         0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
    00079         0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
    00080         0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
    00081         0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
    00082         0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
    00083         0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
    00084         0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
    00085         0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
    00086         0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
    00087         0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
    00088         0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
    00089         0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
    00090         0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
    00091         0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
    00092         0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
    00093 };
    00094
    00096 const byte __flash sBoxInv[256] = {
    00097         0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
    00098         0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
    00099         0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
    00100         0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
    00101         0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
    00102         0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
    00103         0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
    00104         0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
    00105         0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
    00106         0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
    00107         0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
    00108         0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
    00109         0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
    00110         0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
    00111         0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
    00112         0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
    00113         0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
    00114         0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
    00115         0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
    00116         0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
    00117         0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
    00118         0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
    00119         0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
    00120         0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
    00121         0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
    00122         0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
    00123         0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
    00124         0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
    00125         0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
    00126         0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
    00127         0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
    00128         0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
    00129 };
    00130
    00131
    00132
    00134 static void cycleLeft( byte * row )
    00135 {
    00136         // Cycle 4 bytes in an array left once.
    00137         byte temp = row[0];
    00138         row[0] = row[1];
    00139         row[1] = row[2];
    00140         row[2] = row[3];
    00141         row[3] = temp;
    00142 }
    00143
    00144
    00145
    00147 static void mixColumn( byte * column )
    00148 {
    00149         byte result0, result1, result2, result3;
    00150         byte column0, column1, column2, column3;
    00151
    00152         // This generates more effective code, at least
    00153         // with the IAR C compiler.
    00154         column0 = column[0];
    00155         column1 = column[1];
    00156         column2 = column[2];
    00157         column3 = column[3];
    00158
    00159         // Partial sums (modular addition using XOR).
    00160         result0 = column1 ^ column2 ^ column3;
    00161         result1 = column0 ^ column2 ^ column3;
    00162         result2 = column0 ^ column1 ^ column3;
    00163         result3 = column0 ^ column1 ^ column2;
    00164
    00165         // Multiply column bytes by 2 modulo BPOLY.
    00166         // This operation is done the following way to ensure cycle count
    00167         // independent from data contents. Take care when changing this code.
    00168         xor = 0;
    00169         if (column0 & 0x80) {
    00170                 xor = BPOLY;
    00171         }
    00172         column0 <<= 1;
    00173         column0  ^= xor;
    00174
    00175         xor = 0;
    00176         if (column1 & 0x80) {
    00177                 xor = BPOLY;
    00178         }
    00179         column1 <<= 1;
    00180         column1  ^= xor;
    00181
    00182         xor = 0;
    00183         if (column2 & 0x80) {
    00184                 xor = BPOLY;
    00185         }
    00186         column2 <<= 1;
    00187         column2  ^= xor;
    00188
    00189         xor = 0;
    00190         if (column3 & 0x80) {
    00191                 xor = BPOLY;
    00192         }
    00193         column3 <<= 1;
    00194         column3  ^= xor;
    00195
    00196         // Final sums stored into original column bytes.
    00197         column[0] = result0 ^ column0 ^ column1;
    00198         column[1] = result1 ^ column1 ^ column2;
    00199         column[2] = result2 ^ column2 ^ column3;
    00200         column[3] = result3 ^ column0 ^ column3;
    00201 }
    00202
    00203
    00204
    00206 static void mixColumns( byte * state )
    00207 {
    00208         mixColumn( state + 0*4 );
    00209         mixColumn( state + 1*4 );
    00210         mixColumn( state + 2*4 );
    00211         mixColumn( state + 3*4 );
    00212 }
    00213
    00214
    00215
    00217 static void subBytes( byte * bytes, byte count )
    00218 {
    00219         // Copy to temporary variables for optimization.
    00220         byte * tempPtr = bytes;
    00221         byte tempCount = count;
    00222
    00223         do {
    00224                 *tempPtr = sBox[ *tempPtr ]; // Substitute every byte in state.
    00225                 ++tempPtr;
    00226         } while( --tempCount );
    00227 }
    00228
    00229
    00230
    00232 static void shiftRows( byte * state )
    00233 {
    00234         byte temp;
    00235
    00236         // Note: State is arranged column by column.
    00237
    00238         // Cycle second row left one time.
    00239         temp = state[ 1 + 0*4 ];
    00240         state[ 1 + 0*4 ] = state[ 1 + 1*4 ];
    00241         state[ 1 + 1*4 ] = state[ 1 + 2*4 ];
    00242         state[ 1 + 2*4 ] = state[ 1 + 3*4 ];
    00243         state[ 1 + 3*4 ] = temp;
    00244
    00245         // Cycle third row left two times.
    00246         temp = state[ 2 + 0*4 ];
    00247         state[ 2 + 0*4 ] = state[ 2 + 2*4 ];
    00248         state[ 2 + 2*4 ] = temp;
    00249         temp = state[ 2 + 1*4 ];
    00250         state[ 2 + 1*4 ] = state[ 2 + 3*4 ];
    00251         state[ 2 + 3*4 ] = temp;
    00252
    00253         // Cycle fourth row left three times, ie. right once.
    00254         temp = state[ 3 + 3*4 ];
    00255         state[ 3 + 3*4 ] = state[ 3 + 2*4 ];
    00256         state[ 3 + 2*4 ] = state[ 3 + 1*4 ];
    00257         state[ 3 + 1*4 ] = state[ 3 + 0*4 ];
    00258         state[ 3 + 0*4 ] = temp;
    00259 }
    00260
    00261
    00262
    00264 static void invMixColumn( byte * column )
    00265 {
    00266         byte result0, result1, result2, result3;
    00267         byte column0, column1, column2, column3;
    00268         byte xor;
    00269
    00270         // This generates more effective code, at least
    00271         // with the IAR C compiler.
    00272         column0 = column[0];
    00273         column1 = column[1];
    00274         column2 = column[2];
    00275         column3 = column[3];
    00276
    00277         // Partial sums (modular addition using XOR).
    00278         result0 = column1 ^ column2 ^ column3;
    00279         result1 = column0 ^ column2 ^ column3;
    00280         result2 = column0 ^ column1 ^ column3;
    00281         result3 = column0 ^ column1 ^ column2;
    00282
    00283         // Multiply column bytes by 2 modulo BPOLY.
    00284         // This operation is done the following way to ensure cycle count
    00285         // independent from data contents. Take care when changing this code.
    00286         xor = 0;
    00287         if (column0 & 0x80) {
    00288                 xor = BPOLY;
    00289         }
    00290         column0 <<= 1;
    00291         column0  ^= xor;
    00292
    00293         xor = 0;
    00294         if (column1 & 0x80) {
    00295                 xor = BPOLY;
    00296         }
    00297         column1 <<= 1;
    00298         column1  ^= xor;
    00299
    00300         xor = 0;
    00301         if (column2 & 0x80) {
    00302                 xor = BPOLY;
    00303         }
    00304         column2 <<= 1;
    00305         column2  ^= xor;
    00306
    00307         xor = 0;
    00308         if (column3 & 0x80) {
    00309                 xor = BPOLY;
    00310         }
    00311         column3 <<= 1;
    00312         column3  ^= xor;
    00313
    00314         // More partial sums.
    00315         result0 ^= column0 ^ column1;
    00316         result1 ^= column1 ^ column2;
    00317         result2 ^= column2 ^ column3;
    00318         result3 ^= column0 ^ column3;
    00319
    00320         // Multiply column bytes by 2 modulo BPOLY.
    00321         // This operation is done the following way to ensure cycle count
    00322         // independent from data contents. Take care when changing this code.
    00323         xor = 0;
    00324         if (column0 & 0x80) {
    00325                 xor = BPOLY;
    00326         }
    00327         column0 <<= 1;
    00328         column0  ^= xor;
    00329
    00330         xor = 0;
    00331         if (column1 & 0x80) {
    00332                 xor = BPOLY;
    00333         }
    00334         column1 <<= 1;
    00335         column1  ^= xor;
    00336
    00337         xor = 0;
    00338         if (column2 & 0x80) {
    00339                 xor = BPOLY;
    00340         }
    00341         column2 <<= 1;
    00342         column2  ^= xor;
    00343
    00344         xor = 0;
    00345         if (column3 & 0x80) {
    00346                 xor = BPOLY;
    00347         }
    00348         column3 <<= 1;
    00349         column3  ^= xor;
    00350
    00351         // More partial sums.
    00352         result0 ^= column0 ^ column2;
    00353         result1 ^= column1 ^ column3;
    00354         result2 ^= column0 ^ column2;
    00355         result3 ^= column1 ^ column3;
    00356
    00357         // Multiply column bytes by 2 modulo BPOLY.
    00358         // This operation is done the following way to ensure cycle count
    00359         // independent from data contents. Take care when changing this code.
    00360         xor = 0;
    00361         if (column0 & 0x80) {
    00362                 xor = BPOLY;
    00363         }
    00364         column0 <<= 1;
    00365         column0  ^= xor;
    00366
    00367         xor = 0;
    00368         if (column1 & 0x80) {
    00369                 xor = BPOLY;
    00370         }
    00371         column1 <<= 1;
    00372         column1  ^= xor;
    00373
    00374         xor = 0;
    00375         if (column2 & 0x80) {
    00376                 xor = BPOLY;
    00377         }
    00378         column2 <<= 1;
    00379         column2  ^= xor;
    00380
    00381         xor = 0;
    00382         if (column3 & 0x80) {
    00383                 xor = BPOLY;
    00384         }
    00385         column3 <<= 1;
    00386         column3  ^= xor;
    00387
    00388         // Final partial sum.
    00389         column0 ^= column1 ^ column2 ^ column3;
    00390
    00391         // Final sums stored indto original column bytes.
    00392         column[0] = result0 ^ column0;
    00393         column[1] = result1 ^ column0;
    00394         column[2] = result2 ^ column0;
    00395         column[3] = result3 ^ column0;
    00396 }
    00397
    00398
    00399
    00401 static void invMixColumns( byte * state )
    00402 {
    00403         invMixColumn( state + 0*4 );
    00404         invMixColumn( state + 1*4 );
    00405         invMixColumn( state + 2*4 );
    00406         invMixColumn( state + 3*4 );
    00407 }
    00408
    00409
    00410
    00412 static void invShiftRows( byte * state )
    00413 {
    00414         byte temp;
    00415
    00416         // Note: State is arranged column by column.
    00417
    00418         // Cycle second row right one time.
    00419         temp = state[ 1 + 3*4 ];
    00420         state[ 1 + 3*4 ] = state[ 1 + 2*4 ];
    00421         state[ 1 + 2*4 ] = state[ 1 + 1*4 ];
    00422         state[ 1 + 1*4 ] = state[ 1 + 0*4 ];
    00423         state[ 1 + 0*4 ] = temp;
    00424
    00425         // Cycle third row right two times.
    00426         temp = state[ 2 + 0*4 ];
    00427         state[ 2 + 0*4 ] = state[ 2 + 2*4 ];
    00428         state[ 2 + 2*4 ] = temp;
    00429         temp = state[ 2 + 1*4 ];
    00430         state[ 2 + 1*4 ] = state[ 2 + 3*4 ];
    00431         state[ 2 + 3*4 ] = temp;
    00432
    00433         // Cycle fourth row right three times, ie. left once.
    00434         temp = state[ 3 + 0*4 ];
    00435         state[ 3 + 0*4 ] = state[ 3 + 1*4 ];
    00436         state[ 3 + 1*4 ] = state[ 3 + 2*4 ];
    00437         state[ 3 + 2*4 ] = state[ 3 + 3*4 ];
    00438         state[ 3 + 3*4 ] = temp;
    00439 }
    00440
    00441
    00442
    00443 #if KEY_SIZE == 24 // Only needed for 192 bit keys.
    00445 static void addConstantAndCopy( byte * bytes, const byte * constant, byte * destination, byte count )
    00446 {
    00447         // Copy to temporary variables for optimization.
    00448         byte * tempBlock = bytes;
    00449         const byte * tempSource = constant;
    00450         byte * tempDestination = destination;
    00451         byte tempCount = count;
    00452         byte tempValue;
    00453
    00454         do {
    00455                  // Add in GF(2), ie. XOR.
    00456                 tempValue = *tempBlock ^ *tempSource++;
    00457                 *tempBlock++ = tempValue;
    00458                 *tempDestination++ = tempValue;
    00459         } while( --tempCount );
    00460 }
    00461 #endif
    00462
    00463
    00464
    00465 #if KEY_SIZE == 16 || KEY_SIZE == 32
    00467 static void addAndCopy( byte * buf1, byte * buf2, byte count )
    00468 {
    00469         // Copy to temporary variables for optimization.
    00470         byte * tempBuf1 = buf1;
    00471         byte * tempBuf2 = buf2;
    00472         byte tempCount = count;
    00473         byte tempValue;
    00474
    00475         do {
    00476                  // Add in GF(2), ie. XOR.
    00477                 tempValue = *tempBuf1 ^ *tempBuf2;
    00478                 *tempBuf1++ = tempValue;
    00479                 *tempBuf2++ = tempValue;
    00480         } while( --tempCount );
    00481 }
    00482 #endif
    00483
    00484
    00485
    00486 #if KEY_SIZE == 24 // Only used for 192 bit keys.
    00488 static void addAndStore( const byte * buf1, const byte * buf2, byte * destination, byte count )
    00489 {
    00490         // Copy to temporary variables for optimization.
    00491         const byte * tempBuf1 = buf1;
    00492         const byte * tempBuf2 = buf2;
    00493         byte * tempDestination = destination;
    00494         byte tempCount = count;
    00495         byte tempValue;
    00496
    00497         do {
    00498                  // Add in GF(2), ie. XOR.
    00499                 tempValue = *tempBuf1++ ^ *tempBuf2++;
    00500                 *tempDestination++ = tempValue;
    00501         } while( --tempCount );
    00502 }
    00503 #endif
    00504
    00505
    00506
    00508 static void addConstantAndSubstitute( byte * bytes, const byte * constant, byte count )
    00509 {
    00510         // Copy to temporary variables for optimization.
    00511         byte * tempDestination = bytes;
    00512         const byte * tempSource = constant;
    00513         byte tempCount = count;
    00514         byte tempValue;
    00515
    00516         do {
    00517                 // Add in GF(2), ie. XOR.
    00518                 tempValue = *tempDestination ^ *tempSource++;
    00519                 *tempDestination++ = sBox[ tempValue ];
    00520         } while( --tempCount );
    00521 }
    00522
    00523
    00524
    00526 static void invSubstituteAndAddConstant( byte * bytes, const byte * constant, byte count )
    00527 {
    00528         // Copy to temporary variables for optimization.
    00529         byte * tempDestination = bytes;
    00530         const byte * tempSource = constant;
    00531         byte tempCount = count;
    00532         byte tempValue;
    00533
    00534         do {
    00535                 // Add in GF(2), ie. XOR.
    00536                 tempValue = *tempDestination;
    00537                 *tempDestination++ = sBoxInv[ tempValue ] ^ *tempSource++;
    00538         } while( --tempCount );
    00539 }
    00540
    00541
    00542
    00544 static void keyExpansion( byte * scheduleBuffer, byte * roundConstant )
    00545 {
    00546         byte tempWord[4];
    00547         byte schedulePos = 0;
    00548
    00549         // Get last word from previous schedule buffer.
    00550         copyBytes( tempWord, scheduleBuffer + SCHEDULE_BUFFER_SIZE - 4, 4 );
    00551
    00552         // Transform it, since we are at a KEY_SIZE boundary in the schedule.
    00553         cycleLeft( tempWord );
    00554         subBytes( tempWord, 4 );
    00555         addConstant( tempWord, roundConstant, 4 );
    00556
    00557         // Update round constant.
    00558         if( roundConstant[0] & 0x80 ) {
    00559                 roundConstant[0] <<= 1;
    00560                 roundConstant[0] ^= BPOLY;
    00561         } else {
    00562                 roundConstant[0] <<= 1;
    00563         }
    00564
    00565 #if KEY_SIZE == 16 || KEY_SIZE == 32
    00566
    00567   #if KEY_SIZE == 32
    00568         do {
    00569                 // Add value from one KEY_SIZE backwards, ie. in last schedule buffer.
    00570                 // Store in buffer, replacing old value, which was one KEY_SIZE backwards.
    00571                 addAndCopy( tempWord, scheduleBuffer, 4 );
    00572
    00573                 // Move to next word in schedule buffer.
    00574                 scheduleBuffer += 4;
    00575                 schedulePos += 4;
    00576
    00577         } while( schedulePos < BLOCK_SIZE );
    00578
    00579         // Substitute previous word when at BLOCK_SIZE boundary with 256 bit keys.
    00580         subBytes( tempWord, 4 );
    00581   #endif
    00582
    00583         do {
    00584                 // Add value from one KEY_SIZE backwards, ie. in last schedule buffer.
    00585                 // Store in buffer, replacing old value, which was one KEY_SIZE backwards.
    00586                 addAndCopy( tempWord, scheduleBuffer, 4 );
    00587
    00588                 // Move to next word in schedule buffer.
    00589                 scheduleBuffer += 4;
    00590                 schedulePos += 4;
    00591
    00592         } while( schedulePos < SCHEDULE_BUFFER_SIZE );
    00593
    00594 #elif KEY_SIZE == 24
    00595         do {
    00596                 // Add value from one KEY_SIZE backwards (wraps to end of buffer).
    00597                 // Store in buffer, replacing old value.
    00598                 addConstantAndCopy( tempWord, scheduleBuffer + KEY_SIZE, scheduleBuffer, 4 );
    00599
    00600                 // Move to next word in schedule buffer.
    00601                 scheduleBuffer += 4;
    00602                 schedulePos += 4;
    00603
    00604         } while( schedulePos < KEY_SIZE );
    00605
    00606         // Transform previous word, since we are at a KEY_SIZE boundary in the schedule.
    00607         cycleLeft( tempWord );
    00608         subBytes( tempWord, 4 );
    00609         addConstant( tempWord, roundConstant, 4 );
    00610
    00611         // Update round constant.
    00612         if( roundConstant[0] & 0x80 ) {
    00613                 roundConstant[0] <<= 1;
    00614                 roundConstant[0] ^= BPOLY;
    00615         } else {
    00616                 roundConstant[0] <<= 1;
    00617         }
    00618
    00619         do {
    00620                 // Add value from one KEY_SIZE backwards.
    00621                 // Store in buffer, replacing old value.
    00622                 addConstantAndCopy( tempWord, scheduleBuffer - KEY_SIZE, scheduleBuffer, 4 );
    00623
    00624                 // Move to next word in schedule buffer.
    00625                 scheduleBuffer += 4;
    00626                 schedulePos += 4;
    00627
    00628         } while( schedulePos < SCHEDULE_BUFFER_SIZE );
    00629
    00630 #else
    00631   #error Unsupported key size.
    00632 #endif
    00633 }
    00634
    00635
    00636
    00637 #if SCHEDULE_KEY_REPETITIONS > 1 // Only applies when more than one round key is calculated at a time.
    00640 static void initialKeyExpansion( byte * scheduleBuffer, byte * roundConstant )
    00641 {
    00642   #if KEY_SIZE == 24 // Currently only required for 192-bit keys.
    00643         byte tempWord[4];
    00644         byte schedulePos = SCHEDULE_BUFFER_SIZE / 2;
    00645         scheduleBuffer += SCHEDULE_BUFFER_SIZE / 2;
    00646
    00647         // Get last word from previous key in schedule buffer.
    00648         copyBytes( tempWord, scheduleBuffer - 4, 4 );
    00649
    00650         // Transform it, since we are at a KEY_SIZE boundary in the schedule.
    00651         cycleLeft( tempWord );
    00652         subBytes( tempWord, 4 );
    00653         addConstant( tempWord, roundConstant, 4 );
    00654
    00655         // Update round constant.
    00656         if( roundConstant[0] & 0x80 ) {
    00657                 roundConstant[0] <<= 1;
    00658                 roundConstant[0] ^= BPOLY;
    00659         } else {
    00660                 roundConstant[0] <<= 1;
    00661         }
    00662
    00663         do {
    00664                 // Add value from one KEY_SIZE backwards.
    00665                 // Store in buffer.
    00666                 addConstantAndCopy( tempWord, scheduleBuffer - KEY_SIZE, scheduleBuffer, 4 );
    00667
    00668                 // Move to next word in schedule buffer.
    00669                 scheduleBuffer += 4;
    00670                 schedulePos += 4;
    00671
    00672         } while( schedulePos < SCHEDULE_BUFFER_SIZE );
    00673
    00674   #else
    00675     #error Unsupported key size.
    00676   #endif
    00677 }
    00678 #endif
    00679
    00680
    00681
    00683 static void invKeyExpansion( byte * scheduleBuffer, byte * roundConstant )
    00684 {
    00685         byte tempWord[4];
    00686
    00687 #if KEY_SIZE == 16 || KEY_SIZE == 32
    00688         byte schedulePos = SCHEDULE_BUFFER_SIZE - 4;
    00689         scheduleBuffer += SCHEDULE_BUFFER_SIZE - 4;
    00690
    00691   #if KEY_SIZE == 32
    00692         do {
    00693                 // Add with previous word.
    00694                 addConstant( scheduleBuffer, scheduleBuffer - 4, 4 );
    00695
    00696                 // Move to previous word in schedule.
    00697                 scheduleBuffer -= 4;
    00698                 schedulePos -= 4;
    00699
    00700         } while( schedulePos > BLOCK_SIZE );
    00701
    00702         // Prepare substitution of previous word.
    00703         copyBytes( tempWord, scheduleBuffer - 4, 4 );
    00704         subBytes( tempWord, 4 );
    00705
    00706         // Add substituted word to current word.
    00707         addConstant( scheduleBuffer, tempWord, 4 );
    00708
    00709         // Move to previous word in schedule.
    00710         scheduleBuffer -= 4;
    00711         schedulePos -= 4;
    00712   #endif
    00713
    00714         do {
    00715                 // Add with previous word.
    00716                 addConstant( scheduleBuffer, scheduleBuffer - 4, 4 );
    00717
    00718                 // Move to previous word in schedule.
    00719                 scheduleBuffer -= 4;
    00720                 schedulePos -= 4;
    00721
    00722         } while( schedulePos > 0 );
    00723
    00724         // Prepare round constant for transformation that follows.
    00725         if( (roundConstant[0] ^ BPOLY) == 0 ) {
    00726                 roundConstant[0] = 0x80;
    00727         } else {
    00728                 roundConstant[0] >>= 1;
    00729         }
    00730
    00731         // Prepare transformation of previous word (which is now at end of buffer).
    00732         copyBytes( tempWord, scheduleBuffer + SCHEDULE_BUFFER_SIZE - 4, 4 );
    00733         cycleLeft( tempWord );
    00734         subBytes( tempWord, 4 );
    00735         addConstant( tempWord, roundConstant, 4 );
    00736
    00737         // Apply transformation result to current word.
    00738         addConstant( scheduleBuffer, tempWord, 4 );
    00739
    00740 #elif KEY_SIZE == 24
    00741         // Move to end of first KEY_SIZE in schedule.
    00742         byte schedulePos = (SCHEDULE_BUFFER_SIZE/2) - 4;
    00743         scheduleBuffer += (SCHEDULE_BUFFER_SIZE/2) - 4;
    00744
    00745         do {
    00746                 // Get current word.
    00747                 // Add with previous word.
    00748                 // Store at position one KEY_SIZE backwards (wraps to end of buffer).
    00749                 addAndStore( scheduleBuffer, scheduleBuffer - 4, scheduleBuffer + KEY_SIZE, 4 );
    00750
    00751                 // Move to previous word in schedule.
    00752                 scheduleBuffer -= 4;
    00753                 schedulePos -= 4;
    00754
    00755         } while( schedulePos > 0 );
    00756
    00757         // Prepare round constant for transformation that follows.
    00758         if( (roundConstant[0] ^ BPOLY) == 0 ) {
    00759                 roundConstant[0] = 0x80;
    00760         } else {
    00761                 roundConstant[0] >>= 1;
    00762         }
    00763
    00764         // Prepare transformation of previous word (which is now at end of buffer).
    00765         copyBytes( tempWord, scheduleBuffer + SCHEDULE_BUFFER_SIZE - 4, 4 );
    00766         cycleLeft( tempWord );
    00767         subBytes( tempWord, 4 );
    00768         addConstant( tempWord, roundConstant, 4 );
    00769
    00770         // Add current word to transformation result.
    00771         addConstant( tempWord, scheduleBuffer, 4 );
    00772         // Store at position one KEY_SIZE backwards (wraps to end of buffer).
    00773         copyBytes( scheduleBuffer + KEY_SIZE, tempWord, 4 );
    00774
    00775         // Move to last word in schedule.
    00776         schedulePos = SCHEDULE_BUFFER_SIZE - 4;
    00777         scheduleBuffer += SCHEDULE_BUFFER_SIZE - 4;
    00778
    00779         do {
    00780                 // Get current word.
    00781                 // Add with previous word.
    00782                 // Store at position one KEY_SIZE backwards.
    00783                 addAndStore( scheduleBuffer, scheduleBuffer - 4, scheduleBuffer - KEY_SIZE, 4 );
    00784
    00785                 // Move to previous word in schedule.
    00786                 scheduleBuffer -= 4;
    00787                 schedulePos -= 4;
    00788
    00789         } while( schedulePos > KEY_SIZE );
    00790
    00791         // Prepare round constant for transformation that follows.
    00792         if( (roundConstant[0] ^ BPOLY) == 0 ) {
    00793                 roundConstant[0] = 0x80;
    00794         } else {
    00795                 roundConstant[0] >>= 1;
    00796         }
    00797
    00798         // Prepare transformation of previous word.
    00799         copyBytes( tempWord, scheduleBuffer - 4, 4 );
    00800         cycleLeft( tempWord );
    00801         subBytes( tempWord, 4 );
    00802         addConstant( tempWord, roundConstant, 4 );
    00803
    00804         // Add current word to transformation result.
    00805         addConstant( tempWord, scheduleBuffer, 4 );
    00806         // Store at position one KEY_SIZE backwards.
    00807         copyBytes( scheduleBuffer - KEY_SIZE, tempWord, 4 );
    00808
    00809 #else
    00810   #error Unsupported key size.
    00811 #endif
    00812 }
    00813
    00814
    00815
    00817 static void calcLastRoundKey( byte * scheduleBuffer )
    00818 {
    00819         byte roundConstant[ 4 ] = { 0x01, 0x00, 0x00, 0x00 };
    00820
    00821 #if SCHEDULE_KEY_REPETITIONS > 1
    00822         initialKeyExpansion( scheduleBuffer, roundConstant );
    00823 #endif
    00824
    00825         byte round;
    00826         for( round = 1; round < ROUNDS+1; round += SCHEDULE_BLOCK_REPETITIONS ) {
    00827                 keyExpansion( scheduleBuffer, roundConstant );
    00828         }
    00829 }
    00830
    00831
    00832
    00833 void cipher( byte * block, byte * scheduleBuffer, const byte * key )
    00834 {
    00835         byte roundConstant[4] = { 0x01, 0x00, 0x00, 0x00 };
    00836
    00837         copyBytes( scheduleBuffer, key, KEY_SIZE );
    00838 #if SCHEDULE_KEY_REPETITIONS > 1
    00839         initialKeyExpansion( scheduleBuffer, roundConstant );
    00840 #endif
    00841
    00842 #if KEY_SIZE == 16
    00843         byte round;
    00844         for( round = 0; round < ROUNDS-1; ++round ) {
    00845                 addConstantAndSubstitute( block, scheduleBuffer, BLOCK_SIZE );
    00846                 shiftRows( block );
    00847                 mixColumns( block );
    00848
    00849                 keyExpansion( scheduleBuffer, roundConstant );
    00850         }
    00851
    00852         addConstantAndSubstitute( block, scheduleBuffer, BLOCK_SIZE );
    00853         shiftRows( block );
    00854
    00855         keyExpansion( scheduleBuffer, roundConstant );
    00856         addConstant( block, scheduleBuffer, BLOCK_SIZE );
    00857
    00858 #elif KEY_SIZE == 24
    00859         byte round;
    00860         for( round = 0; round < ROUNDS-3; round += 3 ) {
    00861                 addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*0, BLOCK_SIZE );
    00862                 shiftRows( block );
    00863                 mixColumns( block );
    00864
    00865                 addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*1, BLOCK_SIZE );
    00866                 shiftRows( block );
    00867                 mixColumns( block );
    00868
    00869                 addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*2, BLOCK_SIZE );
    00870                 shiftRows( block );
    00871                 mixColumns( block );
    00872
    00873                 keyExpansion( scheduleBuffer, roundConstant );
    00874         }
    00875
    00876         addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*0, BLOCK_SIZE );
    00877         shiftRows( block );
    00878         mixColumns( block );
    00879
    00880         addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*1, BLOCK_SIZE );
    00881         shiftRows( block );
    00882         mixColumns( block );
    00883
    00884         addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*2, BLOCK_SIZE );
    00885         shiftRows( block );
    00886
    00887         keyExpansion( scheduleBuffer, roundConstant );
    00888         addConstant( block, scheduleBuffer, BLOCK_SIZE );
    00889
    00890 #elif KEY_SIZE == 32
    00891         byte round;
    00892         for( round = 0; round < ROUNDS-2; round += 2 ) {
    00893                 addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*0, BLOCK_SIZE );
    00894                 shiftRows( block );
    00895                 mixColumns( block );
    00896
    00897                 addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*1, BLOCK_SIZE );
    00898                 shiftRows( block );
    00899                 mixColumns( block );
    00900
    00901                 keyExpansion( scheduleBuffer, roundConstant );
    00902         }
    00903
    00904         addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*0, BLOCK_SIZE );
    00905         shiftRows( block );
    00906         mixColumns( block );
    00907
    00908         addConstantAndSubstitute( block, scheduleBuffer + BLOCK_SIZE*1, BLOCK_SIZE );
    00909         shiftRows( block );
    00910
    00911         keyExpansion( scheduleBuffer, roundConstant );
    00912         addConstant( block, scheduleBuffer, BLOCK_SIZE );
    00913
    00914 #else
    00915   #error Unsupported key size.
    00916 #endif
    00917 }
    00918
    00919
    00920
    00921 void prepareInvCipher( byte * scheduleBuffer, const byte * key )
    00922 {
    00923         copyBytes( scheduleBuffer, key, KEY_SIZE );
    00924         calcLastRoundKey( scheduleBuffer );
    00925 }
    00926
    00927
    00928
    00929 void invCipher( byte * block, byte * scheduleBuffer )
    00930 {
    00931         byte roundConstant[4] = { LAST_ROUND_CONSTANT, 0x00, 0x00, 0x00 };
    00932
    00933 #if KEY_SIZE == 16
    00934         addConstant( block, scheduleBuffer, BLOCK_SIZE );
    00935
    00936         byte round;
    00937         for( round = 0; round < ROUNDS-1; ++round ) {
    00938                 invKeyExpansion( scheduleBuffer, roundConstant );
    00939
    00940                 invShiftRows( block );
    00941                 invSubstituteAndAddConstant( block, scheduleBuffer, BLOCK_SIZE );
    00942                 invMixColumns( block );
    00943         }
    00944
    00945         invKeyExpansion( scheduleBuffer, roundConstant );
    00946
    00947         invShiftRows( block );
    00948         invSubstituteAndAddConstant( block, scheduleBuffer, BLOCK_SIZE );
    00949
    00950 #elif KEY_SIZE == 24
    00951         // Backtrace last update of round constant, since it is never
    00952         // used, due to the use of two KEY_SIZEs in schedule buffer.
    00953         if( (roundConstant[0] ^ BPOLY) == 0 ) {
    00954                 roundConstant[0] = 0x80;
    00955         } else {
    00956                 roundConstant[0] >>= 1;
    00957         }
    00958
    00959         addConstant( block, scheduleBuffer, BLOCK_SIZE );
    00960
    00961         byte round;
    00962         for( round = 0; round < ROUNDS-3; round += 3 ) {
    00963                 invKeyExpansion( scheduleBuffer, roundConstant );
    00964
    00965                 invShiftRows( block );
    00966                 invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE*2, BLOCK_SIZE );
    00967                 invMixColumns( block );
    00968
    00969                 invShiftRows( block );
    00970                 invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE*1, BLOCK_SIZE );
    00971                 invMixColumns( block );
    00972
    00973                 invShiftRows( block );
    00974                 invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE*0, BLOCK_SIZE );
    00975                 invMixColumns( block );
    00976         }
    00977
    00978         invKeyExpansion( scheduleBuffer, roundConstant );
    00979
    00980         invShiftRows( block );
    00981         invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE*2, BLOCK_SIZE );
    00982         invMixColumns( block );
    00983
    00984         invShiftRows( block );
    00985         invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE*1, BLOCK_SIZE );
    00986         invMixColumns( block );
    00987
    00988         invShiftRows( block );
    00989         invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE*0, BLOCK_SIZE );
    00990
    00991 #elif KEY_SIZE == 32
    00992         addConstant( block, scheduleBuffer, BLOCK_SIZE );
    00993
    00994         byte round;
    00995         for( round = 0; round < ROUNDS-2; round += 2 ) {
    00996                 invKeyExpansion( scheduleBuffer, roundConstant );
    00997
    00998                 invShiftRows( block );
    00999                 invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE, BLOCK_SIZE );
    01000                 invMixColumns( block );
    01001
    01002                 invShiftRows( block );
    01003                 invSubstituteAndAddConstant( block, scheduleBuffer, BLOCK_SIZE );
    01004                 invMixColumns( block );
    01005         }
    01006
    01007         invKeyExpansion( scheduleBuffer, roundConstant );
    01008
    01009         invShiftRows( block );
    01010         invSubstituteAndAddConstant( block, scheduleBuffer + BLOCK_SIZE, BLOCK_SIZE );
    01011         invMixColumns( block );
    01012
    01013         invShiftRows( block );
    01014         invSubstituteAndAddConstant( block, scheduleBuffer, BLOCK_SIZE );
    01015
    01016 #else
    01017   #error Unsupported key size.
    01018 #endif
    01019 }
    01020

@DOC_TITLE@