| Remote Access Control |

# aes.c File Reference

## Detailed Description

Source file for AES public and support functions.

This file contains the function implementation for the AES algorithm. Refer to the aes.h file for more details.

- File: aes.c
- Compiler: IAR EWAVR 4.11B
- Supported devices: ATtiny45/85
- AppNote: AVR411 - Secure Rolling Code Algorithm for Wireless Link

Author:
  Atmel Corporation: http://www.atmel.com
  Support email: avr@atmel.com

Name

Revision
  4331

Date
  2008-08-07 16:44:55 +0200 (to, 07 aug 2008)

Copyright (c) 2006, Atmel Corporation All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. The name of ATMEL may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Definition in file aes.c.

`#include "aes.h"`
`#include "common.h"`
`#include "config.h"`

Include dependency graph for aes.c:

Go to the source code of this file.

## Defines
#define | BPOLY 0x1b
## Functions
static void | addConstant (byte *bytes, const byte *constant, byte count)
static void | addConstantAndSubstitute (byte *bytes, const byte *constant, byte count)
static void | addConstantFromEEPROMAndSubstitute (byte *bytes, const byte __eeprom *constant, byte count)
void | calcKeySchedule (const byte __eeprom *key)
void | cipherLookup (byte *block)
static void | cycleLeft (byte *row)
static void | mixColumn (byte *column)
static void | mixColumns (byte *state)
static void | shiftRows (byte *state)
static void | subBytes (byte *bytes, byte count)
## Variables
__no_init byte __eeprom | keyScheduleInEEPROM [SCHEDULE_EXTRA]
static byte | keyScheduleInSRAM [SCHEDULE_SPLIT]
static const byte __flash | sBox [256]

## Define Documentation

#define BPOLY 0x1b

Lower 8 bits of AES polynomial (x^8+x^4+x^3+x+1), ie. (x^4+x^3+x+1).

Definition at line 55 of file aes.c.

Referenced by calcKeySchedule(), and mixColumn().

## Function Documentation

static void addConstant | ( | byte * | bytes,
|  | const byte * | constant,
|  | byte | count |
| ) |  |  | `[static]`

XOR 'count' bytes from 'constant' buffer into 'bytes' buffer in SRAM.

Definition at line 233 of file aes.c.

Referenced by calcKeySchedule(), and cipherLookup().

    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 }

static void addConstantAndSubstitute | ( | byte * | bytes,
|  | const byte * | constant,
|  | byte | count |
| ) |  |  | `[static]`

XOR 'count' bytes from 'constant' buffer into 'bytes' and substitute using S-Box.

Definition at line 251 of file aes.c.

References sBox.

Referenced by cipherLookup().

    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 }

static void addConstantFromEEPROMAndSubstitute | ( | byte * | bytes,
|  | const byte __eeprom * | constant,
|  | byte | count |
| ) |  |  | `[static]`

XOR 'count' bytes from 'constant' buffer in EEPROM into 'bytes' and substitute using S-Box.

Definition at line 269 of file aes.c.

References sBox.

Referenced by cipherLookup().

    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 }

void calcKeySchedule | ( | const byte __eeprom * | key | ) |

Precalculate AES key schedule from given cipher key.

Definition at line 332 of file aes.c.

References addConstant(), addConstantFromEEPROM(), BLOCK_SIZE, BPOLY, copyBytes(), copyBytesFromEEPROM(), copyBytesToEEPROM(), cycleLeft(), KEY_SIZE, keyScheduleInEEPROM, keyScheduleInSRAM, SCHEDULE_SIZE, SCHEDULE_SPLIT, and subBytes().

Referenced by main(), and transmitTeachMessage().

    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 }

Here is the call graph for this function:

void cipherLookup | ( | byte * | block | ) |

Use precalculated key schedule to encrypt the given data block.

Definition at line 288 of file aes.c.

References addConstant(), addConstantAndSubstitute(), addConstantFromEEPROM(), addConstantFromEEPROMAndSubstitute(), BLOCK_SIZE, keyScheduleInEEPROM, keyScheduleInSRAM, mixColumns(), ROUNDS, SCHEDULE_SPLIT_BLOCKS, and shiftRows().

Referenced by calcCMAC(), calcCMACSubkey(), and transmitTeachMessage().

    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 }

Here is the call graph for this function:

static void cycleLeft | ( | byte * | row | ) | `[static]`

Cycle a 4-byte array left once.

Definition at line 103 of file aes.c.

Referenced by calcKeySchedule().

    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 }

static void mixColumn | ( | byte * | column | ) | `[static]`

Perform an AES column mix operation on the 4 bytes in 'column' buffer.

Definition at line 115 of file aes.c.

References BPOLY.

Referenced by mixColumns().

    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 }

static void mixColumns | ( | byte * | state | ) | `[static]`

Perform AES column mixing for the whole AES block/state.

Definition at line 175 of file aes.c.

References mixColumn().

Referenced by cipherLookup().

    00176 {
    00177         mixColumn( state + 0*4 );
    00178         mixColumn( state + 1*4 );
    00179         mixColumn( state + 2*4 );
    00180         mixColumn( state + 3*4 );
    00181 }

Here is the call graph for this function:

static void shiftRows | ( | byte * | state | ) | `[static]`

Perform AES shift rows operation for the whole AES block/state.

Definition at line 201 of file aes.c.

Referenced by cipherLookup().

    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 }

static void subBytes | ( | byte * | bytes,
|  | byte | count |
| ) |  |  | `[static]`

Substitute 'count' bytes in the 'bytes' buffer in SRAM using the S-Box.

Definition at line 186 of file aes.c.

References sBox.

Referenced by calcKeySchedule().

    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 }

## Variable Documentation

__no_init byte __eeprom keyScheduleInEEPROM[SCHEDULE_EXTRA]

Definition at line 58 of file aes.c.

Referenced by calcKeySchedule(), and cipherLookup().

byte keyScheduleInSRAM[SCHEDULE_SPLIT]`[static]`

Primary (SRAM) storage for key schedule.

Definition at line 62 of file aes.c.

Referenced by calcKeySchedule(), and cipherLookup().

const byte __flash sBox[256]`[static]`

S-Box lookup table.

Definition at line 65 of file aes.c.

Referenced by addConstantAndSubstitute(), addConstantFromEEPROMAndSubstitute(), and subBytes().

@DOC_TITLE@