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