1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci/* 11e1051a39Sopenharmony_ci * AES_encrypt/AES_decrypt are deprecated - but we need to use them to implement 12e1051a39Sopenharmony_ci * these functions 13e1051a39Sopenharmony_ci */ 14e1051a39Sopenharmony_ci#include "internal/deprecated.h" 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci#include <openssl/aes.h> 19e1051a39Sopenharmony_ci#include "aes_local.h" 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_ci/* XXX: probably some better way to do this */ 22e1051a39Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 23e1051a39Sopenharmony_ci# define UNALIGNED_MEMOPS_ARE_FAST 1 24e1051a39Sopenharmony_ci#else 25e1051a39Sopenharmony_ci# define UNALIGNED_MEMOPS_ARE_FAST 0 26e1051a39Sopenharmony_ci#endif 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long)) 29e1051a39Sopenharmony_citypedef struct { 30e1051a39Sopenharmony_ci unsigned long data[N_WORDS]; 31e1051a39Sopenharmony_ci#if defined(__GNUC__) && UNALIGNED_MEMOPS_ARE_FAST 32e1051a39Sopenharmony_ci} aes_block_t __attribute((__aligned__(1))); 33e1051a39Sopenharmony_ci#else 34e1051a39Sopenharmony_ci} aes_block_t; 35e1051a39Sopenharmony_ci#endif 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_ci#if UNALIGNED_MEMOPS_ARE_FAST 38e1051a39Sopenharmony_ci# define load_block(d, s) (d) = *(const aes_block_t *)(s) 39e1051a39Sopenharmony_ci# define store_block(d, s) *(aes_block_t *)(d) = (s) 40e1051a39Sopenharmony_ci#else 41e1051a39Sopenharmony_ci# define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE) 42e1051a39Sopenharmony_ci# define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE) 43e1051a39Sopenharmony_ci#endif 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_ci/* N.B. The IV for this mode is _twice_ the block size */ 46e1051a39Sopenharmony_ci 47e1051a39Sopenharmony_ci/* Use of this function is deprecated. */ 48e1051a39Sopenharmony_civoid AES_ige_encrypt(const unsigned char *in, unsigned char *out, 49e1051a39Sopenharmony_ci size_t length, const AES_KEY *key, 50e1051a39Sopenharmony_ci unsigned char *ivec, const int enc) 51e1051a39Sopenharmony_ci{ 52e1051a39Sopenharmony_ci size_t n; 53e1051a39Sopenharmony_ci size_t len = length / AES_BLOCK_SIZE; 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_ci if (length == 0) 56e1051a39Sopenharmony_ci return; 57e1051a39Sopenharmony_ci 58e1051a39Sopenharmony_ci OPENSSL_assert(in && out && key && ivec); 59e1051a39Sopenharmony_ci OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); 60e1051a39Sopenharmony_ci OPENSSL_assert((length % AES_BLOCK_SIZE) == 0); 61e1051a39Sopenharmony_ci 62e1051a39Sopenharmony_ci if (AES_ENCRYPT == enc) { 63e1051a39Sopenharmony_ci if (in != out && 64e1051a39Sopenharmony_ci (UNALIGNED_MEMOPS_ARE_FAST 65e1051a39Sopenharmony_ci || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) == 66e1051a39Sopenharmony_ci 0)) { 67e1051a39Sopenharmony_ci aes_block_t *ivp = (aes_block_t *) ivec; 68e1051a39Sopenharmony_ci aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE); 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci while (len) { 71e1051a39Sopenharmony_ci aes_block_t *inp = (aes_block_t *) in; 72e1051a39Sopenharmony_ci aes_block_t *outp = (aes_block_t *) out; 73e1051a39Sopenharmony_ci 74e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 75e1051a39Sopenharmony_ci outp->data[n] = inp->data[n] ^ ivp->data[n]; 76e1051a39Sopenharmony_ci AES_encrypt((unsigned char *)outp->data, 77e1051a39Sopenharmony_ci (unsigned char *)outp->data, key); 78e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 79e1051a39Sopenharmony_ci outp->data[n] ^= iv2p->data[n]; 80e1051a39Sopenharmony_ci ivp = outp; 81e1051a39Sopenharmony_ci iv2p = inp; 82e1051a39Sopenharmony_ci --len; 83e1051a39Sopenharmony_ci in += AES_BLOCK_SIZE; 84e1051a39Sopenharmony_ci out += AES_BLOCK_SIZE; 85e1051a39Sopenharmony_ci } 86e1051a39Sopenharmony_ci memcpy(ivec, ivp->data, AES_BLOCK_SIZE); 87e1051a39Sopenharmony_ci memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); 88e1051a39Sopenharmony_ci } else { 89e1051a39Sopenharmony_ci aes_block_t tmp, tmp2; 90e1051a39Sopenharmony_ci aes_block_t iv; 91e1051a39Sopenharmony_ci aes_block_t iv2; 92e1051a39Sopenharmony_ci 93e1051a39Sopenharmony_ci load_block(iv, ivec); 94e1051a39Sopenharmony_ci load_block(iv2, ivec + AES_BLOCK_SIZE); 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ci while (len) { 97e1051a39Sopenharmony_ci load_block(tmp, in); 98e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 99e1051a39Sopenharmony_ci tmp2.data[n] = tmp.data[n] ^ iv.data[n]; 100e1051a39Sopenharmony_ci AES_encrypt((unsigned char *)tmp2.data, 101e1051a39Sopenharmony_ci (unsigned char *)tmp2.data, key); 102e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 103e1051a39Sopenharmony_ci tmp2.data[n] ^= iv2.data[n]; 104e1051a39Sopenharmony_ci store_block(out, tmp2); 105e1051a39Sopenharmony_ci iv = tmp2; 106e1051a39Sopenharmony_ci iv2 = tmp; 107e1051a39Sopenharmony_ci --len; 108e1051a39Sopenharmony_ci in += AES_BLOCK_SIZE; 109e1051a39Sopenharmony_ci out += AES_BLOCK_SIZE; 110e1051a39Sopenharmony_ci } 111e1051a39Sopenharmony_ci memcpy(ivec, iv.data, AES_BLOCK_SIZE); 112e1051a39Sopenharmony_ci memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); 113e1051a39Sopenharmony_ci } 114e1051a39Sopenharmony_ci } else { 115e1051a39Sopenharmony_ci if (in != out && 116e1051a39Sopenharmony_ci (UNALIGNED_MEMOPS_ARE_FAST 117e1051a39Sopenharmony_ci || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) == 118e1051a39Sopenharmony_ci 0)) { 119e1051a39Sopenharmony_ci aes_block_t *ivp = (aes_block_t *) ivec; 120e1051a39Sopenharmony_ci aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE); 121e1051a39Sopenharmony_ci 122e1051a39Sopenharmony_ci while (len) { 123e1051a39Sopenharmony_ci aes_block_t tmp; 124e1051a39Sopenharmony_ci aes_block_t *inp = (aes_block_t *) in; 125e1051a39Sopenharmony_ci aes_block_t *outp = (aes_block_t *) out; 126e1051a39Sopenharmony_ci 127e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 128e1051a39Sopenharmony_ci tmp.data[n] = inp->data[n] ^ iv2p->data[n]; 129e1051a39Sopenharmony_ci AES_decrypt((unsigned char *)tmp.data, 130e1051a39Sopenharmony_ci (unsigned char *)outp->data, key); 131e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 132e1051a39Sopenharmony_ci outp->data[n] ^= ivp->data[n]; 133e1051a39Sopenharmony_ci ivp = inp; 134e1051a39Sopenharmony_ci iv2p = outp; 135e1051a39Sopenharmony_ci --len; 136e1051a39Sopenharmony_ci in += AES_BLOCK_SIZE; 137e1051a39Sopenharmony_ci out += AES_BLOCK_SIZE; 138e1051a39Sopenharmony_ci } 139e1051a39Sopenharmony_ci memcpy(ivec, ivp->data, AES_BLOCK_SIZE); 140e1051a39Sopenharmony_ci memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); 141e1051a39Sopenharmony_ci } else { 142e1051a39Sopenharmony_ci aes_block_t tmp, tmp2; 143e1051a39Sopenharmony_ci aes_block_t iv; 144e1051a39Sopenharmony_ci aes_block_t iv2; 145e1051a39Sopenharmony_ci 146e1051a39Sopenharmony_ci load_block(iv, ivec); 147e1051a39Sopenharmony_ci load_block(iv2, ivec + AES_BLOCK_SIZE); 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci while (len) { 150e1051a39Sopenharmony_ci load_block(tmp, in); 151e1051a39Sopenharmony_ci tmp2 = tmp; 152e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 153e1051a39Sopenharmony_ci tmp.data[n] ^= iv2.data[n]; 154e1051a39Sopenharmony_ci AES_decrypt((unsigned char *)tmp.data, 155e1051a39Sopenharmony_ci (unsigned char *)tmp.data, key); 156e1051a39Sopenharmony_ci for (n = 0; n < N_WORDS; ++n) 157e1051a39Sopenharmony_ci tmp.data[n] ^= iv.data[n]; 158e1051a39Sopenharmony_ci store_block(out, tmp); 159e1051a39Sopenharmony_ci iv = tmp2; 160e1051a39Sopenharmony_ci iv2 = tmp; 161e1051a39Sopenharmony_ci --len; 162e1051a39Sopenharmony_ci in += AES_BLOCK_SIZE; 163e1051a39Sopenharmony_ci out += AES_BLOCK_SIZE; 164e1051a39Sopenharmony_ci } 165e1051a39Sopenharmony_ci memcpy(ivec, iv.data, AES_BLOCK_SIZE); 166e1051a39Sopenharmony_ci memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); 167e1051a39Sopenharmony_ci } 168e1051a39Sopenharmony_ci } 169e1051a39Sopenharmony_ci} 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_ci/* 172e1051a39Sopenharmony_ci * Note that its effectively impossible to do biIGE in anything other 173e1051a39Sopenharmony_ci * than a single pass, so no provision is made for chaining. 174e1051a39Sopenharmony_ci * 175e1051a39Sopenharmony_ci * NB: The implementation of AES_bi_ige_encrypt has a bug. It is supposed to use 176e1051a39Sopenharmony_ci * 2 AES keys, but in fact only one is ever used. This bug has been present 177e1051a39Sopenharmony_ci * since this code was first implemented. It is believed to have minimal 178e1051a39Sopenharmony_ci * security impact in practice and has therefore not been fixed for backwards 179e1051a39Sopenharmony_ci * compatibility reasons. 180e1051a39Sopenharmony_ci * 181e1051a39Sopenharmony_ci * Use of this function is deprecated. 182e1051a39Sopenharmony_ci */ 183e1051a39Sopenharmony_ci 184e1051a39Sopenharmony_ci/* N.B. The IV for this mode is _four times_ the block size */ 185e1051a39Sopenharmony_ci 186e1051a39Sopenharmony_civoid AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, 187e1051a39Sopenharmony_ci size_t length, const AES_KEY *key, 188e1051a39Sopenharmony_ci const AES_KEY *key2, const unsigned char *ivec, 189e1051a39Sopenharmony_ci const int enc) 190e1051a39Sopenharmony_ci{ 191e1051a39Sopenharmony_ci size_t n; 192e1051a39Sopenharmony_ci size_t len = length; 193e1051a39Sopenharmony_ci unsigned char tmp[AES_BLOCK_SIZE]; 194e1051a39Sopenharmony_ci unsigned char tmp2[AES_BLOCK_SIZE]; 195e1051a39Sopenharmony_ci unsigned char tmp3[AES_BLOCK_SIZE]; 196e1051a39Sopenharmony_ci unsigned char prev[AES_BLOCK_SIZE]; 197e1051a39Sopenharmony_ci const unsigned char *iv; 198e1051a39Sopenharmony_ci const unsigned char *iv2; 199e1051a39Sopenharmony_ci 200e1051a39Sopenharmony_ci OPENSSL_assert(in && out && key && ivec); 201e1051a39Sopenharmony_ci OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); 202e1051a39Sopenharmony_ci OPENSSL_assert((length % AES_BLOCK_SIZE) == 0); 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_ci if (AES_ENCRYPT == enc) { 205e1051a39Sopenharmony_ci /* 206e1051a39Sopenharmony_ci * XXX: Do a separate case for when in != out (strictly should check 207e1051a39Sopenharmony_ci * for overlap, too) 208e1051a39Sopenharmony_ci */ 209e1051a39Sopenharmony_ci 210e1051a39Sopenharmony_ci /* First the forward pass */ 211e1051a39Sopenharmony_ci iv = ivec; 212e1051a39Sopenharmony_ci iv2 = ivec + AES_BLOCK_SIZE; 213e1051a39Sopenharmony_ci while (len >= AES_BLOCK_SIZE) { 214e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 215e1051a39Sopenharmony_ci out[n] = in[n] ^ iv[n]; 216e1051a39Sopenharmony_ci AES_encrypt(out, out, key); 217e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 218e1051a39Sopenharmony_ci out[n] ^= iv2[n]; 219e1051a39Sopenharmony_ci iv = out; 220e1051a39Sopenharmony_ci memcpy(prev, in, AES_BLOCK_SIZE); 221e1051a39Sopenharmony_ci iv2 = prev; 222e1051a39Sopenharmony_ci len -= AES_BLOCK_SIZE; 223e1051a39Sopenharmony_ci in += AES_BLOCK_SIZE; 224e1051a39Sopenharmony_ci out += AES_BLOCK_SIZE; 225e1051a39Sopenharmony_ci } 226e1051a39Sopenharmony_ci 227e1051a39Sopenharmony_ci /* And now backwards */ 228e1051a39Sopenharmony_ci iv = ivec + AES_BLOCK_SIZE * 2; 229e1051a39Sopenharmony_ci iv2 = ivec + AES_BLOCK_SIZE * 3; 230e1051a39Sopenharmony_ci len = length; 231e1051a39Sopenharmony_ci while (len >= AES_BLOCK_SIZE) { 232e1051a39Sopenharmony_ci out -= AES_BLOCK_SIZE; 233e1051a39Sopenharmony_ci /* 234e1051a39Sopenharmony_ci * XXX: reduce copies by alternating between buffers 235e1051a39Sopenharmony_ci */ 236e1051a39Sopenharmony_ci memcpy(tmp, out, AES_BLOCK_SIZE); 237e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 238e1051a39Sopenharmony_ci out[n] ^= iv[n]; 239e1051a39Sopenharmony_ci /* 240e1051a39Sopenharmony_ci * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); 241e1051a39Sopenharmony_ci */ 242e1051a39Sopenharmony_ci AES_encrypt(out, out, key); 243e1051a39Sopenharmony_ci /* 244e1051a39Sopenharmony_ci * hexdump(stdout,"enc", out, AES_BLOCK_SIZE); 245e1051a39Sopenharmony_ci */ 246e1051a39Sopenharmony_ci /* 247e1051a39Sopenharmony_ci * hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); 248e1051a39Sopenharmony_ci */ 249e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 250e1051a39Sopenharmony_ci out[n] ^= iv2[n]; 251e1051a39Sopenharmony_ci /* 252e1051a39Sopenharmony_ci * hexdump(stdout,"out", out, AES_BLOCK_SIZE); 253e1051a39Sopenharmony_ci */ 254e1051a39Sopenharmony_ci iv = out; 255e1051a39Sopenharmony_ci memcpy(prev, tmp, AES_BLOCK_SIZE); 256e1051a39Sopenharmony_ci iv2 = prev; 257e1051a39Sopenharmony_ci len -= AES_BLOCK_SIZE; 258e1051a39Sopenharmony_ci } 259e1051a39Sopenharmony_ci } else { 260e1051a39Sopenharmony_ci /* First backwards */ 261e1051a39Sopenharmony_ci iv = ivec + AES_BLOCK_SIZE * 2; 262e1051a39Sopenharmony_ci iv2 = ivec + AES_BLOCK_SIZE * 3; 263e1051a39Sopenharmony_ci in += length; 264e1051a39Sopenharmony_ci out += length; 265e1051a39Sopenharmony_ci while (len >= AES_BLOCK_SIZE) { 266e1051a39Sopenharmony_ci in -= AES_BLOCK_SIZE; 267e1051a39Sopenharmony_ci out -= AES_BLOCK_SIZE; 268e1051a39Sopenharmony_ci memcpy(tmp, in, AES_BLOCK_SIZE); 269e1051a39Sopenharmony_ci memcpy(tmp2, in, AES_BLOCK_SIZE); 270e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 271e1051a39Sopenharmony_ci tmp[n] ^= iv2[n]; 272e1051a39Sopenharmony_ci AES_decrypt(tmp, out, key); 273e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 274e1051a39Sopenharmony_ci out[n] ^= iv[n]; 275e1051a39Sopenharmony_ci memcpy(tmp3, tmp2, AES_BLOCK_SIZE); 276e1051a39Sopenharmony_ci iv = tmp3; 277e1051a39Sopenharmony_ci iv2 = out; 278e1051a39Sopenharmony_ci len -= AES_BLOCK_SIZE; 279e1051a39Sopenharmony_ci } 280e1051a39Sopenharmony_ci 281e1051a39Sopenharmony_ci /* And now forwards */ 282e1051a39Sopenharmony_ci iv = ivec; 283e1051a39Sopenharmony_ci iv2 = ivec + AES_BLOCK_SIZE; 284e1051a39Sopenharmony_ci len = length; 285e1051a39Sopenharmony_ci while (len >= AES_BLOCK_SIZE) { 286e1051a39Sopenharmony_ci memcpy(tmp, out, AES_BLOCK_SIZE); 287e1051a39Sopenharmony_ci memcpy(tmp2, out, AES_BLOCK_SIZE); 288e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 289e1051a39Sopenharmony_ci tmp[n] ^= iv2[n]; 290e1051a39Sopenharmony_ci AES_decrypt(tmp, out, key); 291e1051a39Sopenharmony_ci for (n = 0; n < AES_BLOCK_SIZE; ++n) 292e1051a39Sopenharmony_ci out[n] ^= iv[n]; 293e1051a39Sopenharmony_ci memcpy(tmp3, tmp2, AES_BLOCK_SIZE); 294e1051a39Sopenharmony_ci iv = tmp3; 295e1051a39Sopenharmony_ci iv2 = out; 296e1051a39Sopenharmony_ci len -= AES_BLOCK_SIZE; 297e1051a39Sopenharmony_ci in += AES_BLOCK_SIZE; 298e1051a39Sopenharmony_ci out += AES_BLOCK_SIZE; 299e1051a39Sopenharmony_ci } 300e1051a39Sopenharmony_ci } 301e1051a39Sopenharmony_ci} 302