1 /*
2 * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <string.h>
11 #include <openssl/crypto.h>
12 #include "crypto/modes.h"
13
14 #if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC)
15 # define STRICT_ALIGNMENT 0
16 #endif
17
18 #if defined(__GNUC__) && !STRICT_ALIGNMENT
19 typedef size_t size_t_aX __attribute((__aligned__(1)));
20 #else
21 typedef size_t size_t_aX;
22 #endif
23
CRYPTO_cbc128_encrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)24 void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
25 size_t len, const void *key,
26 unsigned char ivec[16], block128_f block)
27 {
28 size_t n;
29 const unsigned char *iv = ivec;
30
31 if (len == 0)
32 return;
33
34 #if !defined(OPENSSL_SMALL_FOOTPRINT)
35 if (STRICT_ALIGNMENT &&
36 ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
37 while (len >= 16) {
38 for (n = 0; n < 16; ++n)
39 out[n] = in[n] ^ iv[n];
40 (*block) (out, out, key);
41 iv = out;
42 len -= 16;
43 in += 16;
44 out += 16;
45 }
46 } else {
47 while (len >= 16) {
48 for (n = 0; n < 16; n += sizeof(size_t))
49 *(size_t_aX *)(out + n) =
50 *(size_t_aX *)(in + n) ^ *(size_t_aX *)(iv + n);
51 (*block) (out, out, key);
52 iv = out;
53 len -= 16;
54 in += 16;
55 out += 16;
56 }
57 }
58 #endif
59 while (len) {
60 for (n = 0; n < 16 && n < len; ++n)
61 out[n] = in[n] ^ iv[n];
62 for (; n < 16; ++n)
63 out[n] = iv[n];
64 (*block) (out, out, key);
65 iv = out;
66 if (len <= 16)
67 break;
68 len -= 16;
69 in += 16;
70 out += 16;
71 }
72 if (ivec != iv)
73 memcpy(ivec, iv, 16);
74 }
75
CRYPTO_cbc128_decrypt(const unsigned char * in,unsigned char * out,size_t len,const void * key,unsigned char ivec[16],block128_f block)76 void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
77 size_t len, const void *key,
78 unsigned char ivec[16], block128_f block)
79 {
80 size_t n;
81 union {
82 size_t t[16 / sizeof(size_t)];
83 unsigned char c[16];
84 } tmp;
85
86 if (len == 0)
87 return;
88
89 #if !defined(OPENSSL_SMALL_FOOTPRINT)
90 if (in != out) {
91 const unsigned char *iv = ivec;
92
93 if (STRICT_ALIGNMENT &&
94 ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
95 while (len >= 16) {
96 (*block) (in, out, key);
97 for (n = 0; n < 16; ++n)
98 out[n] ^= iv[n];
99 iv = in;
100 len -= 16;
101 in += 16;
102 out += 16;
103 }
104 } else if (16 % sizeof(size_t) == 0) { /* always true */
105 while (len >= 16) {
106 size_t_aX *out_t = (size_t_aX *)out;
107 size_t_aX *iv_t = (size_t_aX *)iv;
108
109 (*block) (in, out, key);
110 for (n = 0; n < 16 / sizeof(size_t); n++)
111 out_t[n] ^= iv_t[n];
112 iv = in;
113 len -= 16;
114 in += 16;
115 out += 16;
116 }
117 }
118 if (ivec != iv)
119 memcpy(ivec, iv, 16);
120 } else {
121 if (STRICT_ALIGNMENT &&
122 ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
123 unsigned char c;
124 while (len >= 16) {
125 (*block) (in, tmp.c, key);
126 for (n = 0; n < 16; ++n) {
127 c = in[n];
128 out[n] = tmp.c[n] ^ ivec[n];
129 ivec[n] = c;
130 }
131 len -= 16;
132 in += 16;
133 out += 16;
134 }
135 } else if (16 % sizeof(size_t) == 0) { /* always true */
136 while (len >= 16) {
137 size_t c;
138 size_t_aX *out_t = (size_t_aX *)out;
139 size_t_aX *ivec_t = (size_t_aX *)ivec;
140 const size_t_aX *in_t = (const size_t_aX *)in;
141
142 (*block) (in, tmp.c, key);
143 for (n = 0; n < 16 / sizeof(size_t); n++) {
144 c = in_t[n];
145 out_t[n] = tmp.t[n] ^ ivec_t[n];
146 ivec_t[n] = c;
147 }
148 len -= 16;
149 in += 16;
150 out += 16;
151 }
152 }
153 }
154 #endif
155 while (len) {
156 unsigned char c;
157 (*block) (in, tmp.c, key);
158 for (n = 0; n < 16 && n < len; ++n) {
159 c = in[n];
160 out[n] = tmp.c[n] ^ ivec[n];
161 ivec[n] = c;
162 }
163 if (len <= 16) {
164 for (; n < 16; ++n)
165 ivec[n] = in[n];
166 break;
167 }
168 len -= 16;
169 in += 16;
170 out += 16;
171 }
172 }
173