| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | /* * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License").  You may not use * this file except in compliance with the License.  You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */#include <string.h>#include <openssl/crypto.h>#include "crypto/modes.h"#if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC)# define STRICT_ALIGNMENT 0#endif#if defined(__GNUC__) && !STRICT_ALIGNMENTtypedef size_t size_t_aX __attribute((__aligned__(1)));#elsetypedef size_t size_t_aX;#endifvoid CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,                           size_t len, const void *key,                           unsigned char ivec[16], block128_f block){    size_t n;    const unsigned char *iv = ivec;    if (len == 0)        return;#if !defined(OPENSSL_SMALL_FOOTPRINT)    if (STRICT_ALIGNMENT &&        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {        while (len >= 16) {            for (n = 0; n < 16; ++n)                out[n] = in[n] ^ iv[n];            (*block) (out, out, key);            iv = out;            len -= 16;            in += 16;            out += 16;        }    } else {        while (len >= 16) {            for (n = 0; n < 16; n += sizeof(size_t))                *(size_t_aX *)(out + n) =                    *(size_t_aX *)(in + n) ^ *(size_t_aX *)(iv + n);            (*block) (out, out, key);            iv = out;            len -= 16;            in += 16;            out += 16;        }    }#endif    while (len) {        for (n = 0; n < 16 && n < len; ++n)            out[n] = in[n] ^ iv[n];        for (; n < 16; ++n)            out[n] = iv[n];        (*block) (out, out, key);        iv = out;        if (len <= 16)            break;        len -= 16;        in += 16;        out += 16;    }    if (ivec != iv)        memcpy(ivec, iv, 16);}void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,                           size_t len, const void *key,                           unsigned char ivec[16], block128_f block){    size_t n;    union {        size_t t[16 / sizeof(size_t)];        unsigned char c[16];    } tmp;    if (len == 0)        return;#if !defined(OPENSSL_SMALL_FOOTPRINT)    if (in != out) {        const unsigned char *iv = ivec;        if (STRICT_ALIGNMENT &&            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {            while (len >= 16) {                (*block) (in, out, key);                for (n = 0; n < 16; ++n)                    out[n] ^= iv[n];                iv = in;                len -= 16;                in += 16;                out += 16;            }        } else if (16 % sizeof(size_t) == 0) { /* always true */            while (len >= 16) {                size_t_aX *out_t = (size_t_aX *)out;                size_t_aX *iv_t = (size_t_aX *)iv;                (*block) (in, out, key);                for (n = 0; n < 16 / sizeof(size_t); n++)                    out_t[n] ^= iv_t[n];                iv = in;                len -= 16;                in += 16;                out += 16;            }        }        if (ivec != iv)            memcpy(ivec, iv, 16);    } else {        if (STRICT_ALIGNMENT &&            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {            unsigned char c;            while (len >= 16) {                (*block) (in, tmp.c, key);                for (n = 0; n < 16; ++n) {                    c = in[n];                    out[n] = tmp.c[n] ^ ivec[n];                    ivec[n] = c;                }                len -= 16;                in += 16;                out += 16;            }        } else if (16 % sizeof(size_t) == 0) { /* always true */            while (len >= 16) {                size_t c;                size_t_aX *out_t = (size_t_aX *)out;                size_t_aX *ivec_t = (size_t_aX *)ivec;                const size_t_aX *in_t = (const size_t_aX *)in;                (*block) (in, tmp.c, key);                for (n = 0; n < 16 / sizeof(size_t); n++) {                    c = in_t[n];                    out_t[n] = tmp.t[n] ^ ivec_t[n];                    ivec_t[n] = c;                }                len -= 16;                in += 16;                out += 16;            }        }    }#endif    while (len) {        unsigned char c;        (*block) (in, tmp.c, key);        for (n = 0; n < 16 && n < len; ++n) {            c = in[n];            out[n] = tmp.c[n] ^ ivec[n];            ivec[n] = c;        }        if (len <= 16) {            for (; n < 16; ++n)                ivec[n] = in[n];            break;        }        len -= 16;        in += 16;        out += 16;    }}
 |