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@
Generated on Fri Aug 8 11:03:16 2008 for AVR411 Secure Rolling Code Algorithm (Transmitter) by doxygen 1.4.7