A simple library to support serving https.
Dependents: oldheating gps motorhome heating
aes-gcm/aes.c@24:cb43290fc439, 2020-04-01 (annotated)
- Committer:
- andrewboyson
- Date:
- Wed Apr 01 12:48:52 2020 +0000
- Revision:
- 24:cb43290fc439
- Parent:
- 6:819c17738dc2
Added check so that if the client closes the TCP connection before the TLS connection is established then respond that we have finished and the TCP connection is to be closed.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 6:819c17738dc2 | 1 | /****************************************************************************** |
andrewboyson | 6:819c17738dc2 | 2 | * |
andrewboyson | 6:819c17738dc2 | 3 | * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL |
andrewboyson | 6:819c17738dc2 | 4 | * |
andrewboyson | 6:819c17738dc2 | 5 | * This is a simple and straightforward implementation of the AES Rijndael |
andrewboyson | 6:819c17738dc2 | 6 | * 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus |
andrewboyson | 6:819c17738dc2 | 7 | * of this work was correctness & accuracy. It is written in 'C' without any |
andrewboyson | 6:819c17738dc2 | 8 | * particular focus upon optimization or speed. It should be endian (memory |
andrewboyson | 6:819c17738dc2 | 9 | * byte order) neutral since the few places that care are handled explicitly. |
andrewboyson | 6:819c17738dc2 | 10 | * |
andrewboyson | 6:819c17738dc2 | 11 | * This implementation of Rijndael was created by Steven M. Gibson of GRC.com. |
andrewboyson | 6:819c17738dc2 | 12 | * |
andrewboyson | 6:819c17738dc2 | 13 | * It is intended for general purpose use, but was written in support of GRC's |
andrewboyson | 6:819c17738dc2 | 14 | * reference implementation of the SQRL (Secure Quick Reliable Login) client. |
andrewboyson | 6:819c17738dc2 | 15 | * |
andrewboyson | 6:819c17738dc2 | 16 | * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html |
andrewboyson | 6:819c17738dc2 | 17 | * |
andrewboyson | 6:819c17738dc2 | 18 | * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE |
andrewboyson | 6:819c17738dc2 | 19 | * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. |
andrewboyson | 6:819c17738dc2 | 20 | * |
andrewboyson | 6:819c17738dc2 | 21 | *******************************************************************************/ |
andrewboyson | 6:819c17738dc2 | 22 | |
andrewboyson | 6:819c17738dc2 | 23 | #include "aes.h" |
andrewboyson | 6:819c17738dc2 | 24 | |
andrewboyson | 6:819c17738dc2 | 25 | static int aes_tables_inited = 0; // run-once flag for performing key |
andrewboyson | 6:819c17738dc2 | 26 | // expasion table generation (see below) |
andrewboyson | 6:819c17738dc2 | 27 | /* |
andrewboyson | 6:819c17738dc2 | 28 | * The following static local tables must be filled-in before the first use of |
andrewboyson | 6:819c17738dc2 | 29 | * the GCM or AES ciphers. They are used for the AES key expansion/scheduling |
andrewboyson | 6:819c17738dc2 | 30 | * and once built are read-only and thread safe. The "gcm_initialize" function |
andrewboyson | 6:819c17738dc2 | 31 | * must be called once during system initialization to populate these arrays |
andrewboyson | 6:819c17738dc2 | 32 | * for subsequent use by the AES key scheduler. If they have not been built |
andrewboyson | 6:819c17738dc2 | 33 | * before attempted use, an error will be returned to the caller. |
andrewboyson | 6:819c17738dc2 | 34 | * |
andrewboyson | 6:819c17738dc2 | 35 | * NOTE: GCM Encryption/Decryption does NOT REQUIRE AES decryption. Since |
andrewboyson | 6:819c17738dc2 | 36 | * GCM uses AES in counter-mode, where the AES cipher output is XORed with |
andrewboyson | 6:819c17738dc2 | 37 | * the GCM input, we ONLY NEED AES encryption. Thus, to save space AES |
andrewboyson | 6:819c17738dc2 | 38 | * decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h. |
andrewboyson | 6:819c17738dc2 | 39 | */ |
andrewboyson | 6:819c17738dc2 | 40 | // We always need our forward tables |
andrewboyson | 6:819c17738dc2 | 41 | static uchar FSb[256]; // Forward substitution box (FSb) |
andrewboyson | 6:819c17738dc2 | 42 | static uint32_t FT0[256]; // Forward key schedule assembly tables |
andrewboyson | 6:819c17738dc2 | 43 | static uint32_t FT1[256]; |
andrewboyson | 6:819c17738dc2 | 44 | static uint32_t FT2[256]; |
andrewboyson | 6:819c17738dc2 | 45 | static uint32_t FT3[256]; |
andrewboyson | 6:819c17738dc2 | 46 | |
andrewboyson | 6:819c17738dc2 | 47 | #if AES_DECRYPTION // We ONLY need reverse for decryption |
andrewboyson | 6:819c17738dc2 | 48 | static uchar RSb[256]; // Reverse substitution box (RSb) |
andrewboyson | 6:819c17738dc2 | 49 | static uint32_t RT0[256]; // Reverse key schedule assembly tables |
andrewboyson | 6:819c17738dc2 | 50 | static uint32_t RT1[256]; |
andrewboyson | 6:819c17738dc2 | 51 | static uint32_t RT2[256]; |
andrewboyson | 6:819c17738dc2 | 52 | static uint32_t RT3[256]; |
andrewboyson | 6:819c17738dc2 | 53 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 54 | |
andrewboyson | 6:819c17738dc2 | 55 | static uint32_t RCON[10]; // AES round constants |
andrewboyson | 6:819c17738dc2 | 56 | |
andrewboyson | 6:819c17738dc2 | 57 | /* |
andrewboyson | 6:819c17738dc2 | 58 | * Platform Endianness Neutralizing Load and Store Macro definitions |
andrewboyson | 6:819c17738dc2 | 59 | * AES wants platform-neutral Little Endian (LE) byte ordering |
andrewboyson | 6:819c17738dc2 | 60 | */ |
andrewboyson | 6:819c17738dc2 | 61 | #define GET_UINT32_LE(n,b,i) { \ |
andrewboyson | 6:819c17738dc2 | 62 | (n) = ( (uint32_t) (b)[(i) ] ) \ |
andrewboyson | 6:819c17738dc2 | 63 | | ( (uint32_t) (b)[(i) + 1] << 8 ) \ |
andrewboyson | 6:819c17738dc2 | 64 | | ( (uint32_t) (b)[(i) + 2] << 16 ) \ |
andrewboyson | 6:819c17738dc2 | 65 | | ( (uint32_t) (b)[(i) + 3] << 24 ); } |
andrewboyson | 6:819c17738dc2 | 66 | |
andrewboyson | 6:819c17738dc2 | 67 | #define PUT_UINT32_LE(n,b,i) { \ |
andrewboyson | 6:819c17738dc2 | 68 | (b)[(i) ] = (uchar) ( (n) ); \ |
andrewboyson | 6:819c17738dc2 | 69 | (b)[(i) + 1] = (uchar) ( (n) >> 8 ); \ |
andrewboyson | 6:819c17738dc2 | 70 | (b)[(i) + 2] = (uchar) ( (n) >> 16 ); \ |
andrewboyson | 6:819c17738dc2 | 71 | (b)[(i) + 3] = (uchar) ( (n) >> 24 ); } |
andrewboyson | 6:819c17738dc2 | 72 | |
andrewboyson | 6:819c17738dc2 | 73 | /* |
andrewboyson | 6:819c17738dc2 | 74 | * AES forward and reverse encryption round processing macros |
andrewboyson | 6:819c17738dc2 | 75 | */ |
andrewboyson | 6:819c17738dc2 | 76 | #define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ |
andrewboyson | 6:819c17738dc2 | 77 | { \ |
andrewboyson | 6:819c17738dc2 | 78 | X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 79 | FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 80 | FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 81 | FT3[ ( Y3 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 82 | \ |
andrewboyson | 6:819c17738dc2 | 83 | X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 84 | FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 85 | FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 86 | FT3[ ( Y0 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 87 | \ |
andrewboyson | 6:819c17738dc2 | 88 | X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 89 | FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 90 | FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 91 | FT3[ ( Y1 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 92 | \ |
andrewboyson | 6:819c17738dc2 | 93 | X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 94 | FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 95 | FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 96 | FT3[ ( Y2 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 97 | } |
andrewboyson | 6:819c17738dc2 | 98 | |
andrewboyson | 6:819c17738dc2 | 99 | #define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ |
andrewboyson | 6:819c17738dc2 | 100 | { \ |
andrewboyson | 6:819c17738dc2 | 101 | X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 102 | RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 103 | RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 104 | RT3[ ( Y1 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 105 | \ |
andrewboyson | 6:819c17738dc2 | 106 | X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 107 | RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 108 | RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 109 | RT3[ ( Y2 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 110 | \ |
andrewboyson | 6:819c17738dc2 | 111 | X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 112 | RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 113 | RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 114 | RT3[ ( Y3 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 115 | \ |
andrewboyson | 6:819c17738dc2 | 116 | X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 117 | RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 118 | RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ |
andrewboyson | 6:819c17738dc2 | 119 | RT3[ ( Y0 >> 24 ) & 0xFF ]; \ |
andrewboyson | 6:819c17738dc2 | 120 | } |
andrewboyson | 6:819c17738dc2 | 121 | |
andrewboyson | 6:819c17738dc2 | 122 | /* |
andrewboyson | 6:819c17738dc2 | 123 | * These macros improve the readability of the key |
andrewboyson | 6:819c17738dc2 | 124 | * generation initialization code by collapsing |
andrewboyson | 6:819c17738dc2 | 125 | * repetitive common operations into logical pieces. |
andrewboyson | 6:819c17738dc2 | 126 | */ |
andrewboyson | 6:819c17738dc2 | 127 | #define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) |
andrewboyson | 6:819c17738dc2 | 128 | #define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) |
andrewboyson | 6:819c17738dc2 | 129 | #define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) |
andrewboyson | 6:819c17738dc2 | 130 | #define MIX(x,y) { y = ( (y << 1) | (y >> 7) ) & 0xFF; x ^= y; } |
andrewboyson | 6:819c17738dc2 | 131 | #define CPY128 { *RK++ = *SK++; *RK++ = *SK++; \ |
andrewboyson | 6:819c17738dc2 | 132 | *RK++ = *SK++; *RK++ = *SK++; } |
andrewboyson | 6:819c17738dc2 | 133 | |
andrewboyson | 6:819c17738dc2 | 134 | /****************************************************************************** |
andrewboyson | 6:819c17738dc2 | 135 | * |
andrewboyson | 6:819c17738dc2 | 136 | * AES_INIT_KEYGEN_TABLES |
andrewboyson | 6:819c17738dc2 | 137 | * |
andrewboyson | 6:819c17738dc2 | 138 | * Fills the AES key expansion tables allocated above with their static |
andrewboyson | 6:819c17738dc2 | 139 | * data. This is not "per key" data, but static system-wide read-only |
andrewboyson | 6:819c17738dc2 | 140 | * table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once |
andrewboyson | 6:819c17738dc2 | 141 | * at system initialization to setup the tables for all subsequent use. |
andrewboyson | 6:819c17738dc2 | 142 | * |
andrewboyson | 6:819c17738dc2 | 143 | ******************************************************************************/ |
andrewboyson | 6:819c17738dc2 | 144 | void aes_init_keygen_tables( void ) |
andrewboyson | 6:819c17738dc2 | 145 | { |
andrewboyson | 6:819c17738dc2 | 146 | int i, x, y, z; // general purpose iteration and computation locals |
andrewboyson | 6:819c17738dc2 | 147 | int pow[256]; |
andrewboyson | 6:819c17738dc2 | 148 | int log[256]; |
andrewboyson | 6:819c17738dc2 | 149 | |
andrewboyson | 6:819c17738dc2 | 150 | // fill the 'pow' and 'log' tables over GF(2^8) |
andrewboyson | 6:819c17738dc2 | 151 | for( i = 0, x = 1; i < 256; i++ ) { |
andrewboyson | 6:819c17738dc2 | 152 | pow[i] = x; |
andrewboyson | 6:819c17738dc2 | 153 | log[x] = i; |
andrewboyson | 6:819c17738dc2 | 154 | x = ( x ^ XTIME( x ) ) & 0xFF; |
andrewboyson | 6:819c17738dc2 | 155 | } |
andrewboyson | 6:819c17738dc2 | 156 | // compute the round constants |
andrewboyson | 6:819c17738dc2 | 157 | for( i = 0, x = 1; i < 10; i++ ) { |
andrewboyson | 6:819c17738dc2 | 158 | RCON[i] = (uint32_t) x; |
andrewboyson | 6:819c17738dc2 | 159 | x = XTIME( x ) & 0xFF; |
andrewboyson | 6:819c17738dc2 | 160 | } |
andrewboyson | 6:819c17738dc2 | 161 | // fill the forward and reverse substitution boxes |
andrewboyson | 6:819c17738dc2 | 162 | FSb[0x00] = 0x63; |
andrewboyson | 6:819c17738dc2 | 163 | #if AES_DECRYPTION // whether AES decryption is supported |
andrewboyson | 6:819c17738dc2 | 164 | RSb[0x63] = 0x00; |
andrewboyson | 6:819c17738dc2 | 165 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 166 | |
andrewboyson | 6:819c17738dc2 | 167 | for( i = 1; i < 256; i++ ) { |
andrewboyson | 6:819c17738dc2 | 168 | x = y = pow[255 - log[i]]; |
andrewboyson | 6:819c17738dc2 | 169 | MIX(x,y); |
andrewboyson | 6:819c17738dc2 | 170 | MIX(x,y); |
andrewboyson | 6:819c17738dc2 | 171 | MIX(x,y); |
andrewboyson | 6:819c17738dc2 | 172 | MIX(x,y); |
andrewboyson | 6:819c17738dc2 | 173 | FSb[i] = (uchar) ( x ^= 0x63 ); |
andrewboyson | 6:819c17738dc2 | 174 | #if AES_DECRYPTION // whether AES decryption is supported |
andrewboyson | 6:819c17738dc2 | 175 | RSb[x] = (uchar) i; |
andrewboyson | 6:819c17738dc2 | 176 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 177 | |
andrewboyson | 6:819c17738dc2 | 178 | } |
andrewboyson | 6:819c17738dc2 | 179 | // generate the forward and reverse key expansion tables |
andrewboyson | 6:819c17738dc2 | 180 | for( i = 0; i < 256; i++ ) { |
andrewboyson | 6:819c17738dc2 | 181 | x = FSb[i]; |
andrewboyson | 6:819c17738dc2 | 182 | y = XTIME( x ) & 0xFF; |
andrewboyson | 6:819c17738dc2 | 183 | z = ( y ^ x ) & 0xFF; |
andrewboyson | 6:819c17738dc2 | 184 | |
andrewboyson | 6:819c17738dc2 | 185 | FT0[i] = ( (uint32_t) y ) ^ ( (uint32_t) x << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 186 | ( (uint32_t) x << 16 ) ^ ( (uint32_t) z << 24 ); |
andrewboyson | 6:819c17738dc2 | 187 | |
andrewboyson | 6:819c17738dc2 | 188 | FT1[i] = ROTL8( FT0[i] ); |
andrewboyson | 6:819c17738dc2 | 189 | FT2[i] = ROTL8( FT1[i] ); |
andrewboyson | 6:819c17738dc2 | 190 | FT3[i] = ROTL8( FT2[i] ); |
andrewboyson | 6:819c17738dc2 | 191 | |
andrewboyson | 6:819c17738dc2 | 192 | #if AES_DECRYPTION // whether AES decryption is supported |
andrewboyson | 6:819c17738dc2 | 193 | x = RSb[i]; |
andrewboyson | 6:819c17738dc2 | 194 | |
andrewboyson | 6:819c17738dc2 | 195 | RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ |
andrewboyson | 6:819c17738dc2 | 196 | ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 197 | ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 198 | ( (uint32_t) MUL( 0x0B, x ) << 24 ); |
andrewboyson | 6:819c17738dc2 | 199 | |
andrewboyson | 6:819c17738dc2 | 200 | RT1[i] = ROTL8( RT0[i] ); |
andrewboyson | 6:819c17738dc2 | 201 | RT2[i] = ROTL8( RT1[i] ); |
andrewboyson | 6:819c17738dc2 | 202 | RT3[i] = ROTL8( RT2[i] ); |
andrewboyson | 6:819c17738dc2 | 203 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 204 | } |
andrewboyson | 6:819c17738dc2 | 205 | aes_tables_inited = 1; // flag that the tables have been generated |
andrewboyson | 6:819c17738dc2 | 206 | } // to permit subsequent use of the AES cipher |
andrewboyson | 6:819c17738dc2 | 207 | |
andrewboyson | 6:819c17738dc2 | 208 | /****************************************************************************** |
andrewboyson | 6:819c17738dc2 | 209 | * |
andrewboyson | 6:819c17738dc2 | 210 | * AES_SET_ENCRYPTION_KEY |
andrewboyson | 6:819c17738dc2 | 211 | * |
andrewboyson | 6:819c17738dc2 | 212 | * This is called by 'aes_setkey' when we're establishing a key for |
andrewboyson | 6:819c17738dc2 | 213 | * subsequent encryption. We give it a pointer to the encryption |
andrewboyson | 6:819c17738dc2 | 214 | * context, a pointer to the key, and the key's length in bytes. |
andrewboyson | 6:819c17738dc2 | 215 | * Valid lengths are: 16, 24 or 32 bytes (128, 192, 256 bits). |
andrewboyson | 6:819c17738dc2 | 216 | * |
andrewboyson | 6:819c17738dc2 | 217 | ******************************************************************************/ |
andrewboyson | 6:819c17738dc2 | 218 | int aes_set_encryption_key( aes_context *ctx, |
andrewboyson | 6:819c17738dc2 | 219 | const uchar *key, |
andrewboyson | 6:819c17738dc2 | 220 | uint keysize ) |
andrewboyson | 6:819c17738dc2 | 221 | { |
andrewboyson | 6:819c17738dc2 | 222 | uint i; // general purpose iteration local |
andrewboyson | 6:819c17738dc2 | 223 | uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer |
andrewboyson | 6:819c17738dc2 | 224 | |
andrewboyson | 6:819c17738dc2 | 225 | for( i = 0; i < (keysize >> 2); i++ ) { |
andrewboyson | 6:819c17738dc2 | 226 | GET_UINT32_LE( RK[i], key, i << 2 ); |
andrewboyson | 6:819c17738dc2 | 227 | } |
andrewboyson | 6:819c17738dc2 | 228 | |
andrewboyson | 6:819c17738dc2 | 229 | switch( ctx->rounds ) |
andrewboyson | 6:819c17738dc2 | 230 | { |
andrewboyson | 6:819c17738dc2 | 231 | case 10: |
andrewboyson | 6:819c17738dc2 | 232 | for( i = 0; i < 10; i++, RK += 4 ) { |
andrewboyson | 6:819c17738dc2 | 233 | RK[4] = RK[0] ^ RCON[i] ^ |
andrewboyson | 6:819c17738dc2 | 234 | ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 235 | ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 236 | ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 237 | ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 238 | |
andrewboyson | 6:819c17738dc2 | 239 | RK[5] = RK[1] ^ RK[4]; |
andrewboyson | 6:819c17738dc2 | 240 | RK[6] = RK[2] ^ RK[5]; |
andrewboyson | 6:819c17738dc2 | 241 | RK[7] = RK[3] ^ RK[6]; |
andrewboyson | 6:819c17738dc2 | 242 | } |
andrewboyson | 6:819c17738dc2 | 243 | break; |
andrewboyson | 6:819c17738dc2 | 244 | |
andrewboyson | 6:819c17738dc2 | 245 | case 12: |
andrewboyson | 6:819c17738dc2 | 246 | for( i = 0; i < 8; i++, RK += 6 ) { |
andrewboyson | 6:819c17738dc2 | 247 | RK[6] = RK[0] ^ RCON[i] ^ |
andrewboyson | 6:819c17738dc2 | 248 | ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 249 | ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 250 | ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 251 | ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 252 | |
andrewboyson | 6:819c17738dc2 | 253 | RK[7] = RK[1] ^ RK[6]; |
andrewboyson | 6:819c17738dc2 | 254 | RK[8] = RK[2] ^ RK[7]; |
andrewboyson | 6:819c17738dc2 | 255 | RK[9] = RK[3] ^ RK[8]; |
andrewboyson | 6:819c17738dc2 | 256 | RK[10] = RK[4] ^ RK[9]; |
andrewboyson | 6:819c17738dc2 | 257 | RK[11] = RK[5] ^ RK[10]; |
andrewboyson | 6:819c17738dc2 | 258 | } |
andrewboyson | 6:819c17738dc2 | 259 | break; |
andrewboyson | 6:819c17738dc2 | 260 | |
andrewboyson | 6:819c17738dc2 | 261 | case 14: |
andrewboyson | 6:819c17738dc2 | 262 | for( i = 0; i < 7; i++, RK += 8 ) { |
andrewboyson | 6:819c17738dc2 | 263 | RK[8] = RK[0] ^ RCON[i] ^ |
andrewboyson | 6:819c17738dc2 | 264 | ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 265 | ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 266 | ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 267 | ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 268 | |
andrewboyson | 6:819c17738dc2 | 269 | RK[9] = RK[1] ^ RK[8]; |
andrewboyson | 6:819c17738dc2 | 270 | RK[10] = RK[2] ^ RK[9]; |
andrewboyson | 6:819c17738dc2 | 271 | RK[11] = RK[3] ^ RK[10]; |
andrewboyson | 6:819c17738dc2 | 272 | |
andrewboyson | 6:819c17738dc2 | 273 | RK[12] = RK[4] ^ |
andrewboyson | 6:819c17738dc2 | 274 | ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 275 | ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 276 | ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 277 | ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 278 | |
andrewboyson | 6:819c17738dc2 | 279 | RK[13] = RK[5] ^ RK[12]; |
andrewboyson | 6:819c17738dc2 | 280 | RK[14] = RK[6] ^ RK[13]; |
andrewboyson | 6:819c17738dc2 | 281 | RK[15] = RK[7] ^ RK[14]; |
andrewboyson | 6:819c17738dc2 | 282 | } |
andrewboyson | 6:819c17738dc2 | 283 | break; |
andrewboyson | 6:819c17738dc2 | 284 | } |
andrewboyson | 6:819c17738dc2 | 285 | return( 0 ); |
andrewboyson | 6:819c17738dc2 | 286 | } |
andrewboyson | 6:819c17738dc2 | 287 | |
andrewboyson | 6:819c17738dc2 | 288 | #if AES_DECRYPTION // whether AES decryption is supported |
andrewboyson | 6:819c17738dc2 | 289 | |
andrewboyson | 6:819c17738dc2 | 290 | /****************************************************************************** |
andrewboyson | 6:819c17738dc2 | 291 | * |
andrewboyson | 6:819c17738dc2 | 292 | * AES_SET_DECRYPTION_KEY |
andrewboyson | 6:819c17738dc2 | 293 | * |
andrewboyson | 6:819c17738dc2 | 294 | * This is called by 'aes_setkey' when we're establishing a |
andrewboyson | 6:819c17738dc2 | 295 | * key for subsequent decryption. We give it a pointer to |
andrewboyson | 6:819c17738dc2 | 296 | * the encryption context, a pointer to the key, and the key's |
andrewboyson | 6:819c17738dc2 | 297 | * length in bits. Valid lengths are: 128, 192, or 256 bits. |
andrewboyson | 6:819c17738dc2 | 298 | * |
andrewboyson | 6:819c17738dc2 | 299 | ******************************************************************************/ |
andrewboyson | 6:819c17738dc2 | 300 | int aes_set_decryption_key( aes_context *ctx, |
andrewboyson | 6:819c17738dc2 | 301 | const uchar *key, |
andrewboyson | 6:819c17738dc2 | 302 | uint keysize ) |
andrewboyson | 6:819c17738dc2 | 303 | { |
andrewboyson | 6:819c17738dc2 | 304 | int i, j; |
andrewboyson | 6:819c17738dc2 | 305 | aes_context cty; // a calling aes context for set_encryption_key |
andrewboyson | 6:819c17738dc2 | 306 | uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer |
andrewboyson | 6:819c17738dc2 | 307 | uint32_t *SK; |
andrewboyson | 6:819c17738dc2 | 308 | int ret; |
andrewboyson | 6:819c17738dc2 | 309 | |
andrewboyson | 6:819c17738dc2 | 310 | cty.rounds = ctx->rounds; // initialize our local aes context |
andrewboyson | 6:819c17738dc2 | 311 | cty.rk = cty.buf; // round count and key buf pointer |
andrewboyson | 6:819c17738dc2 | 312 | |
andrewboyson | 6:819c17738dc2 | 313 | if (( ret = aes_set_encryption_key( &cty, key, keysize )) != 0 ) |
andrewboyson | 6:819c17738dc2 | 314 | return( ret ); |
andrewboyson | 6:819c17738dc2 | 315 | |
andrewboyson | 6:819c17738dc2 | 316 | SK = cty.rk + cty.rounds * 4; |
andrewboyson | 6:819c17738dc2 | 317 | |
andrewboyson | 6:819c17738dc2 | 318 | CPY128 // copy a 128-bit block from *SK to *RK |
andrewboyson | 6:819c17738dc2 | 319 | |
andrewboyson | 6:819c17738dc2 | 320 | for( i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8 ) { |
andrewboyson | 6:819c17738dc2 | 321 | for( j = 0; j < 4; j++, SK++ ) { |
andrewboyson | 6:819c17738dc2 | 322 | *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ |
andrewboyson | 6:819c17738dc2 | 323 | RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ |
andrewboyson | 6:819c17738dc2 | 324 | RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ |
andrewboyson | 6:819c17738dc2 | 325 | RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; |
andrewboyson | 6:819c17738dc2 | 326 | } |
andrewboyson | 6:819c17738dc2 | 327 | } |
andrewboyson | 6:819c17738dc2 | 328 | CPY128 // copy a 128-bit block from *SK to *RK |
andrewboyson | 6:819c17738dc2 | 329 | memset( &cty, 0, sizeof( aes_context ) ); // clear local aes context |
andrewboyson | 6:819c17738dc2 | 330 | return( 0 ); |
andrewboyson | 6:819c17738dc2 | 331 | } |
andrewboyson | 6:819c17738dc2 | 332 | |
andrewboyson | 6:819c17738dc2 | 333 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 334 | |
andrewboyson | 6:819c17738dc2 | 335 | /****************************************************************************** |
andrewboyson | 6:819c17738dc2 | 336 | * |
andrewboyson | 6:819c17738dc2 | 337 | * AES_SETKEY |
andrewboyson | 6:819c17738dc2 | 338 | * |
andrewboyson | 6:819c17738dc2 | 339 | * Invoked to establish the key schedule for subsequent encryption/decryption |
andrewboyson | 6:819c17738dc2 | 340 | * |
andrewboyson | 6:819c17738dc2 | 341 | ******************************************************************************/ |
andrewboyson | 6:819c17738dc2 | 342 | int aes_setkey( aes_context *ctx, // AES context provided by our caller |
andrewboyson | 6:819c17738dc2 | 343 | int mode, // ENCRYPT or DECRYPT flag |
andrewboyson | 6:819c17738dc2 | 344 | const uchar *key, // pointer to the key |
andrewboyson | 6:819c17738dc2 | 345 | uint keysize ) // key length in bytes |
andrewboyson | 6:819c17738dc2 | 346 | { |
andrewboyson | 6:819c17738dc2 | 347 | // since table initialization is not thread safe, we could either add |
andrewboyson | 6:819c17738dc2 | 348 | // system-specific mutexes and init the AES key generation tables on |
andrewboyson | 6:819c17738dc2 | 349 | // demand, or ask the developer to simply call "gcm_initialize" once during |
andrewboyson | 6:819c17738dc2 | 350 | // application startup before threading begins. That's what we choose. |
andrewboyson | 6:819c17738dc2 | 351 | if( !aes_tables_inited ) return ( 0 ); // fail the call when not inited. |
andrewboyson | 6:819c17738dc2 | 352 | |
andrewboyson | 6:819c17738dc2 | 353 | ctx->mode = mode; // capture the key type we're creating |
andrewboyson | 6:819c17738dc2 | 354 | ctx->rk = ctx->buf; // initialize our round key pointer |
andrewboyson | 6:819c17738dc2 | 355 | |
andrewboyson | 6:819c17738dc2 | 356 | switch( keysize ) // set the rounds count based upon the keysize |
andrewboyson | 6:819c17738dc2 | 357 | { |
andrewboyson | 6:819c17738dc2 | 358 | case 16: ctx->rounds = 10; break; // 16-byte, 128-bit key |
andrewboyson | 6:819c17738dc2 | 359 | case 24: ctx->rounds = 12; break; // 24-byte, 192-bit key |
andrewboyson | 6:819c17738dc2 | 360 | case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key |
andrewboyson | 6:819c17738dc2 | 361 | } |
andrewboyson | 6:819c17738dc2 | 362 | |
andrewboyson | 6:819c17738dc2 | 363 | #if AES_DECRYPTION |
andrewboyson | 6:819c17738dc2 | 364 | if( mode == DECRYPT ) // expand our key for encryption or decryption |
andrewboyson | 6:819c17738dc2 | 365 | return( aes_set_decryption_key( ctx, key, keysize ) ); |
andrewboyson | 6:819c17738dc2 | 366 | else /* ENCRYPT */ |
andrewboyson | 6:819c17738dc2 | 367 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 368 | return( aes_set_encryption_key( ctx, key, keysize ) ); |
andrewboyson | 6:819c17738dc2 | 369 | } |
andrewboyson | 6:819c17738dc2 | 370 | |
andrewboyson | 6:819c17738dc2 | 371 | /****************************************************************************** |
andrewboyson | 6:819c17738dc2 | 372 | * |
andrewboyson | 6:819c17738dc2 | 373 | * AES_CIPHER |
andrewboyson | 6:819c17738dc2 | 374 | * |
andrewboyson | 6:819c17738dc2 | 375 | * Perform AES encryption and decryption. |
andrewboyson | 6:819c17738dc2 | 376 | * The AES context will have been setup with the encryption mode |
andrewboyson | 6:819c17738dc2 | 377 | * and all keying information appropriate for the task. |
andrewboyson | 6:819c17738dc2 | 378 | * |
andrewboyson | 6:819c17738dc2 | 379 | ******************************************************************************/ |
andrewboyson | 6:819c17738dc2 | 380 | int aes_cipher( aes_context *ctx, |
andrewboyson | 6:819c17738dc2 | 381 | const uchar input[16], |
andrewboyson | 6:819c17738dc2 | 382 | uchar output[16] ) |
andrewboyson | 6:819c17738dc2 | 383 | { |
andrewboyson | 6:819c17738dc2 | 384 | int i; |
andrewboyson | 6:819c17738dc2 | 385 | uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals |
andrewboyson | 6:819c17738dc2 | 386 | |
andrewboyson | 6:819c17738dc2 | 387 | RK = ctx->rk; |
andrewboyson | 6:819c17738dc2 | 388 | |
andrewboyson | 6:819c17738dc2 | 389 | GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; // load our 128-bit |
andrewboyson | 6:819c17738dc2 | 390 | GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; // input buffer in a storage |
andrewboyson | 6:819c17738dc2 | 391 | GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; // memory endian-neutral way |
andrewboyson | 6:819c17738dc2 | 392 | GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; |
andrewboyson | 6:819c17738dc2 | 393 | |
andrewboyson | 6:819c17738dc2 | 394 | #if AES_DECRYPTION // whether AES decryption is supported |
andrewboyson | 6:819c17738dc2 | 395 | |
andrewboyson | 6:819c17738dc2 | 396 | if( ctx->mode == DECRYPT ) |
andrewboyson | 6:819c17738dc2 | 397 | { |
andrewboyson | 6:819c17738dc2 | 398 | for( i = (ctx->rounds >> 1) - 1; i > 0; i-- ) |
andrewboyson | 6:819c17738dc2 | 399 | { |
andrewboyson | 6:819c17738dc2 | 400 | AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); |
andrewboyson | 6:819c17738dc2 | 401 | AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); |
andrewboyson | 6:819c17738dc2 | 402 | } |
andrewboyson | 6:819c17738dc2 | 403 | |
andrewboyson | 6:819c17738dc2 | 404 | AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); |
andrewboyson | 6:819c17738dc2 | 405 | |
andrewboyson | 6:819c17738dc2 | 406 | X0 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 407 | ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 408 | ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 409 | ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 410 | ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 411 | |
andrewboyson | 6:819c17738dc2 | 412 | X1 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 413 | ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 414 | ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 415 | ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 416 | ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 417 | |
andrewboyson | 6:819c17738dc2 | 418 | X2 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 419 | ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 420 | ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 421 | ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 422 | ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 423 | |
andrewboyson | 6:819c17738dc2 | 424 | X3 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 425 | ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 426 | ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 427 | ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 428 | ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 429 | } |
andrewboyson | 6:819c17738dc2 | 430 | else /* ENCRYPT */ |
andrewboyson | 6:819c17738dc2 | 431 | { |
andrewboyson | 6:819c17738dc2 | 432 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 433 | |
andrewboyson | 6:819c17738dc2 | 434 | for( i = (ctx->rounds >> 1) - 1; i > 0; i-- ) |
andrewboyson | 6:819c17738dc2 | 435 | { |
andrewboyson | 6:819c17738dc2 | 436 | AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); |
andrewboyson | 6:819c17738dc2 | 437 | AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); |
andrewboyson | 6:819c17738dc2 | 438 | } |
andrewboyson | 6:819c17738dc2 | 439 | |
andrewboyson | 6:819c17738dc2 | 440 | AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); |
andrewboyson | 6:819c17738dc2 | 441 | |
andrewboyson | 6:819c17738dc2 | 442 | X0 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 443 | ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 444 | ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 445 | ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 446 | ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 447 | |
andrewboyson | 6:819c17738dc2 | 448 | X1 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 449 | ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 450 | ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 451 | ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 452 | ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 453 | |
andrewboyson | 6:819c17738dc2 | 454 | X2 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 455 | ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 456 | ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 457 | ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 458 | ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 459 | |
andrewboyson | 6:819c17738dc2 | 460 | X3 = *RK++ ^ \ |
andrewboyson | 6:819c17738dc2 | 461 | ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ |
andrewboyson | 6:819c17738dc2 | 462 | ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ |
andrewboyson | 6:819c17738dc2 | 463 | ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ |
andrewboyson | 6:819c17738dc2 | 464 | ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); |
andrewboyson | 6:819c17738dc2 | 465 | |
andrewboyson | 6:819c17738dc2 | 466 | #if AES_DECRYPTION // whether AES decryption is supported |
andrewboyson | 6:819c17738dc2 | 467 | } |
andrewboyson | 6:819c17738dc2 | 468 | #endif /* AES_DECRYPTION */ |
andrewboyson | 6:819c17738dc2 | 469 | |
andrewboyson | 6:819c17738dc2 | 470 | PUT_UINT32_LE( X0, output, 0 ); |
andrewboyson | 6:819c17738dc2 | 471 | PUT_UINT32_LE( X1, output, 4 ); |
andrewboyson | 6:819c17738dc2 | 472 | PUT_UINT32_LE( X2, output, 8 ); |
andrewboyson | 6:819c17738dc2 | 473 | PUT_UINT32_LE( X3, output, 12 ); |
andrewboyson | 6:819c17738dc2 | 474 | |
andrewboyson | 6:819c17738dc2 | 475 | return( 0 ); |
andrewboyson | 6:819c17738dc2 | 476 | } |
andrewboyson | 6:819c17738dc2 | 477 | /* end of aes.c */ |