154359Sroberto/* 254359Sroberto * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. 354359Sroberto * 4132451Sroberto * Licensed under the Apache License 2.0 (the "License"). You may not use 554359Sroberto * this file except in compliance with the License. You can obtain a copy 682498Sroberto * in the file LICENSE in the source distribution or at 754359Sroberto * https://www.openssl.org/source/license.html 854359Sroberto */ 954359Sroberto 1054359Sroberto#include <string.h> 1154359Sroberto#include <openssl/crypto.h> 1254359Sroberto#include "crypto/modes.h" 1354359Sroberto 1454359Sroberto#if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC) 1554359Sroberto# define STRICT_ALIGNMENT 0 16285612Sdelphij#endif 1782498Sroberto 1882498Sroberto#if defined(__GNUC__) && !STRICT_ALIGNMENT 19132451Srobertotypedef size_t size_t_aX __attribute((__aligned__(1))); 2082498Sroberto#else 21285612Sdelphijtypedef size_t size_t_aX; 2282498Sroberto#endif 23285612Sdelphij 2482498Srobertovoid CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out, 2582498Sroberto size_t len, const void *key, 2654359Sroberto unsigned char ivec[16], block128_f block) 2754359Sroberto{ 2854359Sroberto size_t n; 2954359Sroberto const unsigned char *iv = ivec; 3054359Sroberto 3154359Sroberto if (len == 0) 3254359Sroberto return; 3354359Sroberto 3454359Sroberto#if !defined(OPENSSL_SMALL_FOOTPRINT) 3554359Sroberto if (STRICT_ALIGNMENT && 3654359Sroberto ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { 3754359Sroberto while (len >= 16) { 3854359Sroberto for (n = 0; n < 16; ++n) 39132451Sroberto out[n] = in[n] ^ iv[n]; 40132451Sroberto (*block) (out, out, key); 41132451Sroberto iv = out; 42132451Sroberto len -= 16; 43132451Sroberto in += 16; 44132451Sroberto out += 16; 4554359Sroberto } 46132451Sroberto } else { 47132451Sroberto while (len >= 16) { 4854359Sroberto for (n = 0; n < 16; n += sizeof(size_t)) 4954359Sroberto *(size_t_aX *)(out + n) = 5054359Sroberto *(size_t_aX *)(in + n) ^ *(size_t_aX *)(iv + n); 51132451Sroberto (*block) (out, out, key); 52132451Sroberto iv = out; 53285612Sdelphij len -= 16; 54285612Sdelphij in += 16; 5554359Sroberto out += 16; 5654359Sroberto } 5754359Sroberto } 5854359Sroberto#endif 5954359Sroberto while (len) { 60285612Sdelphij for (n = 0; n < 16 && n < len; ++n) 61285612Sdelphij out[n] = in[n] ^ iv[n]; 6254359Sroberto for (; n < 16; ++n) 6354359Sroberto out[n] = iv[n]; 64285612Sdelphij (*block) (out, out, key); 65285612Sdelphij iv = out; 66285612Sdelphij if (len <= 16) 67285612Sdelphij break; 68285612Sdelphij len -= 16; 69285612Sdelphij in += 16; 70285612Sdelphij out += 16; 71285612Sdelphij } 72285612Sdelphij if (ivec != iv) 73285612Sdelphij memcpy(ivec, iv, 16); 74285612Sdelphij} 75285612Sdelphij 76285612Sdelphijvoid CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out, 77285612Sdelphij size_t len, const void *key, 78285612Sdelphij unsigned char ivec[16], block128_f block) 79285612Sdelphij{ 80285612Sdelphij size_t n; 81285612Sdelphij union { 82285612Sdelphij size_t t[16 / sizeof(size_t)]; 83285612Sdelphij unsigned char c[16]; 84294569Sdelphij } tmp; 85294569Sdelphij 86285612Sdelphij if (len == 0) 87285612Sdelphij return; 88285612Sdelphij 89285612Sdelphij#if !defined(OPENSSL_SMALL_FOOTPRINT) 90285612Sdelphij if (in != out) { 91285612Sdelphij const unsigned char *iv = ivec; 92285612Sdelphij 93285612Sdelphij if (STRICT_ALIGNMENT && 94285612Sdelphij ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { 95285612Sdelphij while (len >= 16) { 96285612Sdelphij (*block) (in, out, key); 97285612Sdelphij for (n = 0; n < 16; ++n) 98285612Sdelphij out[n] ^= iv[n]; 99285612Sdelphij iv = in; 100285612Sdelphij len -= 16; 101285612Sdelphij in += 16; 102285612Sdelphij out += 16; 103285612Sdelphij } 104285612Sdelphij } else if (16 % sizeof(size_t) == 0) { /* always true */ 105285612Sdelphij while (len >= 16) { 106285612Sdelphij size_t_aX *out_t = (size_t_aX *)out; 107285612Sdelphij size_t_aX *iv_t = (size_t_aX *)iv; 10854359Sroberto 109285612Sdelphij (*block) (in, out, key); 11054359Sroberto for (n = 0; n < 16 / sizeof(size_t); n++) 11154359Sroberto out_t[n] ^= iv_t[n]; 112285612Sdelphij iv = in; 113285612Sdelphij len -= 16; 11454359Sroberto in += 16; 11554359Sroberto out += 16; 116285612Sdelphij } 11754359Sroberto } 11854359Sroberto if (ivec != iv) 11954359Sroberto memcpy(ivec, iv, 16); 12054359Sroberto } else { 12154359Sroberto if (STRICT_ALIGNMENT && 122285612Sdelphij ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { 123285612Sdelphij unsigned char c; 124285612Sdelphij while (len >= 16) { 125132451Sroberto (*block) (in, tmp.c, key); 126132451Sroberto for (n = 0; n < 16; ++n) { 127132451Sroberto c = in[n]; 128132451Sroberto out[n] = tmp.c[n] ^ ivec[n]; 129132451Sroberto ivec[n] = c; 130132451Sroberto } 131132451Sroberto len -= 16; 132132451Sroberto in += 16; 133132451Sroberto out += 16; 134132451Sroberto } 135132451Sroberto } else if (16 % sizeof(size_t) == 0) { /* always true */ 136132451Sroberto while (len >= 16) { 137132451Sroberto size_t c; 138132451Sroberto size_t_aX *out_t = (size_t_aX *)out; 139132451Sroberto size_t_aX *ivec_t = (size_t_aX *)ivec; 140132451Sroberto const size_t_aX *in_t = (const size_t_aX *)in; 141132451Sroberto 142132451Sroberto (*block) (in, tmp.c, key); 143132451Sroberto for (n = 0; n < 16 / sizeof(size_t); n++) { 144132451Sroberto c = in_t[n]; 145132451Sroberto out_t[n] = tmp.t[n] ^ ivec_t[n]; 146132451Sroberto ivec_t[n] = c; 147132451Sroberto } 148132451Sroberto len -= 16; 149132451Sroberto in += 16; 150285612Sdelphij out += 16; 151285612Sdelphij } 152132451Sroberto } 153132451Sroberto } 154132451Sroberto#endif 155132451Sroberto while (len) { 156132451Sroberto unsigned char c; 157132451Sroberto (*block) (in, tmp.c, key); 158132451Sroberto for (n = 0; n < 16 && n < len; ++n) { 159132451Sroberto c = in[n]; 160132451Sroberto out[n] = tmp.c[n] ^ ivec[n]; 161132451Sroberto ivec[n] = c; 162132451Sroberto } 163132451Sroberto if (len <= 16) { 164132451Sroberto for (; n < 16; ++n) 165132451Sroberto ivec[n] = in[n]; 166132451Sroberto break; 167132451Sroberto } 168132451Sroberto len -= 16; 16954359Sroberto in += 16; 170132451Sroberto out += 16; 17154359Sroberto } 17254359Sroberto} 173132451Sroberto