1/*
2 * Copyright 2008-2016 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
18void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
19 size_t len, const void *key,
20 unsigned char ivec[16], block128_f block)
21{
22 size_t n;
23 const unsigned char *iv = ivec;
24
25 if (len == 0)
26 return;
27
28#if !defined(OPENSSL_SMALL_FOOTPRINT)
29 if (STRICT_ALIGNMENT &&
30 ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
31 while (len >= 16) {
32 for (n = 0; n < 16; ++n)
33 out[n] = in[n] ^ iv[n];
34 (*block) (out, out, key);
35 iv = out;
36 len -= 16;
37 in += 16;
38 out += 16;
39 }
40 } else {
41 while (len >= 16) {
42 for (n = 0; n < 16; n += sizeof(size_t))
43 *(size_t *)(out + n) =
44 *(size_t *)(in + n) ^ *(size_t *)(iv + n);
45 (*block) (out, out, key);
46 iv = out;
47 len -= 16;
48 in += 16;
49 out += 16;
50 }
51 }
52#endif
53 while (len) {
54 for (n = 0; n < 16 && n < len; ++n)
55 out[n] = in[n] ^ iv[n];
56 for (; n < 16; ++n)
57 out[n] = iv[n];
58 (*block) (out, out, key);
59 iv = out;
60 if (len <= 16)
61 break;
62 len -= 16;
63 in += 16;
64 out += 16;
65 }
66 memcpy(ivec, iv, 16);
67}
68
69void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
70 size_t len, const void *key,
71 unsigned char ivec[16], block128_f block)
72{
73 size_t n;
74 union {
75 size_t t[16 / sizeof(size_t)];
76 unsigned char c[16];
77 } tmp;
78
79 if (len == 0)
80 return;
81
82#if !defined(OPENSSL_SMALL_FOOTPRINT)
83 if (in != out) {
84 const unsigned char *iv = ivec;
85
86 if (STRICT_ALIGNMENT &&
87 ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
88 while (len >= 16) {
89 (*block) (in, out, key);
90 for (n = 0; n < 16; ++n)
91 out[n] ^= iv[n];
92 iv = in;
93 len -= 16;
94 in += 16;
95 out += 16;
96 }
97 } else if (16 % sizeof(size_t) == 0) { /* always true */
98 while (len >= 16) {
99 size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
100
101 (*block) (in, out, key);
102 for (n = 0; n < 16 / sizeof(size_t); n++)
103 out_t[n] ^= iv_t[n];
104 iv = in;
105 len -= 16;
106 in += 16;
107 out += 16;
108 }
109 }
110 memcpy(ivec, iv, 16);
111 } else {
112 if (STRICT_ALIGNMENT &&
113 ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
114 unsigned char c;
115 while (len >= 16) {
116 (*block) (in, tmp.c, key);
117 for (n = 0; n < 16; ++n) {
118 c = in[n];
119 out[n] = tmp.c[n] ^ ivec[n];
120 ivec[n] = c;
121 }
122 len -= 16;
123 in += 16;
124 out += 16;
125 }
126 } else if (16 % sizeof(size_t) == 0) { /* always true */
127 while (len >= 16) {
128 size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
129 const size_t *in_t = (const size_t *)in;
130
131 (*block) (in, tmp.c, key);
132 for (n = 0; n < 16 / sizeof(size_t); n++) {
133 c = in_t[n];
134 out_t[n] = tmp.t[n] ^ ivec_t[n];
135 ivec_t[n] = c;
136 }
137 len -= 16;
138 in += 16;
139 out += 16;
140 }
141 }
142 }
143#endif
144 while (len) {
145 unsigned char c;
146 (*block) (in, tmp.c, key);
147 for (n = 0; n < 16 && n < len; ++n) {
148 c = in[n];
149 out[n] = tmp.c[n] ^ ivec[n];
150 ivec[n] = c;
151 }
152 if (len <= 16) {
153 for (; n < 16; ++n)
154 ivec[n] = in[n];
155 break;
156 }
157 len -= 16;
158 in += 16;
159 out += 16;
160 }
161}
162