| 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
  4337

Date
  2008-08-08 10:52:47 +0200 (fr, 08 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 | addAndCopy (byte *buf1, byte *buf2, byte count)
static void | addConstantAndSubstitute (byte *bytes, const byte *constant, byte count)
static void | calcLastRoundKey (byte *scheduleBuffer)
void | cipher (byte *block, byte *scheduleBuffer, const byte *key)
static void | cycleLeft (byte *row)
void | invCipher (byte *block, byte *scheduleBuffer)
static void | invKeyExpansion (byte *scheduleBuffer, byte *roundConstant)
static void | invMixColumn (byte *column)
static void | invMixColumns (byte *state)
static void | invShiftRows (byte *state)
static void | invSubstituteAndAddConstant (byte *bytes, const byte *constant, byte count)
static void | keyExpansion (byte *scheduleBuffer, byte *roundConstant)
static void | mixColumn (byte *column)
static void | mixColumns (byte *state)
void | prepareInvCipher (byte *scheduleBuffer, const byte *key)
static void | shiftRows (byte *state)
static void | subBytes (byte *bytes, byte count)
## Variables
const byte __flash | sBox [256]
const byte __flash | sBoxInv [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 invCipher(), invKeyExpansion(), invMixColumn(), keyExpansion(), and mixColumn().

## Function Documentation

static void addAndCopy | ( | byte * | buf1,
|  | byte * | buf2,
|  | byte | count |
| ) |  |  | `[static]`

XOR 'count' bytes from 'buf1' and 'buf2' buffers and copy result to both buffers.

Definition at line 467 of file aes.c.

Referenced by keyExpansion().

    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 }

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 508 of file aes.c.

References sBox.

Referenced by cipher().

    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 }

static void calcLastRoundKey | ( | byte * | scheduleBuffer | ) | `[static]`

Prepare last round key in schedule given the initial key in 'scheduleBuffer' and 'roundConstant'.

Definition at line 817 of file aes.c.

References keyExpansion(), ROUNDS, and SCHEDULE_BLOCK_REPETITIONS.

Referenced by prepareInvCipher().

    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 }

Here is the call graph for this function:

void cipher | ( | byte * | block,
|  | byte * | scheduleBuffer,
|  | const byte * | key |
| ) |  |  |

Encrypt data block with on-the-fly calculation of key schedule in 'scheduleBuffer'.

Definition at line 833 of file aes.c.

References addConstant(), addConstantAndSubstitute(), BLOCK_SIZE, copyBytes(), KEY_SIZE, keyExpansion(), mixColumns(), ROUNDS, and shiftRows().

Referenced by calcCMAC(), and calcCMACSubkey().

    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 }

Here is the call graph for this function:

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

Cycle a 4-byte array left once.

Definition at line 134 of file aes.c.

Referenced by invKeyExpansion(), and keyExpansion().

    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 }

void invCipher | ( | byte * | block,
|  | byte * | scheduleBuffer |
| ) |  |  |

Decrypt data block using prepared key schedule state from 'scheduleBuffer'.

Definition at line 929 of file aes.c.

References addConstant(), BLOCK_SIZE, BPOLY, invKeyExpansion(), invMixColumns(), invShiftRows(), invSubstituteAndAddConstant(), LAST_ROUND_CONSTANT, and ROUNDS.

Referenced by learnMode().

    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 }

Here is the call graph for this function:

static void invKeyExpansion | ( | byte * | scheduleBuffer,
|  | byte * | roundConstant |
| ) |  |  | `[static]`

Calculate previous round key from current round key in 'scheduleBuffer' and 'roundConstant'.

Definition at line 683 of file aes.c.

References addConstant(), BLOCK_SIZE, BPOLY, copyBytes(), cycleLeft(), KEY_SIZE, SCHEDULE_BUFFER_SIZE, and subBytes().

Referenced by invCipher().

    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 }

Here is the call graph for this function:

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

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

Definition at line 264 of file aes.c.

References BPOLY.

Referenced by invMixColumns().

    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 }

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

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

Definition at line 401 of file aes.c.

References invMixColumn().

Referenced by invCipher().

    00402 {
    00403         invMixColumn( state + 0*4 );
    00404         invMixColumn( state + 1*4 );
    00405         invMixColumn( state + 2*4 );
    00406         invMixColumn( state + 3*4 );
    00407 }

Here is the call graph for this function:

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

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

Definition at line 412 of file aes.c.

Referenced by invCipher().

    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 }

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

Substitute 'count' bytes from 'bytes' using inverse S-Box, XOR with 'constant' and store in 'bytes'.

Definition at line 526 of file aes.c.

References sBoxInv.

Referenced by invCipher().

    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 }

static void keyExpansion | ( | byte * | scheduleBuffer,
|  | byte * | roundConstant |
| ) |  |  | `[static]`

Calculates next round key from current round key in 'scheduleBuffer' and 'roundConstant'.

Definition at line 544 of file aes.c.

References addAndCopy(), addConstant(), BLOCK_SIZE, BPOLY, copyBytes(), cycleLeft(), KEY_SIZE, SCHEDULE_BUFFER_SIZE, and subBytes().

Referenced by calcLastRoundKey(), and cipher().

    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 }

Here is the call graph for this function:

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

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

Definition at line 147 of file aes.c.

References BPOLY.

Referenced by mixColumns().

    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 }

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

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

Definition at line 206 of file aes.c.

References mixColumn().

Referenced by cipher().

    00207 {
    00208         mixColumn( state + 0*4 );
    00209         mixColumn( state + 1*4 );
    00210         mixColumn( state + 2*4 );
    00211         mixColumn( state + 3*4 );
    00212 }

Here is the call graph for this function:

void prepareInvCipher | ( | byte * | scheduleBuffer,
|  | const byte * | key |
| ) |  |  |

Calculate starting point for key schedule to be used for decryption.

Definition at line 921 of file aes.c.

References calcLastRoundKey(), copyBytes(), and KEY_SIZE.

Referenced by learnMode().

    00922 {
    00923         copyBytes( scheduleBuffer, key, KEY_SIZE );
    00924         calcLastRoundKey( scheduleBuffer );
    00925 }

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 232 of file aes.c.

Referenced by cipher().

    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 }

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

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

Definition at line 217 of file aes.c.

References sBox.

Referenced by invKeyExpansion(), and keyExpansion().

    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 }

## Variable Documentation

const byte __flash sBox[256]

S-Box lookup table.

Definition at line 60 of file aes.c.

Referenced by addConstantAndSubstitute(), and subBytes().

const byte __flash sBoxInv[256]

Inverse S-Box lookup table.

Definition at line 96 of file aes.c.

Referenced by invSubstituteAndAddConstant().

@DOC_TITLE@