A simple library to support serving https.

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Sun Sep 01 18:15:12 2019 +0000
Revision:
6:819c17738dc2
Making progress - now have decryption working.

Who changed what in which revision?

UserRevisionLine numberNew 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 AES-GCM authenticated
andrewboyson 6:819c17738dc2 6 * encryption. The focus of this work was correctness & accuracy. It is written
andrewboyson 6:819c17738dc2 7 * in straight 'C' without any particular focus upon optimization or speed. It
andrewboyson 6:819c17738dc2 8 * should be endian (memory byte order) neutral since the few places that care
andrewboyson 6:819c17738dc2 9 * are handled explicitly.
andrewboyson 6:819c17738dc2 10 *
andrewboyson 6:819c17738dc2 11 * This implementation of AES-GCM 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/publications/nistpubs/800-38D/SP-800-38D.pdf
andrewboyson 6:819c17738dc2 17 * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
andrewboyson 6:819c17738dc2 18 * gcm/gcm-revised-spec.pdf
andrewboyson 6:819c17738dc2 19 *
andrewboyson 6:819c17738dc2 20 * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
andrewboyson 6:819c17738dc2 21 * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
andrewboyson 6:819c17738dc2 22 *
andrewboyson 6:819c17738dc2 23 *******************************************************************************/
andrewboyson 6:819c17738dc2 24
andrewboyson 6:819c17738dc2 25 #include "gcm.h"
andrewboyson 6:819c17738dc2 26 #include "aes.h"
andrewboyson 6:819c17738dc2 27
andrewboyson 6:819c17738dc2 28 /******************************************************************************
andrewboyson 6:819c17738dc2 29 * ==== IMPLEMENTATION WARNING ====
andrewboyson 6:819c17738dc2 30 *
andrewboyson 6:819c17738dc2 31 * This code was developed for use within SQRL's fixed environmnent. Thus, it
andrewboyson 6:819c17738dc2 32 * is somewhat less "general purpose" than it would be if it were designed as
andrewboyson 6:819c17738dc2 33 * a general purpose AES-GCM library. Specifically, it bothers with almost NO
andrewboyson 6:819c17738dc2 34 * error checking on parameter limits, buffer bounds, etc. It assumes that it
andrewboyson 6:819c17738dc2 35 * is being invoked by its author or by someone who understands the values it
andrewboyson 6:819c17738dc2 36 * expects to receive. Its behavior will be undefined otherwise.
andrewboyson 6:819c17738dc2 37 *
andrewboyson 6:819c17738dc2 38 * All functions that might fail are defined to return 'ints' to indicate a
andrewboyson 6:819c17738dc2 39 * problem. Most do not do so now. But this allows for error propagation out
andrewboyson 6:819c17738dc2 40 * of internal functions if robust error checking should ever be desired.
andrewboyson 6:819c17738dc2 41 *
andrewboyson 6:819c17738dc2 42 ******************************************************************************/
andrewboyson 6:819c17738dc2 43
andrewboyson 6:819c17738dc2 44 /* Calculating the "GHASH"
andrewboyson 6:819c17738dc2 45 *
andrewboyson 6:819c17738dc2 46 * There are many ways of calculating the so-called GHASH in software, each with
andrewboyson 6:819c17738dc2 47 * a traditional size vs performance tradeoff. The GHASH (Galois field hash) is
andrewboyson 6:819c17738dc2 48 * an intriguing construction which takes two 128-bit strings (also the cipher's
andrewboyson 6:819c17738dc2 49 * block size and the fundamental operation size for the system) and hashes them
andrewboyson 6:819c17738dc2 50 * into a third 128-bit result.
andrewboyson 6:819c17738dc2 51 *
andrewboyson 6:819c17738dc2 52 * Many implementation solutions have been worked out that use large precomputed
andrewboyson 6:819c17738dc2 53 * table lookups in place of more time consuming bit fiddling, and this approach
andrewboyson 6:819c17738dc2 54 * can be scaled easily upward or downward as needed to change the time/space
andrewboyson 6:819c17738dc2 55 * tradeoff. It's been studied extensively and there's a solid body of theory and
andrewboyson 6:819c17738dc2 56 * practice. For example, without using any lookup tables an implementation
andrewboyson 6:819c17738dc2 57 * might obtain 119 cycles per byte throughput, whereas using a simple, though
andrewboyson 6:819c17738dc2 58 * large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13
andrewboyson 6:819c17738dc2 59 * cycles per byte.
andrewboyson 6:819c17738dc2 60 *
andrewboyson 6:819c17738dc2 61 * And Intel's processors have, since 2010, included an instruction which does
andrewboyson 6:819c17738dc2 62 * the entire 128x128->128 bit job in just several 64x64->128 bit pieces.
andrewboyson 6:819c17738dc2 63 *
andrewboyson 6:819c17738dc2 64 * Since SQRL is interactive, and only processing a few 128-bit blocks, I've
andrewboyson 6:819c17738dc2 65 * settled upon a relatively slower but appealing small-table compromise which
andrewboyson 6:819c17738dc2 66 * folds a bunch of not only time consuming but also bit twiddling into a simple
andrewboyson 6:819c17738dc2 67 * 16-entry table which is attributed to Victor Shoup's 1996 work while at
andrewboyson 6:819c17738dc2 68 * Bellcore: "On Fast and Provably Secure MessageAuthentication Based on
andrewboyson 6:819c17738dc2 69 * Universal Hashing." See: http://www.shoup.net/papers/macs.pdf
andrewboyson 6:819c17738dc2 70 * See, also section 4.1 of the "gcm-revised-spec" cited above.
andrewboyson 6:819c17738dc2 71 */
andrewboyson 6:819c17738dc2 72
andrewboyson 6:819c17738dc2 73 /*
andrewboyson 6:819c17738dc2 74 * This 16-entry table of pre-computed constants is used by the
andrewboyson 6:819c17738dc2 75 * GHASH multiplier to improve over a strictly table-free but
andrewboyson 6:819c17738dc2 76 * significantly slower 128x128 bit multiple within GF(2^128).
andrewboyson 6:819c17738dc2 77 */
andrewboyson 6:819c17738dc2 78 static const uint64_t last4[16] = {
andrewboyson 6:819c17738dc2 79 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
andrewboyson 6:819c17738dc2 80 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0 };
andrewboyson 6:819c17738dc2 81
andrewboyson 6:819c17738dc2 82 /*
andrewboyson 6:819c17738dc2 83 * Platform Endianness Neutralizing Load and Store Macro definitions
andrewboyson 6:819c17738dc2 84 * GCM wants platform-neutral Big Endian (BE) byte ordering
andrewboyson 6:819c17738dc2 85 */
andrewboyson 6:819c17738dc2 86 #define GET_UINT32_BE(n,b,i) { \
andrewboyson 6:819c17738dc2 87 (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
andrewboyson 6:819c17738dc2 88 | ( (uint32_t) (b)[(i) + 1] << 16 ) \
andrewboyson 6:819c17738dc2 89 | ( (uint32_t) (b)[(i) + 2] << 8 ) \
andrewboyson 6:819c17738dc2 90 | ( (uint32_t) (b)[(i) + 3] ); }
andrewboyson 6:819c17738dc2 91
andrewboyson 6:819c17738dc2 92 #define PUT_UINT32_BE(n,b,i) { \
andrewboyson 6:819c17738dc2 93 (b)[(i) ] = (uchar) ( (n) >> 24 ); \
andrewboyson 6:819c17738dc2 94 (b)[(i) + 1] = (uchar) ( (n) >> 16 ); \
andrewboyson 6:819c17738dc2 95 (b)[(i) + 2] = (uchar) ( (n) >> 8 ); \
andrewboyson 6:819c17738dc2 96 (b)[(i) + 3] = (uchar) ( (n) ); }
andrewboyson 6:819c17738dc2 97
andrewboyson 6:819c17738dc2 98
andrewboyson 6:819c17738dc2 99 /******************************************************************************
andrewboyson 6:819c17738dc2 100 *
andrewboyson 6:819c17738dc2 101 * GCM_INITIALIZE
andrewboyson 6:819c17738dc2 102 *
andrewboyson 6:819c17738dc2 103 * Must be called once to initialize the GCM library.
andrewboyson 6:819c17738dc2 104 *
andrewboyson 6:819c17738dc2 105 * At present, this only calls the AES keygen table generator, which expands
andrewboyson 6:819c17738dc2 106 * the AES keying tables for use. This is NOT A THREAD-SAFE function, so it
andrewboyson 6:819c17738dc2 107 * MUST be called during system initialization before a multi-threading
andrewboyson 6:819c17738dc2 108 * environment is running.
andrewboyson 6:819c17738dc2 109 *
andrewboyson 6:819c17738dc2 110 ******************************************************************************/
andrewboyson 6:819c17738dc2 111 int gcm_initialize( void )
andrewboyson 6:819c17738dc2 112 {
andrewboyson 6:819c17738dc2 113 aes_init_keygen_tables();
andrewboyson 6:819c17738dc2 114 return( 0 );
andrewboyson 6:819c17738dc2 115 }
andrewboyson 6:819c17738dc2 116
andrewboyson 6:819c17738dc2 117
andrewboyson 6:819c17738dc2 118 /******************************************************************************
andrewboyson 6:819c17738dc2 119 *
andrewboyson 6:819c17738dc2 120 * GCM_MULT
andrewboyson 6:819c17738dc2 121 *
andrewboyson 6:819c17738dc2 122 * Performs a GHASH operation on the 128-bit input vector 'x', setting
andrewboyson 6:819c17738dc2 123 * the 128-bit output vector to 'x' times H using our precomputed tables.
andrewboyson 6:819c17738dc2 124 * 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
andrewboyson 6:819c17738dc2 125 *
andrewboyson 6:819c17738dc2 126 ******************************************************************************/
andrewboyson 6:819c17738dc2 127 static void gcm_mult( gcm_context *ctx, // pointer to established context
andrewboyson 6:819c17738dc2 128 const uchar x[16], // pointer to 128-bit input vector
andrewboyson 6:819c17738dc2 129 uchar output[16] ) // pointer to 128-bit output vector
andrewboyson 6:819c17738dc2 130 {
andrewboyson 6:819c17738dc2 131 int i;
andrewboyson 6:819c17738dc2 132 uchar lo, hi, rem;
andrewboyson 6:819c17738dc2 133 uint64_t zh, zl;
andrewboyson 6:819c17738dc2 134
andrewboyson 6:819c17738dc2 135 lo = (uchar)( x[15] & 0x0f );
andrewboyson 6:819c17738dc2 136 hi = (uchar)( x[15] >> 4 );
andrewboyson 6:819c17738dc2 137 zh = ctx->HH[lo];
andrewboyson 6:819c17738dc2 138 zl = ctx->HL[lo];
andrewboyson 6:819c17738dc2 139
andrewboyson 6:819c17738dc2 140 for( i = 15; i >= 0; i-- ) {
andrewboyson 6:819c17738dc2 141 lo = (uchar) ( x[i] & 0x0f );
andrewboyson 6:819c17738dc2 142 hi = (uchar) ( x[i] >> 4 );
andrewboyson 6:819c17738dc2 143
andrewboyson 6:819c17738dc2 144 if( i != 15 ) {
andrewboyson 6:819c17738dc2 145 rem = (uchar) ( zl & 0x0f );
andrewboyson 6:819c17738dc2 146 zl = ( zh << 60 ) | ( zl >> 4 );
andrewboyson 6:819c17738dc2 147 zh = ( zh >> 4 );
andrewboyson 6:819c17738dc2 148 zh ^= (uint64_t) last4[rem] << 48;
andrewboyson 6:819c17738dc2 149 zh ^= ctx->HH[lo];
andrewboyson 6:819c17738dc2 150 zl ^= ctx->HL[lo];
andrewboyson 6:819c17738dc2 151 }
andrewboyson 6:819c17738dc2 152 rem = (uchar) ( zl & 0x0f );
andrewboyson 6:819c17738dc2 153 zl = ( zh << 60 ) | ( zl >> 4 );
andrewboyson 6:819c17738dc2 154 zh = ( zh >> 4 );
andrewboyson 6:819c17738dc2 155 zh ^= (uint64_t) last4[rem] << 48;
andrewboyson 6:819c17738dc2 156 zh ^= ctx->HH[hi];
andrewboyson 6:819c17738dc2 157 zl ^= ctx->HL[hi];
andrewboyson 6:819c17738dc2 158 }
andrewboyson 6:819c17738dc2 159 PUT_UINT32_BE( zh >> 32, output, 0 );
andrewboyson 6:819c17738dc2 160 PUT_UINT32_BE( zh, output, 4 );
andrewboyson 6:819c17738dc2 161 PUT_UINT32_BE( zl >> 32, output, 8 );
andrewboyson 6:819c17738dc2 162 PUT_UINT32_BE( zl, output, 12 );
andrewboyson 6:819c17738dc2 163 }
andrewboyson 6:819c17738dc2 164
andrewboyson 6:819c17738dc2 165
andrewboyson 6:819c17738dc2 166 /******************************************************************************
andrewboyson 6:819c17738dc2 167 *
andrewboyson 6:819c17738dc2 168 * GCM_SETKEY
andrewboyson 6:819c17738dc2 169 *
andrewboyson 6:819c17738dc2 170 * This is called to set the AES-GCM key. It initializes the AES key
andrewboyson 6:819c17738dc2 171 * and populates the gcm context's pre-calculated HTables.
andrewboyson 6:819c17738dc2 172 *
andrewboyson 6:819c17738dc2 173 ******************************************************************************/
andrewboyson 6:819c17738dc2 174 int gcm_setkey( gcm_context *ctx, // pointer to caller-provided gcm context
andrewboyson 6:819c17738dc2 175 const uchar *key, // pointer to the AES encryption key
andrewboyson 6:819c17738dc2 176 const uint keysize) // must be 128, 192 or 256
andrewboyson 6:819c17738dc2 177 {
andrewboyson 6:819c17738dc2 178 int ret, i, j;
andrewboyson 6:819c17738dc2 179 uint64_t hi, lo;
andrewboyson 6:819c17738dc2 180 uint64_t vl, vh;
andrewboyson 6:819c17738dc2 181 unsigned char h[16];
andrewboyson 6:819c17738dc2 182
andrewboyson 6:819c17738dc2 183 memset( ctx, 0, sizeof(gcm_context) ); // zero caller-provided GCM context
andrewboyson 6:819c17738dc2 184 memset( h, 0, 16 ); // initialize the block to encrypt
andrewboyson 6:819c17738dc2 185
andrewboyson 6:819c17738dc2 186 // encrypt the null 128-bit block to generate a key-based value
andrewboyson 6:819c17738dc2 187 // which is then used to initialize our GHASH lookup tables
andrewboyson 6:819c17738dc2 188 if(( ret = aes_setkey( &ctx->aes_ctx, ENCRYPT, key, keysize )) != 0 )
andrewboyson 6:819c17738dc2 189 return( ret );
andrewboyson 6:819c17738dc2 190 if(( ret = aes_cipher( &ctx->aes_ctx, h, h )) != 0 )
andrewboyson 6:819c17738dc2 191 return( ret );
andrewboyson 6:819c17738dc2 192
andrewboyson 6:819c17738dc2 193 GET_UINT32_BE( hi, h, 0 ); // pack h as two 64-bit ints, big-endian
andrewboyson 6:819c17738dc2 194 GET_UINT32_BE( lo, h, 4 );
andrewboyson 6:819c17738dc2 195 vh = (uint64_t) hi << 32 | lo;
andrewboyson 6:819c17738dc2 196
andrewboyson 6:819c17738dc2 197 GET_UINT32_BE( hi, h, 8 );
andrewboyson 6:819c17738dc2 198 GET_UINT32_BE( lo, h, 12 );
andrewboyson 6:819c17738dc2 199 vl = (uint64_t) hi << 32 | lo;
andrewboyson 6:819c17738dc2 200
andrewboyson 6:819c17738dc2 201 ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
andrewboyson 6:819c17738dc2 202 ctx->HH[8] = vh;
andrewboyson 6:819c17738dc2 203 ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
andrewboyson 6:819c17738dc2 204 ctx->HL[0] = 0;
andrewboyson 6:819c17738dc2 205
andrewboyson 6:819c17738dc2 206 for( i = 4; i > 0; i >>= 1 ) {
andrewboyson 6:819c17738dc2 207 uint32_t T = (uint32_t) ( vl & 1 ) * 0xe1000000U;
andrewboyson 6:819c17738dc2 208 vl = ( vh << 63 ) | ( vl >> 1 );
andrewboyson 6:819c17738dc2 209 vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32);
andrewboyson 6:819c17738dc2 210 ctx->HL[i] = vl;
andrewboyson 6:819c17738dc2 211 ctx->HH[i] = vh;
andrewboyson 6:819c17738dc2 212 }
andrewboyson 6:819c17738dc2 213 for (i = 2; i < 16; i <<= 1 ) {
andrewboyson 6:819c17738dc2 214 uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
andrewboyson 6:819c17738dc2 215 vh = *HiH;
andrewboyson 6:819c17738dc2 216 vl = *HiL;
andrewboyson 6:819c17738dc2 217 for( j = 1; j < i; j++ ) {
andrewboyson 6:819c17738dc2 218 HiH[j] = vh ^ ctx->HH[j];
andrewboyson 6:819c17738dc2 219 HiL[j] = vl ^ ctx->HL[j];
andrewboyson 6:819c17738dc2 220 }
andrewboyson 6:819c17738dc2 221 }
andrewboyson 6:819c17738dc2 222 return( 0 );
andrewboyson 6:819c17738dc2 223 }
andrewboyson 6:819c17738dc2 224
andrewboyson 6:819c17738dc2 225
andrewboyson 6:819c17738dc2 226 /******************************************************************************
andrewboyson 6:819c17738dc2 227 *
andrewboyson 6:819c17738dc2 228 * GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
andrewboyson 6:819c17738dc2 229 *
andrewboyson 6:819c17738dc2 230 * SETKEY:
andrewboyson 6:819c17738dc2 231 *
andrewboyson 6:819c17738dc2 232 * START: Sets the Encryption/Decryption mode.
andrewboyson 6:819c17738dc2 233 * Accepts the initialization vector and additional data.
andrewboyson 6:819c17738dc2 234 *
andrewboyson 6:819c17738dc2 235 * UPDATE: Encrypts or decrypts the plaintext or ciphertext.
andrewboyson 6:819c17738dc2 236 *
andrewboyson 6:819c17738dc2 237 * FINISH: Performs a final GHASH to generate the authentication tag.
andrewboyson 6:819c17738dc2 238 *
andrewboyson 6:819c17738dc2 239 ******************************************************************************
andrewboyson 6:819c17738dc2 240 *
andrewboyson 6:819c17738dc2 241 * GCM_START
andrewboyson 6:819c17738dc2 242 *
andrewboyson 6:819c17738dc2 243 * Given a user-provided GCM context, this initializes it, sets the encryption
andrewboyson 6:819c17738dc2 244 * mode, and preprocesses the initialization vector and additional AEAD data.
andrewboyson 6:819c17738dc2 245 *
andrewboyson 6:819c17738dc2 246 ******************************************************************************/
andrewboyson 6:819c17738dc2 247 int gcm_start( gcm_context *ctx, // pointer to user-provided GCM context
andrewboyson 6:819c17738dc2 248 int mode, // GCM_ENCRYPT or GCM_DECRYPT
andrewboyson 6:819c17738dc2 249 const uchar *iv, // pointer to initialization vector
andrewboyson 6:819c17738dc2 250 size_t iv_len, // IV length in bytes (should == 12)
andrewboyson 6:819c17738dc2 251 const uchar *add, // ptr to additional AEAD data (NULL if none)
andrewboyson 6:819c17738dc2 252 size_t add_len ) // length of additional AEAD data (bytes)
andrewboyson 6:819c17738dc2 253 {
andrewboyson 6:819c17738dc2 254 int ret; // our error return if the AES encrypt fails
andrewboyson 6:819c17738dc2 255 uchar work_buf[16]; // XOR source built from provided IV if len != 16
andrewboyson 6:819c17738dc2 256 const uchar *p; // general purpose array pointer
andrewboyson 6:819c17738dc2 257 size_t use_len; // byte count to process, up to 16 bytes
andrewboyson 6:819c17738dc2 258 size_t i; // local loop iterator
andrewboyson 6:819c17738dc2 259
andrewboyson 6:819c17738dc2 260 // since the context might be reused under the same key
andrewboyson 6:819c17738dc2 261 // we zero the working buffers for this next new process
andrewboyson 6:819c17738dc2 262 memset( ctx->y, 0x00, sizeof(ctx->y ) );
andrewboyson 6:819c17738dc2 263 memset( ctx->buf, 0x00, sizeof(ctx->buf) );
andrewboyson 6:819c17738dc2 264 ctx->len = 0;
andrewboyson 6:819c17738dc2 265 ctx->add_len = 0;
andrewboyson 6:819c17738dc2 266
andrewboyson 6:819c17738dc2 267 ctx->mode = mode; // set the GCM encryption/decryption mode
andrewboyson 6:819c17738dc2 268 ctx->aes_ctx.mode = ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
andrewboyson 6:819c17738dc2 269
andrewboyson 6:819c17738dc2 270 if( iv_len == 12 ) { // GCM natively uses a 12-byte, 96-bit IV
andrewboyson 6:819c17738dc2 271 memcpy( ctx->y, iv, iv_len ); // copy the IV to the top of the 'y' buff
andrewboyson 6:819c17738dc2 272 ctx->y[15] = 1; // start "counting" from 1 (not 0)
andrewboyson 6:819c17738dc2 273 }
andrewboyson 6:819c17738dc2 274 else // if we don't have a 12-byte IV, we GHASH whatever we've been given
andrewboyson 6:819c17738dc2 275 {
andrewboyson 6:819c17738dc2 276 memset( work_buf, 0x00, 16 ); // clear the working buffer
andrewboyson 6:819c17738dc2 277 PUT_UINT32_BE( iv_len * 8, work_buf, 12 ); // place the IV into buffer
andrewboyson 6:819c17738dc2 278
andrewboyson 6:819c17738dc2 279 p = iv;
andrewboyson 6:819c17738dc2 280 while( iv_len > 0 ) {
andrewboyson 6:819c17738dc2 281 use_len = ( iv_len < 16 ) ? iv_len : 16;
andrewboyson 6:819c17738dc2 282 for( i = 0; i < use_len; i++ ) ctx->y[i] ^= p[i];
andrewboyson 6:819c17738dc2 283 gcm_mult( ctx, ctx->y, ctx->y );
andrewboyson 6:819c17738dc2 284 iv_len -= use_len;
andrewboyson 6:819c17738dc2 285 p += use_len;
andrewboyson 6:819c17738dc2 286 }
andrewboyson 6:819c17738dc2 287 for( i = 0; i < 16; i++ ) ctx->y[i] ^= work_buf[i];
andrewboyson 6:819c17738dc2 288 gcm_mult( ctx, ctx->y, ctx->y );
andrewboyson 6:819c17738dc2 289 }
andrewboyson 6:819c17738dc2 290 if( ( ret = aes_cipher( &ctx->aes_ctx, ctx->y, ctx->base_ectr ) ) != 0 )
andrewboyson 6:819c17738dc2 291 return( ret );
andrewboyson 6:819c17738dc2 292
andrewboyson 6:819c17738dc2 293 ctx->add_len = add_len;
andrewboyson 6:819c17738dc2 294 p = add;
andrewboyson 6:819c17738dc2 295 while( add_len > 0 ) {
andrewboyson 6:819c17738dc2 296 use_len = ( add_len < 16 ) ? add_len : 16;
andrewboyson 6:819c17738dc2 297 for( i = 0; i < use_len; i++ ) ctx->buf[i] ^= p[i];
andrewboyson 6:819c17738dc2 298 gcm_mult( ctx, ctx->buf, ctx->buf );
andrewboyson 6:819c17738dc2 299 add_len -= use_len;
andrewboyson 6:819c17738dc2 300 p += use_len;
andrewboyson 6:819c17738dc2 301 }
andrewboyson 6:819c17738dc2 302 return( 0 );
andrewboyson 6:819c17738dc2 303 }
andrewboyson 6:819c17738dc2 304
andrewboyson 6:819c17738dc2 305 /******************************************************************************
andrewboyson 6:819c17738dc2 306 *
andrewboyson 6:819c17738dc2 307 * GCM_UPDATE
andrewboyson 6:819c17738dc2 308 *
andrewboyson 6:819c17738dc2 309 * This is called once or more to process bulk plaintext or ciphertext data.
andrewboyson 6:819c17738dc2 310 * We give this some number of bytes of input and it returns the same number
andrewboyson 6:819c17738dc2 311 * of output bytes. If called multiple times (which is fine) all but the final
andrewboyson 6:819c17738dc2 312 * invocation MUST be called with length mod 16 == 0. (Only the final call can
andrewboyson 6:819c17738dc2 313 * have a partial block length of < 128 bits.)
andrewboyson 6:819c17738dc2 314 *
andrewboyson 6:819c17738dc2 315 ******************************************************************************/
andrewboyson 6:819c17738dc2 316 int gcm_update( gcm_context *ctx, // pointer to user-provided GCM context
andrewboyson 6:819c17738dc2 317 size_t length, // length, in bytes, of data to process
andrewboyson 6:819c17738dc2 318 const uchar *input, // pointer to source data
andrewboyson 6:819c17738dc2 319 uchar *output ) // pointer to destination data
andrewboyson 6:819c17738dc2 320 {
andrewboyson 6:819c17738dc2 321 int ret; // our error return if the AES encrypt fails
andrewboyson 6:819c17738dc2 322 uchar ectr[16]; // counter-mode cipher output for XORing
andrewboyson 6:819c17738dc2 323 size_t use_len; // byte count to process, up to 16 bytes
andrewboyson 6:819c17738dc2 324 size_t i; // local loop iterator
andrewboyson 6:819c17738dc2 325
andrewboyson 6:819c17738dc2 326 ctx->len += length; // bump the GCM context's running length count
andrewboyson 6:819c17738dc2 327
andrewboyson 6:819c17738dc2 328 while( length > 0 ) {
andrewboyson 6:819c17738dc2 329 // clamp the length to process at 16 bytes
andrewboyson 6:819c17738dc2 330 use_len = ( length < 16 ) ? length : 16;
andrewboyson 6:819c17738dc2 331
andrewboyson 6:819c17738dc2 332 // increment the context's 128-bit IV||Counter 'y' vector
andrewboyson 6:819c17738dc2 333 for( i = 16; i > 12; i-- ) if( ++ctx->y[i - 1] != 0 ) break;
andrewboyson 6:819c17738dc2 334
andrewboyson 6:819c17738dc2 335 // encrypt the context's 'y' vector under the established key
andrewboyson 6:819c17738dc2 336 if( ( ret = aes_cipher( &ctx->aes_ctx, ctx->y, ectr ) ) != 0 )
andrewboyson 6:819c17738dc2 337 return( ret );
andrewboyson 6:819c17738dc2 338
andrewboyson 6:819c17738dc2 339 // encrypt or decrypt the input to the output
andrewboyson 6:819c17738dc2 340 for( i = 0; i < use_len; i++ ) {
andrewboyson 6:819c17738dc2 341 // XOR the cipher's ouptut vector (ectr) with our input
andrewboyson 6:819c17738dc2 342 output[i] = (uchar) ( ectr[i] ^ input[i] );
andrewboyson 6:819c17738dc2 343 // now we mix in our data into the authentication hash.
andrewboyson 6:819c17738dc2 344 // if we're ENcrypting we XOR in the post-XOR (output) results,
andrewboyson 6:819c17738dc2 345 // but if we're DEcrypting we XOR in the input data
andrewboyson 6:819c17738dc2 346 if( ctx->mode == ENCRYPT ) ctx->buf[i] ^= output[i];
andrewboyson 6:819c17738dc2 347 else ctx->buf[i] ^= input[i];
andrewboyson 6:819c17738dc2 348 }
andrewboyson 6:819c17738dc2 349 gcm_mult( ctx, ctx->buf, ctx->buf ); // perform a GHASH operation
andrewboyson 6:819c17738dc2 350
andrewboyson 6:819c17738dc2 351 length -= use_len; // drop the remaining byte count to process
andrewboyson 6:819c17738dc2 352 input += use_len; // bump our input pointer forward
andrewboyson 6:819c17738dc2 353 output += use_len; // bump our output pointer forward
andrewboyson 6:819c17738dc2 354 }
andrewboyson 6:819c17738dc2 355 return( 0 );
andrewboyson 6:819c17738dc2 356 }
andrewboyson 6:819c17738dc2 357
andrewboyson 6:819c17738dc2 358 /******************************************************************************
andrewboyson 6:819c17738dc2 359 *
andrewboyson 6:819c17738dc2 360 * GCM_FINISH
andrewboyson 6:819c17738dc2 361 *
andrewboyson 6:819c17738dc2 362 * This is called once after all calls to GCM_UPDATE to finalize the GCM.
andrewboyson 6:819c17738dc2 363 * It performs the final GHASH to produce the resulting authentication TAG.
andrewboyson 6:819c17738dc2 364 *
andrewboyson 6:819c17738dc2 365 ******************************************************************************/
andrewboyson 6:819c17738dc2 366 int gcm_finish( gcm_context *ctx, // pointer to user-provided GCM context
andrewboyson 6:819c17738dc2 367 uchar *tag, // pointer to buffer which receives the tag
andrewboyson 6:819c17738dc2 368 size_t tag_len ) // length, in bytes, of the tag-receiving buf
andrewboyson 6:819c17738dc2 369 {
andrewboyson 6:819c17738dc2 370 uchar work_buf[16];
andrewboyson 6:819c17738dc2 371 uint64_t orig_len = ctx->len * 8;
andrewboyson 6:819c17738dc2 372 uint64_t orig_add_len = ctx->add_len * 8;
andrewboyson 6:819c17738dc2 373 size_t i;
andrewboyson 6:819c17738dc2 374
andrewboyson 6:819c17738dc2 375 if( tag_len != 0 ) memcpy( tag, ctx->base_ectr, tag_len );
andrewboyson 6:819c17738dc2 376
andrewboyson 6:819c17738dc2 377 if( orig_len || orig_add_len ) {
andrewboyson 6:819c17738dc2 378 memset( work_buf, 0x00, 16 );
andrewboyson 6:819c17738dc2 379
andrewboyson 6:819c17738dc2 380 PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 );
andrewboyson 6:819c17738dc2 381 PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 );
andrewboyson 6:819c17738dc2 382 PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 );
andrewboyson 6:819c17738dc2 383 PUT_UINT32_BE( ( orig_len ), work_buf, 12 );
andrewboyson 6:819c17738dc2 384
andrewboyson 6:819c17738dc2 385 for( i = 0; i < 16; i++ ) ctx->buf[i] ^= work_buf[i];
andrewboyson 6:819c17738dc2 386 gcm_mult( ctx, ctx->buf, ctx->buf );
andrewboyson 6:819c17738dc2 387 for( i = 0; i < tag_len; i++ ) tag[i] ^= ctx->buf[i];
andrewboyson 6:819c17738dc2 388 }
andrewboyson 6:819c17738dc2 389 return( 0 );
andrewboyson 6:819c17738dc2 390 }
andrewboyson 6:819c17738dc2 391
andrewboyson 6:819c17738dc2 392
andrewboyson 6:819c17738dc2 393 /******************************************************************************
andrewboyson 6:819c17738dc2 394 *
andrewboyson 6:819c17738dc2 395 * GCM_CRYPT_AND_TAG
andrewboyson 6:819c17738dc2 396 *
andrewboyson 6:819c17738dc2 397 * This either encrypts or decrypts the user-provided data and, either
andrewboyson 6:819c17738dc2 398 * way, generates an authentication tag of the requested length. It must be
andrewboyson 6:819c17738dc2 399 * called with a GCM context whose key has already been set with GCM_SETKEY.
andrewboyson 6:819c17738dc2 400 *
andrewboyson 6:819c17738dc2 401 * The user would typically call this explicitly to ENCRYPT a buffer of data
andrewboyson 6:819c17738dc2 402 * and optional associated data, and produce its an authentication tag.
andrewboyson 6:819c17738dc2 403 *
andrewboyson 6:819c17738dc2 404 * To reverse the process the user would typically call the companion
andrewboyson 6:819c17738dc2 405 * GCM_AUTH_DECRYPT function to decrypt data and verify a user-provided
andrewboyson 6:819c17738dc2 406 * authentication tag. The GCM_AUTH_DECRYPT function calls this function
andrewboyson 6:819c17738dc2 407 * to perform its decryption and tag generation, which it then compares.
andrewboyson 6:819c17738dc2 408 *
andrewboyson 6:819c17738dc2 409 ******************************************************************************/
andrewboyson 6:819c17738dc2 410 int gcm_crypt_and_tag(
andrewboyson 6:819c17738dc2 411 gcm_context *ctx, // gcm context with key already setup
andrewboyson 6:819c17738dc2 412 int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
andrewboyson 6:819c17738dc2 413 const uchar *iv, // pointer to the 12-byte initialization vector
andrewboyson 6:819c17738dc2 414 size_t iv_len, // byte length if the IV. should always be 12
andrewboyson 6:819c17738dc2 415 const uchar *add, // pointer to the non-ciphered additional data
andrewboyson 6:819c17738dc2 416 size_t add_len, // byte length of the additional AEAD data
andrewboyson 6:819c17738dc2 417 const uchar *input, // pointer to the cipher data source
andrewboyson 6:819c17738dc2 418 uchar *output, // pointer to the cipher data destination
andrewboyson 6:819c17738dc2 419 size_t length, // byte length of the cipher data
andrewboyson 6:819c17738dc2 420 uchar *tag, // pointer to the tag to be generated
andrewboyson 6:819c17738dc2 421 size_t tag_len ) // byte length of the tag to be generated
andrewboyson 6:819c17738dc2 422 { /*
andrewboyson 6:819c17738dc2 423 assuming that the caller has already invoked gcm_setkey to
andrewboyson 6:819c17738dc2 424 prepare the gcm context with the keying material, we simply
andrewboyson 6:819c17738dc2 425 invoke each of the three GCM sub-functions in turn...
andrewboyson 6:819c17738dc2 426 */
andrewboyson 6:819c17738dc2 427 gcm_start ( ctx, mode, iv, iv_len, add, add_len );
andrewboyson 6:819c17738dc2 428 gcm_update ( ctx, length, input, output );
andrewboyson 6:819c17738dc2 429 gcm_finish ( ctx, tag, tag_len );
andrewboyson 6:819c17738dc2 430 return( 0 );
andrewboyson 6:819c17738dc2 431 }
andrewboyson 6:819c17738dc2 432
andrewboyson 6:819c17738dc2 433
andrewboyson 6:819c17738dc2 434 /******************************************************************************
andrewboyson 6:819c17738dc2 435 *
andrewboyson 6:819c17738dc2 436 * GCM_AUTH_DECRYPT
andrewboyson 6:819c17738dc2 437 *
andrewboyson 6:819c17738dc2 438 * This DECRYPTS a user-provided data buffer with optional associated data.
andrewboyson 6:819c17738dc2 439 * It then verifies a user-supplied authentication tag against the tag just
andrewboyson 6:819c17738dc2 440 * re-created during decryption to verify that the data has not been altered.
andrewboyson 6:819c17738dc2 441 *
andrewboyson 6:819c17738dc2 442 * This function calls GCM_CRYPT_AND_TAG (above) to perform the decryption
andrewboyson 6:819c17738dc2 443 * and authentication tag generation.
andrewboyson 6:819c17738dc2 444 *
andrewboyson 6:819c17738dc2 445 ******************************************************************************/
andrewboyson 6:819c17738dc2 446 int gcm_auth_decrypt(
andrewboyson 6:819c17738dc2 447 gcm_context *ctx, // gcm context with key already setup
andrewboyson 6:819c17738dc2 448 const uchar *iv, // pointer to the 12-byte initialization vector
andrewboyson 6:819c17738dc2 449 size_t iv_len, // byte length if the IV. should always be 12
andrewboyson 6:819c17738dc2 450 const uchar *add, // pointer to the non-ciphered additional data
andrewboyson 6:819c17738dc2 451 size_t add_len, // byte length of the additional AEAD data
andrewboyson 6:819c17738dc2 452 const uchar *input, // pointer to the cipher data source
andrewboyson 6:819c17738dc2 453 uchar *output, // pointer to the cipher data destination
andrewboyson 6:819c17738dc2 454 size_t length, // byte length of the cipher data
andrewboyson 6:819c17738dc2 455 const uchar *tag, // pointer to the tag to be authenticated
andrewboyson 6:819c17738dc2 456 size_t tag_len ) // byte length of the tag <= 16
andrewboyson 6:819c17738dc2 457 {
andrewboyson 6:819c17738dc2 458 uchar check_tag[16]; // the tag generated and returned by decryption
andrewboyson 6:819c17738dc2 459 int diff; // an ORed flag to detect authentication errors
andrewboyson 6:819c17738dc2 460 size_t i; // our local iterator
andrewboyson 6:819c17738dc2 461 /*
andrewboyson 6:819c17738dc2 462 we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
andrewboyson 6:819c17738dc2 463 (which is an identical XORing to reverse the previous one)
andrewboyson 6:819c17738dc2 464 and also to re-generate the matching authentication tag
andrewboyson 6:819c17738dc2 465 */
andrewboyson 6:819c17738dc2 466 gcm_crypt_and_tag( ctx, DECRYPT, iv, iv_len, add, add_len,
andrewboyson 6:819c17738dc2 467 input, output, length, check_tag, tag_len );
andrewboyson 6:819c17738dc2 468
andrewboyson 6:819c17738dc2 469 // now we verify the authentication tag in 'constant time'
andrewboyson 6:819c17738dc2 470 for( diff = 0, i = 0; i < tag_len; i++ )
andrewboyson 6:819c17738dc2 471 diff |= tag[i] ^ check_tag[i];
andrewboyson 6:819c17738dc2 472
andrewboyson 6:819c17738dc2 473 if( diff != 0 ) { // see whether any bits differed?
andrewboyson 6:819c17738dc2 474 memset( output, 0, length ); // if so... wipe the output data
andrewboyson 6:819c17738dc2 475 return( GCM_AUTH_FAILURE ); // return GCM_AUTH_FAILURE
andrewboyson 6:819c17738dc2 476 }
andrewboyson 6:819c17738dc2 477 return( 0 );
andrewboyson 6:819c17738dc2 478 }
andrewboyson 6:819c17738dc2 479
andrewboyson 6:819c17738dc2 480 /******************************************************************************
andrewboyson 6:819c17738dc2 481 *
andrewboyson 6:819c17738dc2 482 * GCM_ZERO_CTX
andrewboyson 6:819c17738dc2 483 *
andrewboyson 6:819c17738dc2 484 * The GCM context contains both the GCM context and the AES context.
andrewboyson 6:819c17738dc2 485 * This includes keying and key-related material which is security-
andrewboyson 6:819c17738dc2 486 * sensitive, so it MUST be zeroed after use. This function does that.
andrewboyson 6:819c17738dc2 487 *
andrewboyson 6:819c17738dc2 488 ******************************************************************************/
andrewboyson 6:819c17738dc2 489 void gcm_zero_ctx( gcm_context *ctx )
andrewboyson 6:819c17738dc2 490 {
andrewboyson 6:819c17738dc2 491 // zero the context originally provided to us
andrewboyson 6:819c17738dc2 492 memset( ctx, 0, sizeof( gcm_context ) );
andrewboyson 6:819c17738dc2 493 }