aes_ige.c revision 194206
1100384Speter/* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */ 2100384Speter/* ==================================================================== 3100384Speter * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 4100384Speter * 5100384Speter * Redistribution and use in source and binary forms, with or without 6100384Speter * modification, are permitted provided that the following conditions 7100384Speter * are met: 8100384Speter * 9100384Speter * 1. Redistributions of source code must retain the above copyright 10100384Speter * notice, this list of conditions and the following disclaimer. 11100384Speter * 12100384Speter * 2. Redistributions in binary form must reproduce the above copyright 13100384Speter * notice, this list of conditions and the following disclaimer in 14100384Speter * the documentation and/or other materials provided with the 15100384Speter * distribution. 16100384Speter * 17100384Speter * 3. All advertising materials mentioning features or use of this 18100384Speter * software must display the following acknowledgment: 19100384Speter * "This product includes software developed by the OpenSSL Project 20100384Speter * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 21100384Speter * 22100384Speter * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23100384Speter * endorse or promote products derived from this software without 24100384Speter * prior written permission. For written permission, please contact 25100384Speter * openssl-core@openssl.org. 26100384Speter * 27118031Sobrien * 5. Products derived from this software may not be called "OpenSSL" 28118031Sobrien * nor may "OpenSSL" appear in their names without prior written 29118031Sobrien * permission of the OpenSSL Project. 30104738Speter * 31191673Sjamie * 6. Redistributions of any form whatsoever must retain the following 32191673Sjamie * acknowledgment: 33104738Speter * "This product includes software developed by the OpenSSL Project 34100384Speter * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 35100384Speter * 36162954Sphk * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37100384Speter * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38100384Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39100384Speter * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40100384Speter * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41185435Sbz * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42100384Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43161343Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44100384Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45100384Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46100384Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47151909Sps * OF THE POSSIBILITY OF SUCH DAMAGE. 48100384Speter * ==================================================================== 49100384Speter * 50100384Speter */ 51100384Speter 52183044Sobrien#include "cryptlib.h" 53100384Speter 54100384Speter#include <openssl/aes.h> 55100384Speter#include "aes_locl.h" 56100384Speter 57100384Speter#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long)) 58146950Spstypedef struct { 59100384Speter unsigned long data[N_WORDS]; 60100384Speter} aes_block_t; 61100384Speter 62100384Speter/* XXX: probably some better way to do this */ 63100384Speter#if defined(__i386__) || defined(__x86_64__) 64100384Speter#define UNALIGNED_MEMOPS_ARE_FAST 1 65150883Sjhb#else 66113859Sjhb#define UNALIGNED_MEMOPS_ARE_FAST 0 67100384Speter#endif 68100384Speter 69100384Speter#if UNALIGNED_MEMOPS_ARE_FAST 70183044Sobrien#define load_block(d, s) (d) = *(const aes_block_t *)(s) 71162551Sdavidxu#define store_block(d, s) *(aes_block_t *)(d) = (s) 72100384Speter#else 73162551Sdavidxu#define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE) 74100384Speter#define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE) 75127140Sjhb#endif 76157285Sps 77174381Sjhb/* N.B. The IV for this mode is _twice_ the block size */ 78174381Sjhb 79157285Spsvoid AES_ige_encrypt(const unsigned char *in, unsigned char *out, 80100384Speter const unsigned long length, const AES_KEY *key, 81191673Sjamie unsigned char *ivec, const int enc) 82191673Sjamie { 83191673Sjamie unsigned long n; 84191673Sjamie unsigned long len; 85100384Speter 86100384Speter OPENSSL_assert(in && out && key && ivec); 87100384Speter OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); 88100384Speter OPENSSL_assert((length%AES_BLOCK_SIZE) == 0); 89100384Speter 90100384Speter len = length / AES_BLOCK_SIZE; 91100384Speter 92100384Speter if (AES_ENCRYPT == enc) 93151582Sps { 94151582Sps if (in != out && 95183188Sobrien (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0)) 96183188Sobrien { 97119333Speter aes_block_t *ivp = (aes_block_t *)ivec; 98119333Speter aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE); 99174380Sjhb 100163018Sdavidxu while (len) 101119333Speter { 102100384Speter aes_block_t *inp = (aes_block_t *)in; 103121719Speter aes_block_t *outp = (aes_block_t *)out; 104121719Speter 105174377Sjhb for(n=0 ; n < N_WORDS; ++n) 106121719Speter outp->data[n] = inp->data[n] ^ ivp->data[n]; 107121719Speter AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key); 108174377Sjhb for(n=0 ; n < N_WORDS; ++n) 109174377Sjhb outp->data[n] ^= iv2p->data[n]; 110174377Sjhb ivp = outp; 111174377Sjhb iv2p = inp; 112174377Sjhb --len; 113174377Sjhb in += AES_BLOCK_SIZE; 114121719Speter out += AES_BLOCK_SIZE; 115174377Sjhb } 116174377Sjhb memcpy(ivec, ivp->data, AES_BLOCK_SIZE); 117174377Sjhb memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); 118100384Speter } 119119333Speter else 120100384Speter { 121127140Sjhb aes_block_t tmp, tmp2; 122127140Sjhb aes_block_t iv; 123136152Sjhb aes_block_t iv2; 124100384Speter 125136152Sjhb load_block(iv, ivec); 126136152Sjhb load_block(iv2, ivec + AES_BLOCK_SIZE); 127136152Sjhb 128136152Sjhb while (len) 129136152Sjhb { 130100384Speter load_block(tmp, in); 131100384Speter for(n=0 ; n < N_WORDS; ++n) 132127140Sjhb tmp2.data[n] = tmp.data[n] ^ iv.data[n]; 133127140Sjhb AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key); 134127140Sjhb for(n=0 ; n < N_WORDS; ++n) 135100384Speter tmp2.data[n] ^= iv2.data[n]; 136100384Speter store_block(out, tmp2); 137100384Speter iv = tmp2; 138100384Speter iv2 = tmp; 139100384Speter --len; 140100384Speter in += AES_BLOCK_SIZE; 141100384Speter out += AES_BLOCK_SIZE; 142100384Speter } 143100384Speter memcpy(ivec, iv.data, AES_BLOCK_SIZE); 144100384Speter memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); 145100384Speter } 146100384Speter } 147100384Speter else 148100384Speter { 149100384Speter if (in != out && 150100384Speter (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0)) 151127140Sjhb { 152100384Speter aes_block_t *ivp = (aes_block_t *)ivec; 153100384Speter aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE); 154100384Speter 155100384Speter while (len) 156128597Smarcel { 157174526Sjhb aes_block_t tmp; 158100384Speter aes_block_t *inp = (aes_block_t *)in; 159100384Speter aes_block_t *outp = (aes_block_t *)out; 160172003Sjhb 161174424Sscottl for(n=0 ; n < N_WORDS; ++n) 162156266Sps tmp.data[n] = inp->data[n] ^ iv2p->data[n]; 163100384Speter AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key); 164172003Sjhb for(n=0 ; n < N_WORDS; ++n) 165100384Speter outp->data[n] ^= ivp->data[n]; 166100384Speter ivp = inp; 167100384Speter iv2p = outp; 168172003Sjhb --len; 169174526Sjhb in += AES_BLOCK_SIZE; 170100384Speter out += AES_BLOCK_SIZE; 171100384Speter } 172100384Speter memcpy(ivec, ivp->data, AES_BLOCK_SIZE); 173100384Speter memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); 174174526Sjhb } 175174526Sjhb else 176156266Sps { 177156266Sps aes_block_t tmp, tmp2; 178156266Sps aes_block_t iv; 179156266Sps aes_block_t iv2; 180174526Sjhb 181174526Sjhb load_block(iv, ivec); 182156266Sps load_block(iv2, ivec + AES_BLOCK_SIZE); 183156266Sps 184100384Speter while (len) 185128597Smarcel { 186100384Speter load_block(tmp, in); 187128597Smarcel tmp2 = tmp; 188100384Speter for(n=0 ; n < N_WORDS; ++n) 189128260Speter tmp.data[n] ^= iv2.data[n]; 190100384Speter AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key); 191147178Spjd for(n=0 ; n < N_WORDS; ++n) 192147178Spjd tmp.data[n] ^= iv.data[n]; 193147178Spjd store_block(out, tmp); 194100384Speter iv = tmp2; 195100384Speter iv2 = tmp; 196147178Spjd --len; 197147178Spjd in += AES_BLOCK_SIZE; 198147302Spjd out += AES_BLOCK_SIZE; 199147302Spjd } 200100384Speter memcpy(ivec, iv.data, AES_BLOCK_SIZE); 201147178Spjd memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); 202147178Spjd } 203174526Sjhb } 204147178Spjd } 205147178Spjd 206147178Spjd/* 207147178Spjd * Note that its effectively impossible to do biIGE in anything other 208100384Speter * than a single pass, so no provision is made for chaining. 209147178Spjd */ 210100384Speter 211100384Speter/* N.B. The IV for this mode is _four times_ the block size */ 212100384Speter 213128597Smarcelvoid AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, 214100384Speter const unsigned long length, const AES_KEY *key, 215100384Speter const AES_KEY *key2, const unsigned char *ivec, 216119333Speter const int enc) 217119333Speter { 218100384Speter unsigned long n; 219113859Sjhb unsigned long len = length; 220113859Sjhb unsigned char tmp[AES_BLOCK_SIZE]; 221100384Speter unsigned char tmp2[AES_BLOCK_SIZE]; 222100384Speter unsigned char tmp3[AES_BLOCK_SIZE]; 223113859Sjhb unsigned char prev[AES_BLOCK_SIZE]; 224113859Sjhb const unsigned char *iv; 225100384Speter const unsigned char *iv2; 226100384Speter 227113859Sjhb OPENSSL_assert(in && out && key && ivec); 228113859Sjhb OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); 229113859Sjhb OPENSSL_assert((length%AES_BLOCK_SIZE) == 0); 230113859Sjhb 231113859Sjhb if (AES_ENCRYPT == enc) 232113859Sjhb { 233113859Sjhb /* XXX: Do a separate case for when in != out (strictly should 234113859Sjhb check for overlap, too) */ 235113859Sjhb 236113859Sjhb /* First the forward pass */ 237113859Sjhb iv = ivec; 238113859Sjhb iv2 = ivec + AES_BLOCK_SIZE; 239100384Speter while (len >= AES_BLOCK_SIZE) 240100384Speter { 241100384Speter for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 242100384Speter out[n] = in[n] ^ iv[n]; 243142059Sjhb AES_encrypt(out, out, key); 244142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 245142059Sjhb out[n] ^= iv2[n]; 246142059Sjhb iv = out; 247142059Sjhb memcpy(prev, in, AES_BLOCK_SIZE); 248142059Sjhb iv2 = prev; 249142059Sjhb len -= AES_BLOCK_SIZE; 250100384Speter in += AES_BLOCK_SIZE; 251142059Sjhb out += AES_BLOCK_SIZE; 252142059Sjhb } 253142059Sjhb 254100384Speter /* And now backwards */ 255100384Speter iv = ivec + AES_BLOCK_SIZE*2; 256142059Sjhb iv2 = ivec + AES_BLOCK_SIZE*3; 257142059Sjhb len = length; 258142059Sjhb while(len >= AES_BLOCK_SIZE) 259100384Speter { 260142059Sjhb out -= AES_BLOCK_SIZE; 261142059Sjhb /* XXX: reduce copies by alternating between buffers */ 262142059Sjhb memcpy(tmp, out, AES_BLOCK_SIZE); 263142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 264147588Sjhb out[n] ^= iv[n]; 265147588Sjhb /* hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */ 266142059Sjhb AES_encrypt(out, out, key); 267142059Sjhb /* hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */ 268142059Sjhb /* hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */ 269142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 270142059Sjhb out[n] ^= iv2[n]; 271142059Sjhb /* hexdump(stdout,"out", out, AES_BLOCK_SIZE); */ 272142059Sjhb iv = out; 273142059Sjhb memcpy(prev, tmp, AES_BLOCK_SIZE); 274142059Sjhb iv2 = prev; 275177789Skib len -= AES_BLOCK_SIZE; 276177789Skib } 277177789Skib } 278177789Skib else 279177789Skib { 280177789Skib /* First backwards */ 281177789Skib iv = ivec + AES_BLOCK_SIZE*2; 282177789Skib iv2 = ivec + AES_BLOCK_SIZE*3; 283177789Skib in += length; 284142059Sjhb out += length; 285142059Sjhb while (len >= AES_BLOCK_SIZE) 286142059Sjhb { 287142059Sjhb in -= AES_BLOCK_SIZE; 288142059Sjhb out -= AES_BLOCK_SIZE; 289142059Sjhb memcpy(tmp, in, AES_BLOCK_SIZE); 290142059Sjhb memcpy(tmp2, in, AES_BLOCK_SIZE); 291142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 292156440Sups tmp[n] ^= iv2[n]; 293142059Sjhb AES_decrypt(tmp, out, key); 294142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 295142059Sjhb out[n] ^= iv[n]; 296142059Sjhb memcpy(tmp3, tmp2, AES_BLOCK_SIZE); 297142059Sjhb iv = tmp3; 298142059Sjhb iv2 = out; 299156440Sups len -= AES_BLOCK_SIZE; 300156440Sups } 301142059Sjhb 302142059Sjhb /* And now forwards */ 303142059Sjhb iv = ivec; 304142059Sjhb iv2 = ivec + AES_BLOCK_SIZE; 305100384Speter len = length; 306142059Sjhb while (len >= AES_BLOCK_SIZE) 307142059Sjhb { 308142059Sjhb memcpy(tmp, out, AES_BLOCK_SIZE); 309142059Sjhb memcpy(tmp2, out, AES_BLOCK_SIZE); 310142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 311142059Sjhb tmp[n] ^= iv2[n]; 312142059Sjhb AES_decrypt(tmp, out, key); 313142059Sjhb for(n=0 ; n < AES_BLOCK_SIZE ; ++n) 314142059Sjhb out[n] ^= iv[n]; 315100384Speter memcpy(tmp3, tmp2, AES_BLOCK_SIZE); 316100384Speter iv = tmp3; 317156440Sups iv2 = out; 318142059Sjhb len -= AES_BLOCK_SIZE; 319142059Sjhb in += AES_BLOCK_SIZE; 320142059Sjhb out += AES_BLOCK_SIZE; 321142059Sjhb } 322142059Sjhb } 323142059Sjhb } 324142059Sjhb