| 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 #if SCHEDULE_EXTRA > 0
    00058 __no_init byte __eeprom keyScheduleInEEPROM[ SCHEDULE_EXTRA ];
    00059 #endif
    00060
    00062 static byte keyScheduleInSRAM[ SCHEDULE_SPLIT ];
    00063
    00065 static const byte __flash sBox[256] = {
    00066         0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
    00067         0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
    00068         0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
    00069         0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
    00070         0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
    00071         0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
    00072         0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
    00073         0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
    00074         0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
    00075         0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
    00076         0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
    00077         0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
    00078         0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
    00079         0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
    00080         0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
    00081         0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
    00082         0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
    00083         0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
    00084         0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
    00085         0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
    00086         0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
    00087         0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
    00088         0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
    00089         0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
    00090         0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
    00091         0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
    00092         0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
    00093         0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
    00094         0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
    00095         0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
    00096         0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
    00097         0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
    00098 };
    00099
    00100
    00101
    00103 static void cycleLeft( byte * row )
    00104 {
    00105         byte temp = row[0];
    00106         row[0] = row[1];
    00107         row[1] = row[2];
    00108         row[2] = row[3];
    00109         row[3] = temp;
    00110 }
    00111
    00112
    00113
    00115 static void mixColumn( byte * column )
    00116 {
    00117         byte result0, result1, result2, result3;
    00118         byte column0, column1, column2, column3;
    00119         byte xor;
    00120
    00121         // This generates more effective code, at least
    00122         // with the IAR C compiler.
    00123         column0 = column[0];
    00124         column1 = column[1];
    00125         column2 = column[2];
    00126         column3 = column[3];
    00127
    00128         // Partial sums (modular addition using XOR).
    00129         result0 = column1 ^ column2 ^ column3;
    00130         result1 = column0 ^ column2 ^ column3;
    00131         result2 = column0 ^ column1 ^ column3;
    00132         result3 = column0 ^ column1 ^ column2;
    00133
    00134         // Multiply column bytes by 2 modulo BPOLY.
    00135         // This operation is done the following way to ensure cycle count
    00136         // independent from data contents. Take care when changing this code.
    00137         xor = 0;
    00138         if (column0 & 0x80) {
    00139                 xor = BPOLY;
    00140         }
    00141         column0 <<= 1;
    00142         column0  ^= xor;
    00143
    00144         xor = 0;
    00145         if (column1 & 0x80) {
    00146                 xor = BPOLY;
    00147         }
    00148         column1 <<= 1;
    00149         column1  ^= xor;
    00150
    00151         xor = 0;
    00152         if (column2 & 0x80) {
    00153                 xor = BPOLY;
    00154         }
    00155         column2 <<= 1;
    00156         column2  ^= xor;
    00157
    00158         xor = 0;
    00159         if (column3 & 0x80) {
    00160                 xor = BPOLY;
    00161         }
    00162         column3 <<= 1;
    00163         column3  ^= xor;
    00164
    00165         // Final sums stored into original column bytes.
    00166         column[0] = result0 ^ column0 ^ column1;
    00167         column[1] = result1 ^ column1 ^ column2;
    00168         column[2] = result2 ^ column2 ^ column3;
    00169         column[3] = result3 ^ column0 ^ column3;
    00170 }
    00171
    00172
    00173
    00175 static void mixColumns( byte * state )
    00176 {
    00177         mixColumn( state + 0*4 );
    00178         mixColumn( state + 1*4 );
    00179         mixColumn( state + 2*4 );
    00180         mixColumn( state + 3*4 );
    00181 }
    00182
    00183
    00184
    00186 static void subBytes( byte * bytes, byte count )
    00187 {
    00188         // Copy to temporary variables for optimization.
    00189         byte * tempPtr = bytes;
    00190         byte tempCount = count;
    00191
    00192         do {
    00193                 *tempPtr = sBox[ *tempPtr ]; // Substitute every byte in state.
    00194                 ++tempPtr;
    00195         } while( --tempCount );
    00196 }
    00197
    00198
    00199
    00201 static void shiftRows( byte * state )
    00202 {
    00203         byte temp;
    00204
    00205         // Note: State is arranged column by column.
    00206
    00207         // Cycle second row left one time.
    00208         temp = state[ 1 + 0*4 ];
    00209         state[ 1 + 0*4 ] = state[ 1 + 1*4 ];
    00210         state[ 1 + 1*4 ] = state[ 1 + 2*4 ];
    00211         state[ 1 + 2*4 ] = state[ 1 + 3*4 ];
    00212         state[ 1 + 3*4 ] = temp;
    00213
    00214         // Cycle third row left two times.
    00215         temp = state[ 2 + 0*4 ];
    00216         state[ 2 + 0*4 ] = state[ 2 + 2*4 ];
    00217         state[ 2 + 2*4 ] = temp;
    00218         temp = state[ 2 + 1*4 ];
    00219         state[ 2 + 1*4 ] = state[ 2 + 3*4 ];
    00220         state[ 2 + 3*4 ] = temp;
    00221
    00222         // Cycle fourth row left three times, ie. right once.
    00223         temp = state[ 3 + 3*4 ];
    00224         state[ 3 + 3*4 ] = state[ 3 + 2*4 ];
    00225         state[ 3 + 2*4 ] = state[ 3 + 1*4 ];
    00226         state[ 3 + 1*4 ] = state[ 3 + 0*4 ];
    00227         state[ 3 + 0*4 ] = temp;
    00228 }
    00229
    00230
    00231
    00233 static void addConstant( byte * bytes, const byte * constant, byte count )
    00234 {
    00235         // Copy to temporary variables for optimization.
    00236         byte * tempDestination = bytes;
    00237         const byte * tempSource = constant;
    00238         byte tempCount = count;
    00239         byte tempValue;
    00240
    00241         do {
    00242                  // Add in GF(2), ie. XOR.
    00243                 tempValue = *tempDestination ^ *tempSource++;
    00244                 *tempDestination++ = tempValue;
    00245         } while( --tempCount );
    00246 }
    00247
    00248
    00249
    00251 static void addConstantAndSubstitute( byte * bytes, const byte * constant, byte count )
    00252 {
    00253         // Copy to temporary variables for optimization.
    00254         byte * tempDestination = bytes;
    00255         const byte * tempSource = constant;
    00256         byte tempCount = count;
    00257         byte tempValue;
    00258
    00259         do {
    00260                 // Add in GF(2), ie. XOR.
    00261                 tempValue = *tempDestination ^ *tempSource++;
    00262                 *tempDestination++ = sBox[ tempValue ];
    00263         } while( --tempCount );
    00264 }
    00265
    00266
    00267
    00269 static void addConstantFromEEPROMAndSubstitute( byte * bytes,
    00270                 const byte __eeprom * constant, byte count )
    00271 {
    00272         // Copy to temporary variables for optimization.
    00273         byte * tempDestination = bytes;
    00274         byte tempCount = count;
    00275         byte tempValue;
    00276         EEAR = (unsigned short int) constant;
    00277
    00278         do {
    00279                 EECR |= (1<<EERE);
    00280                 ++EEAR;
    00281                 tempValue = *tempDestination ^ EEDR; // Add in GF(2), ie. XOR.
    00282                 *tempDestination++ = sBox[ tempValue ];
    00283         } while( --tempCount );
    00284 }
    00285
    00286
    00287
    00288 void cipherLookup( byte * block )
    00289 {
    00290         byte * keySchedule1 = keyScheduleInSRAM;
    00291         byte round = 0;
    00292
    00293 #if SCHEDULE_EXTRA > 0
    00294         byte __eeprom * keySchedule2 = keyScheduleInEEPROM;
    00295
    00296         for( ; round < SCHEDULE_SPLIT_BLOCKS; ++round ) {
    00297                 addConstantAndSubstitute( block, keySchedule1, BLOCK_SIZE );
    00298                 shiftRows( block );
    00299                 mixColumns( block );
    00300                 keySchedule1 += BLOCK_SIZE;
    00301         }
    00302
    00303         for( ; round < ROUNDS-1; ++round ) {
    00304                 addConstantFromEEPROMAndSubstitute( block,
    00305                                 keySchedule2, BLOCK_SIZE );
    00306                 shiftRows( block );
    00307                 mixColumns( block );
    00308                 keySchedule2 += BLOCK_SIZE;
    00309         }
    00310
    00311         addConstantFromEEPROMAndSubstitute( block, keySchedule2, BLOCK_SIZE );
    00312         shiftRows( block );
    00313         keySchedule2 += BLOCK_SIZE;
    00314         addConstantFromEEPROM( block, keySchedule2, BLOCK_SIZE );
    00315 #else
    00316         for( ; round < ROUNDS-1; ++round ) {
    00317                 addConstantAndSubstitute( block, keySchedule1, BLOCK_SIZE );
    00318                 shiftRows( block );
    00319                 mixColumns( block );
    00320                 keySchedule1 += BLOCK_SIZE;
    00321         }
    00322
    00323         addConstantAndSubstitute( block, keySchedule1, BLOCK_SIZE );
    00324         shiftRows( block );
    00325         keySchedule1 += BLOCK_SIZE;
    00326         addConstant( block, keySchedule1, BLOCK_SIZE );
    00327 #endif
    00328 }
    00329
    00330
    00331
    00332 void calcKeySchedule( const byte __eeprom * key )
    00333 {
    00334         byte schedulePos; // Current position inside schedule.
    00335         byte temp[4]; // Temporary word when expanding the key.
    00336         byte roundConstant[4] = { 0x01, 0x00, 0x00, 0x00 };
    00337         byte * keySchedule1 = keyScheduleInSRAM;
    00338 #if SCHEDULE_EXTRA > 0
    00339         byte __eeprom * keySchedule2 = keyScheduleInEEPROM;
    00340 #endif
    00341
    00342         // Copy entire key to start of schedule.
    00343         copyBytesFromEEPROM( keySchedule1, key, KEY_SIZE );
    00344         keySchedule1 += KEY_SIZE;
    00345         // Copy last 4 bytes of key to temp word.
    00346         copyBytes( temp, keySchedule1-4, 4 );
    00347
    00348         // Expand key into schedule buffer 1 first.
    00349         schedulePos = KEY_SIZE;
    00350         while( schedulePos < SCHEDULE_SIZE ) {
    00351                 // Multiple of key size?
    00352                 if( (schedulePos % KEY_SIZE) == 0 ) {
    00353                         cycleLeft( temp ); // Cycle left one byte.
    00354                         subBytes( temp, 4 ); // Substitute each byte.
    00355                         addConstant( temp, roundConstant, 4 ); // Add to temp.
    00356
    00357                         // Modular doubling of round constant's first byte.
    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 (roundConstant[0] & 0x80) {
    00362                                 xor = BPOLY;
    00363                         }
    00364                         roundConstant[0] <<= 1;
    00365                         roundConstant[0]  ^= xor;
    00366                 }
    00367
    00368 #if KEY_SIZE > 24
    00369                 // Multiple of key size + block size, ie. block size into key.
    00370                 else if( (schedulePos % KEY_SIZE) == BLOCK_SIZE ) {
    00371                         subBytes( temp, 4 ); // Substitute each byte.
    00372                 }
    00373 #endif
    00374
    00375 #if SCHEDULE_EXTRA > 0
    00376                 // Select correct source buffer for addition temp word.
    00377                 if( schedulePos <= SCHEDULE_SPLIT+KEY_SIZE-4 ) {
    00378 #endif
    00379                         // Add with data KEY_SIZE backwards in schedule.
    00380                         addConstant( temp, keySchedule1 - KEY_SIZE, 4 );
    00381
    00382 #if SCHEDULE_EXTRA > 0
    00383                         // Copy temp word to currect destination buffer.
    00384                         if( schedulePos <= SCHEDULE_SPLIT-4 ) {
    00385 #endif
    00386                                 copyBytes( keySchedule1, temp, 4 );
    00387                                 keySchedule1 += 4;
    00388 #if SCHEDULE_EXTRA > 0
    00389                         } else {
    00390                                 copyBytesToEEPROM( keySchedule2, temp, 4 );
    00391                                 keySchedule1 += 4; // We need buffer 1 also.
    00392                                 keySchedule2 += 4;
    00393                         }
    00394                 } else {
    00395                         // Add with data KEY_SIZE backwards in schedule.
    00396                         addConstantFromEEPROM( temp,
    00397                                         keySchedule2 - KEY_SIZE, 4 );
    00398                         copyBytesToEEPROM( keySchedule2, temp, 4 );
    00399                         keySchedule2 += 4;
    00400                 }
    00401 #endif
    00402                 schedulePos += 4;
    00403         }
    00404 }
    00405

@DOC_TITLE@