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 #include <openssl/type_check.h>
50 
51 #include <assert.h>
52 #include <string.h>
53 
54 #include "internal.h"
55 
56 
57 OPENSSL_STATIC_ASSERT(16 % sizeof(size_t) == 0,
58                       "block cannot be divided into size_t");
59 
CRYPTO_cfb128_encrypt(const uint8_t * in,uint8_t * out,size_t len,const AES_KEY * key,uint8_t ivec[16],unsigned * num,int enc,block128_f block)60 void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
61                            const AES_KEY *key, uint8_t ivec[16], unsigned *num,
62                            int enc, block128_f block) {
63   assert(in && out && key && ivec && num);
64 
65   unsigned n = *num;
66 
67   if (enc) {
68     while (n && len) {
69       *(out++) = ivec[n] ^= *(in++);
70       --len;
71       n = (n + 1) % 16;
72     }
73     while (len >= 16) {
74       (*block)(ivec, ivec, key);
75       for (; n < 16; n += sizeof(size_t)) {
76         size_t tmp = load_word_le(ivec + n) ^ load_word_le(in + n);
77         store_word_le(ivec + n, tmp);
78         store_word_le(out + n, tmp);
79       }
80       len -= 16;
81       out += 16;
82       in += 16;
83       n = 0;
84     }
85     if (len) {
86       (*block)(ivec, ivec, key);
87       while (len--) {
88         out[n] = ivec[n] ^= in[n];
89         ++n;
90       }
91     }
92     *num = n;
93     return;
94   } else {
95     while (n && len) {
96       uint8_t c;
97       *(out++) = ivec[n] ^ (c = *(in++));
98       ivec[n] = c;
99       --len;
100       n = (n + 1) % 16;
101     }
102     while (len >= 16) {
103       (*block)(ivec, ivec, key);
104       for (; n < 16; n += sizeof(size_t)) {
105         size_t t = load_word_le(in + n);
106         store_word_le(out + n, load_word_le(ivec + n) ^ t);
107         store_word_le(ivec + n, t);
108       }
109       len -= 16;
110       out += 16;
111       in += 16;
112       n = 0;
113     }
114     if (len) {
115       (*block)(ivec, ivec, key);
116       while (len--) {
117         uint8_t c;
118         out[n] = ivec[n] ^ (c = in[n]);
119         ivec[n] = c;
120         ++n;
121       }
122     }
123     *num = n;
124     return;
125   }
126 }
127 
128 
129 /* This expects a single block of size nbits for both in and out. Note that
130    it corrupts any extra bits in the last byte of out */
cfbr_encrypt_block(const uint8_t * in,uint8_t * out,unsigned nbits,const AES_KEY * key,uint8_t ivec[16],int enc,block128_f block)131 static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits,
132                                const AES_KEY *key, uint8_t ivec[16], int enc,
133                                block128_f block) {
134   int n, rem, num;
135   uint8_t ovec[16 * 2 + 1]; /* +1 because we dererefence (but don't use) one
136                                byte off the end */
137 
138   if (nbits <= 0 || nbits > 128) {
139     return;
140   }
141 
142   // fill in the first half of the new IV with the current IV
143   OPENSSL_memcpy(ovec, ivec, 16);
144   // construct the new IV
145   (*block)(ivec, ivec, key);
146   num = (nbits + 7) / 8;
147   if (enc) {
148     // encrypt the input
149     for (n = 0; n < num; ++n) {
150       out[n] = (ovec[16 + n] = in[n] ^ ivec[n]);
151     }
152   } else {
153     // decrypt the input
154     for (n = 0; n < num; ++n) {
155       out[n] = (ovec[16 + n] = in[n]) ^ ivec[n];
156     }
157   }
158   // shift ovec left...
159   rem = nbits % 8;
160   num = nbits / 8;
161   if (rem == 0) {
162     OPENSSL_memcpy(ivec, ovec + num, 16);
163   } else {
164     for (n = 0; n < 16; ++n) {
165       ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem);
166     }
167   }
168 
169   // it is not necessary to cleanse ovec, since the IV is not secret
170 }
171 
172 // N.B. This expects the input to be packed, MS bit first
CRYPTO_cfb128_1_encrypt(const uint8_t * in,uint8_t * out,size_t bits,const AES_KEY * key,uint8_t ivec[16],unsigned * num,int enc,block128_f block)173 void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
174                              const AES_KEY *key, uint8_t ivec[16],
175                              unsigned *num, int enc, block128_f block) {
176   size_t n;
177   uint8_t c[1], d[1];
178 
179   assert(in && out && key && ivec && num);
180   assert(*num == 0);
181 
182   for (n = 0; n < bits; ++n) {
183     c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
184     cfbr_encrypt_block(c, d, 1, key, ivec, enc, block);
185     out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) |
186                  ((d[0] & 0x80) >> (unsigned int)(n % 8));
187   }
188 }
189 
CRYPTO_cfb128_8_encrypt(const unsigned char * in,unsigned char * out,size_t length,const AES_KEY * key,unsigned char ivec[16],unsigned * num,int enc,block128_f block)190 void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
191                              size_t length, const AES_KEY *key,
192                              unsigned char ivec[16], unsigned *num, int enc,
193                              block128_f block) {
194   size_t n;
195 
196   assert(in && out && key && ivec && num);
197   assert(*num == 0);
198 
199   for (n = 0; n < length; ++n) {
200     cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
201   }
202 }
203