"Jumbo" update for crypto/modes:
[openssl.git] / crypto / modes / cbc128.c
1 /* ====================================================================
2  * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    openssl-core@openssl.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  */
50
51 #include "modes_lcl.h"
52 #include <string.h>
53
54 #ifndef MODES_DEBUG
55 # ifndef NDEBUG
56 #  define NDEBUG
57 # endif
58 #endif
59 #include <assert.h>
60
61 #ifndef STRICT_ALIGNMENT
62 #  define STRICT_ALIGNMENT 0
63 #endif
64
65 void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
66                         size_t len, const void *key,
67                         unsigned char ivec[16], block128_f block)
68 {
69         size_t n;
70         const unsigned char *iv = ivec;
71
72         assert(in && out && key && ivec);
73
74 #if !defined(OPENSSL_SMALL_FOOTPRINT)
75         if (STRICT_ALIGNMENT &&
76             ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(size_t) != 0) {
77                 while (len>=16) {
78                         for(n=0; n<16; ++n)
79                                 out[n] = in[n] ^ iv[n];
80                         (*block)(out, out, key);
81                         iv = out;
82                         len -= 16;
83                         in  += 16;
84                         out += 16;
85                 }
86         } else {
87                 while (len>=16) {
88                         for(n=0; n<16; n+=sizeof(size_t))
89                                 *(size_t*)(out+n) =
90                                 *(size_t*)(in+n) ^ *(size_t*)(iv+n);
91                         (*block)(out, out, key);
92                         iv = out;
93                         len -= 16;
94                         in  += 16;
95                         out += 16;
96                 }
97         }
98 #endif
99         while (len) {
100                 for(n=0; n<16 && n<len; ++n)
101                         out[n] = in[n] ^ iv[n];
102                 for(; n<16; ++n)
103                         out[n] = iv[n];
104                 (*block)(out, out, key);
105                 iv = out;
106                 if (len<=16) break;
107                 len -= 16;
108                 in  += 16;
109                 out += 16;
110         }
111         memcpy(ivec,iv,16);
112 }
113
114 void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
115                         size_t len, const void *key,
116                         unsigned char ivec[16], block128_f block)
117 {
118         size_t n;
119         union { size_t align; unsigned char c[16]; } tmp;
120
121         assert(in && out && key && ivec);
122
123 #if !defined(OPENSSL_SMALL_FOOTPRINT)
124         if (in != out) {
125                 const unsigned char *iv = ivec;
126
127                 if (STRICT_ALIGNMENT &&
128                     ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(size_t) != 0) {
129                         while (len>=16) {
130                                 (*block)(in, out, key);
131                                 for(n=0; n<16; ++n)
132                                         out[n] ^= iv[n];
133                                 iv = in;
134                                 len -= 16;
135                                 in  += 16;
136                                 out += 16;
137                         }
138                 }
139                 else {
140                         while (len>=16) {
141                                 (*block)(in, out, key);
142                                 for(n=0; n<16; n+=sizeof(size_t))
143                                         *(size_t *)(out+n) ^= *(size_t *)(iv+n);
144                                 iv = in;
145                                 len -= 16;
146                                 in  += 16;
147                                 out += 16;
148                         }
149                 }
150                 memcpy(ivec,iv,16);
151         } else {
152                 if (STRICT_ALIGNMENT &&
153                     ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(size_t) != 0) {
154                         unsigned char c;
155                         while (len>=16) {
156                                 (*block)(in, tmp.c, key);
157                                 for(n=0; n<16; ++n) {
158                                         c = in[n];
159                                         out[n] = tmp.c[n] ^ ivec[n];
160                                         ivec[n] = c;
161                                 }
162                                 len -= 16;
163                                 in  += 16;
164                                 out += 16;
165                         }
166                 }
167                 else {
168                         size_t c;
169                         while (len>=16) {
170                                 (*block)(in, tmp.c, key);
171                                 for(n=0; n<16; n+=sizeof(size_t)) {
172                                         c = *(size_t *)(in+n);
173                                         *(size_t *)(out+n) =
174                                         *(size_t *)(tmp.c+n) ^ *(size_t *)(ivec+n);
175                                         *(size_t *)(ivec+n) = c;
176                                 }
177                                 len -= 16;
178                                 in  += 16;
179                                 out += 16;
180                         }
181                 }
182         }
183 #endif
184         while (len) {
185                 unsigned char c;
186                 (*block)(in, tmp.c, key);
187                 for(n=0; n<16 && n<len; ++n) {
188                         c = in[n];
189                         out[n] = tmp.c[n] ^ ivec[n];
190                         ivec[n] = c;
191                 }
192                 if (len<=16) {
193                         for (; n<16; ++n)
194                                 ivec[n] = in[n];
195                         break;
196                 }
197                 len -= 16;
198                 in  += 16;
199                 out += 16;
200         }
201 }