4ce5eb2ae341841a36c9a29dbe11aff262d2c20d
[openssl.git] / crypto / modes / cbc128.c
1 /*
2  * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (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 <openssl/crypto.h>
11 #include "modes_lcl.h"
12 #include <string.h>
13
14 #if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC)
15 # define STRICT_ALIGNMENT 0
16 #endif
17
18 void 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
69 void 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 }