1 /* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */
   2 /* ====================================================================
   3  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  * 1. Redistributions of source code must retain the above copyright
  10  *    notice, this list of conditions and the following disclaimer.
  11  *
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in
  14  *    the documentation and/or other materials provided with the
  15  *    distribution.
  16  *
  17  * 3. All advertising materials mentioning features or use of this
  18  *    software must display the following acknowledgment:
  19  *    "This product includes software developed by the OpenSSL Project
  20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
  21  *
  22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  23  *    endorse or promote products derived from this software without
  24  *    prior written permission. For written permission, please contact
  25  *    openssl-core@openssl.org.
  26  *
  27  * 5. Products derived from this software may not be called "OpenSSL"
  28  *    nor may "OpenSSL" appear in their names without prior written
  29  *    permission of the OpenSSL Project.
  30  *
  31  * 6. Redistributions of any form whatsoever must retain the following
  32  *    acknowledgment:
  33  *    "This product includes software developed by the OpenSSL Project
  34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
  35  *
  36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
  40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  47  * OF THE POSSIBILITY OF SUCH DAMAGE.
  48  * ====================================================================
  49  *
  50  */
  51 
  52 #include "cryptlib.h"
  53 
  54 #include <openssl/aes.h>
  55 #include "aes_locl.h"
  56 
  57 #define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
  58 typedef struct {
  59         unsigned long data[N_WORDS];
  60 } aes_block_t;
  61 
  62 /* XXX: probably some better way to do this */
  63 #if defined(__i386__) || defined(__x86_64__)
  64 #define UNALIGNED_MEMOPS_ARE_FAST 1
  65 #else
  66 #define UNALIGNED_MEMOPS_ARE_FAST 0
  67 #endif
  68 
  69 #if UNALIGNED_MEMOPS_ARE_FAST
  70 #define load_block(d, s)        (d) = *(const aes_block_t *)(s)
  71 #define store_block(d, s)       *(aes_block_t *)(d) = (s)
  72 #else
  73 #define load_block(d, s)        memcpy((d).data, (s), AES_BLOCK_SIZE)
  74 #define store_block(d, s)       memcpy((d), (s).data, AES_BLOCK_SIZE)
  75 #endif
  76 
  77 /* N.B. The IV for this mode is _twice_ the block size */
  78 
  79 void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
  80                                          size_t length, const AES_KEY *key,
  81                                          unsigned char *ivec, const int enc)
  82         {
  83         size_t n;
  84         size_t len = length;
  85 
  86         OPENSSL_assert(in && out && key && ivec);
  87         OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
  88         OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
  89 
  90         len = length / AES_BLOCK_SIZE;
  91 
  92         if (AES_ENCRYPT == enc)
  93                 {
  94                 if (in != out &&
  95                     (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
  96                         {
  97                         aes_block_t *ivp = (aes_block_t *)ivec;
  98                         aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
  99 
 100                         while (len)
 101                                 {
 102                                 aes_block_t *inp = (aes_block_t *)in;
 103                                 aes_block_t *outp = (aes_block_t *)out;
 104 
 105                                 for(n=0 ; n < N_WORDS; ++n)
 106                                         outp->data[n] = inp->data[n] ^ ivp->data[n];
 107                                 AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key);
 108                                 for(n=0 ; n < N_WORDS; ++n)
 109                                         outp->data[n] ^= iv2p->data[n];
 110                                 ivp = outp;
 111                                 iv2p = inp;
 112                                 --len;
 113                                 in += AES_BLOCK_SIZE;
 114                                 out += AES_BLOCK_SIZE;
 115                                 }
 116                         memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
 117                         memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
 118                         }
 119                 else
 120                         {
 121                         aes_block_t tmp, tmp2;
 122                         aes_block_t iv;
 123                         aes_block_t iv2;
 124 
 125                         load_block(iv, ivec);
 126                         load_block(iv2, ivec + AES_BLOCK_SIZE);
 127 
 128                         while (len)
 129                                 {
 130                                 load_block(tmp, in);
 131                                 for(n=0 ; n < N_WORDS; ++n)
 132                                         tmp2.data[n] = tmp.data[n] ^ iv.data[n];
 133                                 AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key);
 134                                 for(n=0 ; n < N_WORDS; ++n)
 135                                         tmp2.data[n] ^= iv2.data[n];
 136                                 store_block(out, tmp2);
 137                                 iv = tmp2;
 138                                 iv2 = tmp;
 139                                 --len;
 140                                 in += AES_BLOCK_SIZE;
 141                                 out += AES_BLOCK_SIZE;
 142                                 }
 143                         memcpy(ivec, iv.data, AES_BLOCK_SIZE);
 144                         memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
 145                         }
 146                 }
 147         else
 148                 {
 149                 if (in != out &&
 150                     (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
 151                         {
 152                         aes_block_t *ivp = (aes_block_t *)ivec;
 153                         aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
 154 
 155                         while (len)
 156                                 {
 157                                 aes_block_t tmp;
 158                                 aes_block_t *inp = (aes_block_t *)in;
 159                                 aes_block_t *outp = (aes_block_t *)out;
 160 
 161                                 for(n=0 ; n < N_WORDS; ++n)
 162                                         tmp.data[n] = inp->data[n] ^ iv2p->data[n];
 163                                 AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key);
 164                                 for(n=0 ; n < N_WORDS; ++n)
 165                                         outp->data[n] ^= ivp->data[n];
 166                                 ivp = inp;
 167                                 iv2p = outp;
 168                                 --len;
 169                                 in += AES_BLOCK_SIZE;
 170                                 out += AES_BLOCK_SIZE;
 171                                 }
 172                         memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
 173                         memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
 174                         }
 175                 else
 176                         {
 177                         aes_block_t tmp, tmp2;
 178                         aes_block_t iv;
 179                         aes_block_t iv2;
 180 
 181                         load_block(iv, ivec);
 182                         load_block(iv2, ivec + AES_BLOCK_SIZE);
 183 
 184                         while (len)
 185                                 {
 186                                 load_block(tmp, in);
 187                                 tmp2 = tmp;
 188                                 for(n=0 ; n < N_WORDS; ++n)
 189                                         tmp.data[n] ^= iv2.data[n];
 190                                 AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key);
 191                                 for(n=0 ; n < N_WORDS; ++n)
 192                                         tmp.data[n] ^= iv.data[n];
 193                                 store_block(out, tmp);
 194                                 iv = tmp2;
 195                                 iv2 = tmp;
 196                                 --len;
 197                                 in += AES_BLOCK_SIZE;
 198                                 out += AES_BLOCK_SIZE;
 199                                 }
 200                         memcpy(ivec, iv.data, AES_BLOCK_SIZE);
 201                         memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
 202                         }
 203                 }
 204         }
 205 
 206 /*
 207  * Note that its effectively impossible to do biIGE in anything other
 208  * than a single pass, so no provision is made for chaining.
 209  */
 210 
 211 /* N.B. The IV for this mode is _four times_ the block size */
 212 
 213 void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
 214                                                 size_t length, const AES_KEY *key,
 215                                                 const AES_KEY *key2, const unsigned char *ivec,
 216                                                 const int enc)
 217         {
 218         size_t n;
 219         size_t len = length;
 220         unsigned char tmp[AES_BLOCK_SIZE];
 221         unsigned char tmp2[AES_BLOCK_SIZE];
 222         unsigned char tmp3[AES_BLOCK_SIZE];
 223         unsigned char prev[AES_BLOCK_SIZE];
 224         const unsigned char *iv;
 225         const unsigned char *iv2;
 226 
 227         OPENSSL_assert(in && out && key && ivec);
 228         OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
 229         OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
 230 
 231         if (AES_ENCRYPT == enc)
 232                 {
 233                 /* XXX: Do a separate case for when in != out (strictly should
 234                    check for overlap, too) */
 235 
 236                 /* First the forward pass */
 237                 iv = ivec;
 238                 iv2 = ivec + AES_BLOCK_SIZE;
 239                 while (len >= AES_BLOCK_SIZE)
 240                         {
 241                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 242                                 out[n] = in[n] ^ iv[n];
 243                         AES_encrypt(out, out, key);
 244                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 245                                 out[n] ^= iv2[n];
 246                         iv = out;
 247                         memcpy(prev, in, AES_BLOCK_SIZE);
 248                         iv2 = prev;
 249                         len -= AES_BLOCK_SIZE;
 250                         in += AES_BLOCK_SIZE;
 251                         out += AES_BLOCK_SIZE;
 252                         }
 253 
 254                 /* And now backwards */
 255                 iv = ivec + AES_BLOCK_SIZE*2;
 256                 iv2 = ivec + AES_BLOCK_SIZE*3;
 257                 len = length;
 258                 while(len >= AES_BLOCK_SIZE)
 259                         {
 260                         out -= AES_BLOCK_SIZE;
 261                         /* XXX: reduce copies by alternating between buffers */
 262                         memcpy(tmp, out, AES_BLOCK_SIZE);
 263                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 264                                 out[n] ^= iv[n];
 265                         /*                      hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */
 266                         AES_encrypt(out, out, key);
 267                         /*                      hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */
 268                         /*                      hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */
 269                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 270                                 out[n] ^= iv2[n];
 271                         /*                      hexdump(stdout,"out", out, AES_BLOCK_SIZE); */
 272                         iv = out;
 273                         memcpy(prev, tmp, AES_BLOCK_SIZE);
 274                         iv2 = prev;
 275                         len -= AES_BLOCK_SIZE;
 276                         }
 277                 }
 278         else
 279                 {
 280                 /* First backwards */
 281                 iv = ivec + AES_BLOCK_SIZE*2;
 282                 iv2 = ivec + AES_BLOCK_SIZE*3;
 283                 in += length;
 284                 out += length;
 285                 while (len >= AES_BLOCK_SIZE)
 286                         {
 287                         in -= AES_BLOCK_SIZE;
 288                         out -= AES_BLOCK_SIZE;
 289                         memcpy(tmp, in, AES_BLOCK_SIZE);
 290                         memcpy(tmp2, in, AES_BLOCK_SIZE);
 291                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 292                                 tmp[n] ^= iv2[n];
 293                         AES_decrypt(tmp, out, key);
 294                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 295                                 out[n] ^= iv[n];
 296                         memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
 297                         iv = tmp3;
 298                         iv2 = out;
 299                         len -= AES_BLOCK_SIZE;
 300                         }
 301 
 302                 /* And now forwards */
 303                 iv = ivec;
 304                 iv2 = ivec + AES_BLOCK_SIZE;
 305                 len = length;
 306                 while (len >= AES_BLOCK_SIZE)
 307                         {
 308                         memcpy(tmp, out, AES_BLOCK_SIZE);
 309                         memcpy(tmp2, out, AES_BLOCK_SIZE);
 310                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 311                                 tmp[n] ^= iv2[n];
 312                         AES_decrypt(tmp, out, key);
 313                         for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
 314                                 out[n] ^= iv[n];
 315                         memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
 316                         iv = tmp3;
 317                         iv2 = out;
 318                         len -= AES_BLOCK_SIZE;
 319                         in += AES_BLOCK_SIZE;
 320                         out += AES_BLOCK_SIZE;
 321                         }
 322                 }
 323         }