PKCS#7: avoid NULL pointer dereferences with missing content
[openssl.git] / crypto / modes / ctr128.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.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 typedef unsigned int u32;
62 typedef unsigned char u8;
63
64 #define STRICT_ALIGNMENT
65 #if defined(__i386)     || defined(__i386__)    || \
66     defined(__x86_64)   || defined(__x86_64__)  || \
67     defined(_M_IX86)    || defined(_M_AMD64)    || defined(_M_X64) || \
68     defined(__s390__)   || defined(__s390x__)
69 # undef STRICT_ALIGNMENT
70 #endif
71
72 /*
73  * NOTE: the IV/counter CTR mode is big-endian.  The code itself is
74  * endian-neutral.
75  */
76
77 /* increment counter (128-bit int) by 1 */
78 static void ctr128_inc(unsigned char *counter)
79 {
80     u32 n = 16;
81     u8 c;
82
83     do {
84         --n;
85         c = counter[n];
86         ++c;
87         counter[n] = c;
88         if (c)
89             return;
90     } while (n);
91 }
92
93 #if !defined(OPENSSL_SMALL_FOOTPRINT)
94 static void ctr128_inc_aligned(unsigned char *counter)
95 {
96     size_t *data, c, n;
97     const union {
98         long one;
99         char little;
100     } is_endian = {
101         1
102     };
103
104     if (is_endian.little) {
105         ctr128_inc(counter);
106         return;
107     }
108
109     data = (size_t *)counter;
110     n = 16 / sizeof(size_t);
111     do {
112         --n;
113         c = data[n];
114         ++c;
115         data[n] = c;
116         if (c)
117             return;
118     } while (n);
119 }
120 #endif
121
122 /*
123  * The input encrypted as though 128bit counter mode is being used.  The
124  * extra state information to record how much of the 128bit block we have
125  * used is contained in *num, and the encrypted counter is kept in
126  * ecount_buf.  Both *num and ecount_buf must be initialised with zeros
127  * before the first call to CRYPTO_ctr128_encrypt(). This algorithm assumes
128  * that the counter is in the x lower bits of the IV (ivec), and that the
129  * application has full control over overflow and the rest of the IV.  This
130  * implementation takes NO responsability for checking that the counter
131  * doesn't overflow into the rest of the IV when incremented.
132  */
133 void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out,
134                            size_t len, const void *key,
135                            unsigned char ivec[16],
136                            unsigned char ecount_buf[16], unsigned int *num,
137                            block128_f block)
138 {
139     unsigned int n;
140     size_t l = 0;
141
142     assert(in && out && key && ecount_buf && num);
143     assert(*num < 16);
144
145     n = *num;
146
147 #if !defined(OPENSSL_SMALL_FOOTPRINT)
148     if (16 % sizeof(size_t) == 0) { /* always true actually */
149         do {
150             while (n && len) {
151                 *(out++) = *(in++) ^ ecount_buf[n];
152                 --len;
153                 n = (n + 1) % 16;
154             }
155
156 # if defined(STRICT_ALIGNMENT)
157             if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) !=
158                 0)
159                 break;
160 # endif
161             while (len >= 16) {
162                 (*block) (ivec, ecount_buf, key);
163                 ctr128_inc_aligned(ivec);
164                 for (; n < 16; n += sizeof(size_t))
165                     *(size_t *)(out + n) =
166                         *(size_t *)(in + n) ^ *(size_t *)(ecount_buf + n);
167                 len -= 16;
168                 out += 16;
169                 in += 16;
170                 n = 0;
171             }
172             if (len) {
173                 (*block) (ivec, ecount_buf, key);
174                 ctr128_inc_aligned(ivec);
175                 while (len--) {
176                     out[n] = in[n] ^ ecount_buf[n];
177                     ++n;
178                 }
179             }
180             *num = n;
181             return;
182         } while (0);
183     }
184     /* the rest would be commonly eliminated by x86* compiler */
185 #endif
186     while (l < len) {
187         if (n == 0) {
188             (*block) (ivec, ecount_buf, key);
189             ctr128_inc(ivec);
190         }
191         out[l] = in[l] ^ ecount_buf[n];
192         ++l;
193         n = (n + 1) % 16;
194     }
195
196     *num = n;
197 }