1295016Sjkim/* crypto/aes/aes_ige.c */ 2162911Ssimon/* ==================================================================== 3162911Ssimon * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 4162911Ssimon * 5162911Ssimon * Redistribution and use in source and binary forms, with or without 6162911Ssimon * modification, are permitted provided that the following conditions 7162911Ssimon * are met: 8162911Ssimon * 9162911Ssimon * 1. Redistributions of source code must retain the above copyright 10280304Sjkim * notice, this list of conditions and the following disclaimer. 11162911Ssimon * 12162911Ssimon * 2. Redistributions in binary form must reproduce the above copyright 13162911Ssimon * notice, this list of conditions and the following disclaimer in 14162911Ssimon * the documentation and/or other materials provided with the 15162911Ssimon * distribution. 16162911Ssimon * 17162911Ssimon * 3. All advertising materials mentioning features or use of this 18162911Ssimon * software must display the following acknowledgment: 19162911Ssimon * "This product includes software developed by the OpenSSL Project 20162911Ssimon * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 21162911Ssimon * 22162911Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23162911Ssimon * endorse or promote products derived from this software without 24162911Ssimon * prior written permission. For written permission, please contact 25162911Ssimon * openssl-core@openssl.org. 26162911Ssimon * 27162911Ssimon * 5. Products derived from this software may not be called "OpenSSL" 28162911Ssimon * nor may "OpenSSL" appear in their names without prior written 29162911Ssimon * permission of the OpenSSL Project. 30162911Ssimon * 31162911Ssimon * 6. Redistributions of any form whatsoever must retain the following 32162911Ssimon * acknowledgment: 33162911Ssimon * "This product includes software developed by the OpenSSL Project 34162911Ssimon * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 35162911Ssimon * 36162911Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37162911Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38162911Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39162911Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40162911Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41162911Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42162911Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43162911Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44162911Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45162911Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46162911Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47162911Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 48162911Ssimon * ==================================================================== 49162911Ssimon * 50162911Ssimon */ 51162911Ssimon 52162911Ssimon#include "cryptlib.h" 53162911Ssimon 54162911Ssimon#include <openssl/aes.h> 55162911Ssimon#include "aes_locl.h" 56162911Ssimon 57194206Ssimon#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long)) 58194206Ssimontypedef struct { 59280304Sjkim unsigned long data[N_WORDS]; 60194206Ssimon} aes_block_t; 61162911Ssimon 62194206Ssimon/* XXX: probably some better way to do this */ 63194206Ssimon#if defined(__i386__) || defined(__x86_64__) 64280304Sjkim# define UNALIGNED_MEMOPS_ARE_FAST 1 65194206Ssimon#else 66280304Sjkim# define UNALIGNED_MEMOPS_ARE_FAST 0 67194206Ssimon#endif 68162911Ssimon 69194206Ssimon#if UNALIGNED_MEMOPS_ARE_FAST 70280304Sjkim# define load_block(d, s) (d) = *(const aes_block_t *)(s) 71280304Sjkim# define store_block(d, s) *(aes_block_t *)(d) = (s) 72194206Ssimon#else 73280304Sjkim# define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE) 74280304Sjkim# define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE) 75194206Ssimon#endif 76194206Ssimon 77162911Ssimon/* N.B. The IV for this mode is _twice_ the block size */ 78162911Ssimon 79162911Ssimonvoid AES_ige_encrypt(const unsigned char *in, unsigned char *out, 80280304Sjkim size_t length, const AES_KEY *key, 81280304Sjkim unsigned char *ivec, const int enc) 82280304Sjkim{ 83280304Sjkim size_t n; 84280304Sjkim size_t len = length; 85162911Ssimon 86280304Sjkim OPENSSL_assert(in && out && key && ivec); 87280304Sjkim OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); 88280304Sjkim OPENSSL_assert((length % AES_BLOCK_SIZE) == 0); 89162911Ssimon 90280304Sjkim len = length / AES_BLOCK_SIZE; 91194206Ssimon 92280304Sjkim if (AES_ENCRYPT == enc) { 93280304Sjkim if (in != out && 94280304Sjkim (UNALIGNED_MEMOPS_ARE_FAST 95280304Sjkim || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) == 96280304Sjkim 0)) { 97280304Sjkim aes_block_t *ivp = (aes_block_t *) ivec; 98280304Sjkim aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE); 99194206Ssimon 100280304Sjkim while (len) { 101280304Sjkim aes_block_t *inp = (aes_block_t *) in; 102280304Sjkim aes_block_t *outp = (aes_block_t *) out; 103194206Ssimon 104280304Sjkim for (n = 0; n < N_WORDS; ++n) 105280304Sjkim outp->data[n] = inp->data[n] ^ ivp->data[n]; 106280304Sjkim AES_encrypt((unsigned char *)outp->data, 107280304Sjkim (unsigned char *)outp->data, key); 108280304Sjkim for (n = 0; n < N_WORDS; ++n) 109280304Sjkim outp->data[n] ^= iv2p->data[n]; 110280304Sjkim ivp = outp; 111280304Sjkim iv2p = inp; 112280304Sjkim --len; 113280304Sjkim in += AES_BLOCK_SIZE; 114280304Sjkim out += AES_BLOCK_SIZE; 115280304Sjkim } 116280304Sjkim memcpy(ivec, ivp->data, AES_BLOCK_SIZE); 117280304Sjkim memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); 118280304Sjkim } else { 119280304Sjkim aes_block_t tmp, tmp2; 120280304Sjkim aes_block_t iv; 121280304Sjkim aes_block_t iv2; 122194206Ssimon 123280304Sjkim load_block(iv, ivec); 124280304Sjkim load_block(iv2, ivec + AES_BLOCK_SIZE); 125194206Ssimon 126280304Sjkim while (len) { 127280304Sjkim load_block(tmp, in); 128280304Sjkim for (n = 0; n < N_WORDS; ++n) 129280304Sjkim tmp2.data[n] = tmp.data[n] ^ iv.data[n]; 130280304Sjkim AES_encrypt((unsigned char *)tmp2.data, 131280304Sjkim (unsigned char *)tmp2.data, key); 132280304Sjkim for (n = 0; n < N_WORDS; ++n) 133280304Sjkim tmp2.data[n] ^= iv2.data[n]; 134280304Sjkim store_block(out, tmp2); 135280304Sjkim iv = tmp2; 136280304Sjkim iv2 = tmp; 137280304Sjkim --len; 138280304Sjkim in += AES_BLOCK_SIZE; 139280304Sjkim out += AES_BLOCK_SIZE; 140280304Sjkim } 141280304Sjkim memcpy(ivec, iv.data, AES_BLOCK_SIZE); 142280304Sjkim memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); 143280304Sjkim } 144280304Sjkim } else { 145280304Sjkim if (in != out && 146280304Sjkim (UNALIGNED_MEMOPS_ARE_FAST 147280304Sjkim || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) == 148280304Sjkim 0)) { 149280304Sjkim aes_block_t *ivp = (aes_block_t *) ivec; 150280304Sjkim aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE); 151194206Ssimon 152280304Sjkim while (len) { 153280304Sjkim aes_block_t tmp; 154280304Sjkim aes_block_t *inp = (aes_block_t *) in; 155280304Sjkim aes_block_t *outp = (aes_block_t *) out; 156194206Ssimon 157280304Sjkim for (n = 0; n < N_WORDS; ++n) 158280304Sjkim tmp.data[n] = inp->data[n] ^ iv2p->data[n]; 159280304Sjkim AES_decrypt((unsigned char *)tmp.data, 160280304Sjkim (unsigned char *)outp->data, key); 161280304Sjkim for (n = 0; n < N_WORDS; ++n) 162280304Sjkim outp->data[n] ^= ivp->data[n]; 163280304Sjkim ivp = inp; 164280304Sjkim iv2p = outp; 165280304Sjkim --len; 166280304Sjkim in += AES_BLOCK_SIZE; 167280304Sjkim out += AES_BLOCK_SIZE; 168280304Sjkim } 169280304Sjkim memcpy(ivec, ivp->data, AES_BLOCK_SIZE); 170280304Sjkim memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); 171280304Sjkim } else { 172280304Sjkim aes_block_t tmp, tmp2; 173280304Sjkim aes_block_t iv; 174280304Sjkim aes_block_t iv2; 175194206Ssimon 176280304Sjkim load_block(iv, ivec); 177280304Sjkim load_block(iv2, ivec + AES_BLOCK_SIZE); 178194206Ssimon 179280304Sjkim while (len) { 180280304Sjkim load_block(tmp, in); 181280304Sjkim tmp2 = tmp; 182280304Sjkim for (n = 0; n < N_WORDS; ++n) 183280304Sjkim tmp.data[n] ^= iv2.data[n]; 184280304Sjkim AES_decrypt((unsigned char *)tmp.data, 185280304Sjkim (unsigned char *)tmp.data, key); 186280304Sjkim for (n = 0; n < N_WORDS; ++n) 187280304Sjkim tmp.data[n] ^= iv.data[n]; 188280304Sjkim store_block(out, tmp); 189280304Sjkim iv = tmp2; 190280304Sjkim iv2 = tmp; 191280304Sjkim --len; 192280304Sjkim in += AES_BLOCK_SIZE; 193280304Sjkim out += AES_BLOCK_SIZE; 194280304Sjkim } 195280304Sjkim memcpy(ivec, iv.data, AES_BLOCK_SIZE); 196280304Sjkim memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); 197280304Sjkim } 198280304Sjkim } 199280304Sjkim} 200162911Ssimon 201162911Ssimon/* 202162911Ssimon * Note that its effectively impossible to do biIGE in anything other 203162911Ssimon * than a single pass, so no provision is made for chaining. 204162911Ssimon */ 205162911Ssimon 206162911Ssimon/* N.B. The IV for this mode is _four times_ the block size */ 207162911Ssimon 208162911Ssimonvoid AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, 209280304Sjkim size_t length, const AES_KEY *key, 210280304Sjkim const AES_KEY *key2, const unsigned char *ivec, 211280304Sjkim const int enc) 212280304Sjkim{ 213280304Sjkim size_t n; 214280304Sjkim size_t len = length; 215280304Sjkim unsigned char tmp[AES_BLOCK_SIZE]; 216280304Sjkim unsigned char tmp2[AES_BLOCK_SIZE]; 217280304Sjkim unsigned char tmp3[AES_BLOCK_SIZE]; 218280304Sjkim unsigned char prev[AES_BLOCK_SIZE]; 219280304Sjkim const unsigned char *iv; 220280304Sjkim const unsigned char *iv2; 221162911Ssimon 222280304Sjkim OPENSSL_assert(in && out && key && ivec); 223280304Sjkim OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); 224280304Sjkim OPENSSL_assert((length % AES_BLOCK_SIZE) == 0); 225162911Ssimon 226280304Sjkim if (AES_ENCRYPT == enc) { 227280304Sjkim /* 228280304Sjkim * XXX: Do a separate case for when in != out (strictly should check 229280304Sjkim * for overlap, too) 230280304Sjkim */ 231162911Ssimon 232280304Sjkim /* First the forward pass */ 233280304Sjkim iv = ivec; 234280304Sjkim iv2 = ivec + AES_BLOCK_SIZE; 235280304Sjkim while (len >= AES_BLOCK_SIZE) { 236280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 237280304Sjkim out[n] = in[n] ^ iv[n]; 238280304Sjkim AES_encrypt(out, out, key); 239280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 240280304Sjkim out[n] ^= iv2[n]; 241280304Sjkim iv = out; 242280304Sjkim memcpy(prev, in, AES_BLOCK_SIZE); 243280304Sjkim iv2 = prev; 244280304Sjkim len -= AES_BLOCK_SIZE; 245280304Sjkim in += AES_BLOCK_SIZE; 246280304Sjkim out += AES_BLOCK_SIZE; 247280304Sjkim } 248162911Ssimon 249280304Sjkim /* And now backwards */ 250280304Sjkim iv = ivec + AES_BLOCK_SIZE * 2; 251280304Sjkim iv2 = ivec + AES_BLOCK_SIZE * 3; 252280304Sjkim len = length; 253280304Sjkim while (len >= AES_BLOCK_SIZE) { 254280304Sjkim out -= AES_BLOCK_SIZE; 255280304Sjkim /* 256280304Sjkim * XXX: reduce copies by alternating between buffers 257280304Sjkim */ 258280304Sjkim memcpy(tmp, out, AES_BLOCK_SIZE); 259280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 260280304Sjkim out[n] ^= iv[n]; 261280304Sjkim /* 262280304Sjkim * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); 263280304Sjkim */ 264280304Sjkim AES_encrypt(out, out, key); 265280304Sjkim /* 266280304Sjkim * hexdump(stdout,"enc", out, AES_BLOCK_SIZE); 267280304Sjkim */ 268280304Sjkim /* 269280304Sjkim * hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); 270280304Sjkim */ 271280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 272280304Sjkim out[n] ^= iv2[n]; 273280304Sjkim /* 274280304Sjkim * hexdump(stdout,"out", out, AES_BLOCK_SIZE); 275280304Sjkim */ 276280304Sjkim iv = out; 277280304Sjkim memcpy(prev, tmp, AES_BLOCK_SIZE); 278280304Sjkim iv2 = prev; 279280304Sjkim len -= AES_BLOCK_SIZE; 280280304Sjkim } 281280304Sjkim } else { 282280304Sjkim /* First backwards */ 283280304Sjkim iv = ivec + AES_BLOCK_SIZE * 2; 284280304Sjkim iv2 = ivec + AES_BLOCK_SIZE * 3; 285280304Sjkim in += length; 286280304Sjkim out += length; 287280304Sjkim while (len >= AES_BLOCK_SIZE) { 288280304Sjkim in -= AES_BLOCK_SIZE; 289280304Sjkim out -= AES_BLOCK_SIZE; 290280304Sjkim memcpy(tmp, in, AES_BLOCK_SIZE); 291280304Sjkim memcpy(tmp2, in, AES_BLOCK_SIZE); 292280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 293280304Sjkim tmp[n] ^= iv2[n]; 294280304Sjkim AES_decrypt(tmp, out, key); 295280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 296280304Sjkim out[n] ^= iv[n]; 297280304Sjkim memcpy(tmp3, tmp2, AES_BLOCK_SIZE); 298280304Sjkim iv = tmp3; 299280304Sjkim iv2 = out; 300280304Sjkim len -= AES_BLOCK_SIZE; 301280304Sjkim } 302162911Ssimon 303280304Sjkim /* And now forwards */ 304280304Sjkim iv = ivec; 305280304Sjkim iv2 = ivec + AES_BLOCK_SIZE; 306280304Sjkim len = length; 307280304Sjkim while (len >= AES_BLOCK_SIZE) { 308280304Sjkim memcpy(tmp, out, AES_BLOCK_SIZE); 309280304Sjkim memcpy(tmp2, out, AES_BLOCK_SIZE); 310280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 311280304Sjkim tmp[n] ^= iv2[n]; 312280304Sjkim AES_decrypt(tmp, out, key); 313280304Sjkim for (n = 0; n < AES_BLOCK_SIZE; ++n) 314280304Sjkim out[n] ^= iv[n]; 315280304Sjkim memcpy(tmp3, tmp2, AES_BLOCK_SIZE); 316280304Sjkim iv = tmp3; 317280304Sjkim iv2 = out; 318280304Sjkim len -= AES_BLOCK_SIZE; 319280304Sjkim in += AES_BLOCK_SIZE; 320280304Sjkim out += AES_BLOCK_SIZE; 321280304Sjkim } 322280304Sjkim } 323280304Sjkim} 324