Line data Source code
1 : /* cipher-cfb.c - Generic CFB mode implementation
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
3 : * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
4 : *
5 : * This file is part of Libgcrypt.
6 : *
7 : * Libgcrypt is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU Lesser general Public License as
9 : * published by the Free Software Foundation; either version 2.1 of
10 : * the License, or (at your option) any later version.
11 : *
12 : * Libgcrypt is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public
18 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <errno.h>
26 :
27 : #include "g10lib.h"
28 : #include "cipher.h"
29 : #include "bufhelp.h"
30 : #include "./cipher-internal.h"
31 :
32 :
33 : gcry_err_code_t
34 66208 : _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
35 : unsigned char *outbuf, size_t outbuflen,
36 : const unsigned char *inbuf, size_t inbuflen)
37 : {
38 : unsigned char *ivp;
39 66208 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
40 66208 : size_t blocksize = c->spec->blocksize;
41 66208 : size_t blocksize_x_2 = blocksize + blocksize;
42 : unsigned int burn, nburn;
43 :
44 : /* Tell compiler that we require a cipher with a 64bit or 128 bit block
45 : * length, to allow better optimization of this function. */
46 66208 : if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
47 0 : return GPG_ERR_INV_LENGTH;
48 :
49 66208 : if (outbuflen < inbuflen)
50 0 : return GPG_ERR_BUFFER_TOO_SHORT;
51 :
52 66208 : if ( inbuflen <= c->unused )
53 : {
54 : /* Short enough to be encoded by the remaining XOR mask. */
55 : /* XOR the input with the IV and store input into IV. */
56 0 : ivp = c->u_iv.iv + blocksize - c->unused;
57 0 : buf_xor_2dst(outbuf, ivp, inbuf, inbuflen);
58 0 : c->unused -= inbuflen;
59 0 : return 0;
60 : }
61 :
62 66208 : burn = 0;
63 :
64 66208 : if ( c->unused )
65 : {
66 : /* XOR the input with the IV and store input into IV */
67 0 : inbuflen -= c->unused;
68 0 : ivp = c->u_iv.iv + blocksize - c->unused;
69 0 : buf_xor_2dst(outbuf, ivp, inbuf, c->unused);
70 0 : outbuf += c->unused;
71 0 : inbuf += c->unused;
72 0 : c->unused = 0;
73 : }
74 :
75 : /* Now we can process complete blocks. We use a loop as long as we
76 : have at least 2 blocks and use conditions for the rest. This
77 : also allows to use a bulk encryption function if available. */
78 66208 : if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc)
79 13310 : {
80 13310 : size_t nblocks = inbuflen / blocksize;
81 13310 : c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
82 13310 : outbuf += nblocks * blocksize;
83 13310 : inbuf += nblocks * blocksize;
84 13310 : inbuflen -= nblocks * blocksize;
85 : }
86 : else
87 : {
88 5857444 : while ( inbuflen >= blocksize_x_2 )
89 : {
90 : /* Encrypt the IV. */
91 5751648 : nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
92 5751648 : burn = nburn > burn ? nburn : burn;
93 : /* XOR the input with the IV and store input into IV. */
94 5751648 : buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
95 5751648 : outbuf += blocksize;
96 5751648 : inbuf += blocksize;
97 5751648 : inbuflen -= blocksize;
98 : }
99 : }
100 :
101 66208 : if ( inbuflen >= blocksize )
102 : {
103 : /* Save the current IV and then encrypt the IV. */
104 52898 : buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
105 52898 : nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
106 52898 : burn = nburn > burn ? nburn : burn;
107 : /* XOR the input with the IV and store input into IV */
108 52898 : buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
109 52898 : outbuf += blocksize;
110 52898 : inbuf += blocksize;
111 52898 : inbuflen -= blocksize;
112 : }
113 66208 : if ( inbuflen )
114 : {
115 : /* Save the current IV and then encrypt the IV. */
116 0 : buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
117 0 : nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
118 0 : burn = nburn > burn ? nburn : burn;
119 0 : c->unused = blocksize;
120 : /* Apply the XOR. */
121 0 : c->unused -= inbuflen;
122 0 : buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen);
123 0 : outbuf += inbuflen;
124 0 : inbuf += inbuflen;
125 0 : inbuflen = 0;
126 : }
127 :
128 66208 : if (burn > 0)
129 50898 : _gcry_burn_stack (burn + 4 * sizeof(void *));
130 :
131 66208 : return 0;
132 : }
133 :
134 :
135 : gcry_err_code_t
136 57994 : _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
137 : unsigned char *outbuf, size_t outbuflen,
138 : const unsigned char *inbuf, size_t inbuflen)
139 : {
140 : unsigned char *ivp;
141 57994 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
142 57994 : size_t blocksize = c->spec->blocksize;
143 57994 : size_t blocksize_x_2 = blocksize + blocksize;
144 : unsigned int burn, nburn;
145 :
146 : /* Tell compiler that we require a cipher with a 64bit or 128 bit block
147 : * length, to allow better optimization of this function. */
148 57994 : if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
149 0 : return GPG_ERR_INV_LENGTH;
150 :
151 57994 : if (outbuflen < inbuflen)
152 0 : return GPG_ERR_BUFFER_TOO_SHORT;
153 :
154 57994 : if (inbuflen <= c->unused)
155 : {
156 : /* Short enough to be encoded by the remaining XOR mask. */
157 : /* XOR the input with the IV and store input into IV. */
158 0 : ivp = c->u_iv.iv + blocksize - c->unused;
159 0 : buf_xor_n_copy(outbuf, ivp, inbuf, inbuflen);
160 0 : c->unused -= inbuflen;
161 0 : return 0;
162 : }
163 :
164 57994 : burn = 0;
165 :
166 57994 : if (c->unused)
167 : {
168 : /* XOR the input with the IV and store input into IV. */
169 0 : inbuflen -= c->unused;
170 0 : ivp = c->u_iv.iv + blocksize - c->unused;
171 0 : buf_xor_n_copy(outbuf, ivp, inbuf, c->unused);
172 0 : outbuf += c->unused;
173 0 : inbuf += c->unused;
174 0 : c->unused = 0;
175 : }
176 :
177 : /* Now we can process complete blocks. We use a loop as long as we
178 : have at least 2 blocks and use conditions for the rest. This
179 : also allows to use a bulk encryption function if available. */
180 57994 : if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec)
181 41200 : {
182 41200 : size_t nblocks = inbuflen / blocksize;
183 41200 : c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
184 41200 : outbuf += nblocks * blocksize;
185 41200 : inbuf += nblocks * blocksize;
186 41200 : inbuflen -= nblocks * blocksize;
187 : }
188 : else
189 : {
190 1805736 : while (inbuflen >= blocksize_x_2 )
191 : {
192 : /* Encrypt the IV. */
193 1772148 : nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
194 1772148 : burn = nburn > burn ? nburn : burn;
195 : /* XOR the input with the IV and store input into IV. */
196 1772148 : buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
197 1772148 : outbuf += blocksize;
198 1772148 : inbuf += blocksize;
199 1772148 : inbuflen -= blocksize;
200 : }
201 : }
202 :
203 57994 : if (inbuflen >= blocksize )
204 : {
205 : /* Save the current IV and then encrypt the IV. */
206 16794 : buf_cpy ( c->lastiv, c->u_iv.iv, blocksize);
207 16794 : nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
208 16794 : burn = nburn > burn ? nburn : burn;
209 : /* XOR the input with the IV and store input into IV */
210 16794 : buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
211 16794 : outbuf += blocksize;
212 16794 : inbuf += blocksize;
213 16794 : inbuflen -= blocksize;
214 : }
215 :
216 57994 : if (inbuflen)
217 : {
218 : /* Save the current IV and then encrypt the IV. */
219 0 : buf_cpy ( c->lastiv, c->u_iv.iv, blocksize );
220 0 : nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
221 0 : burn = nburn > burn ? nburn : burn;
222 0 : c->unused = blocksize;
223 : /* Apply the XOR. */
224 0 : c->unused -= inbuflen;
225 0 : buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, inbuflen);
226 0 : outbuf += inbuflen;
227 0 : inbuf += inbuflen;
228 0 : inbuflen = 0;
229 : }
230 :
231 57994 : if (burn > 0)
232 14902 : _gcry_burn_stack (burn + 4 * sizeof(void *));
233 :
234 57994 : return 0;
235 : }
236 :
237 :
238 : gcry_err_code_t
239 10210 : _gcry_cipher_cfb8_encrypt (gcry_cipher_hd_t c,
240 : unsigned char *outbuf, size_t outbuflen,
241 : const unsigned char *inbuf, size_t inbuflen)
242 : {
243 10210 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
244 10210 : size_t blocksize = c->spec->blocksize;
245 : unsigned int burn, nburn;
246 :
247 10210 : if (outbuflen < inbuflen)
248 0 : return GPG_ERR_BUFFER_TOO_SHORT;
249 :
250 10210 : burn = 0;
251 :
252 2549824 : while ( inbuflen > 0)
253 : {
254 : int i;
255 :
256 : /* Encrypt the IV. */
257 2529404 : nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
258 2529404 : burn = nburn > burn ? nburn : burn;
259 :
260 2529404 : outbuf[0] = c->lastiv[0] ^ inbuf[0];
261 :
262 : /* Bitshift iv by 8 bit to the left */
263 33015424 : for (i = 0; i < blocksize-1; i++)
264 30486020 : c->u_iv.iv[i] = c->u_iv.iv[i+1];
265 :
266 : /* append cipher text to iv */
267 2529404 : c->u_iv.iv[blocksize-1] = outbuf[0];
268 :
269 2529404 : outbuf += 1;
270 2529404 : inbuf += 1;
271 2529404 : inbuflen -= 1;
272 : }
273 :
274 10210 : if (burn > 0)
275 9427 : _gcry_burn_stack (burn + 4 * sizeof(void *));
276 :
277 10210 : return 0;
278 : }
279 :
280 :
281 : gcry_err_code_t
282 10210 : _gcry_cipher_cfb8_decrypt (gcry_cipher_hd_t c,
283 : unsigned char *outbuf, size_t outbuflen,
284 : const unsigned char *inbuf, size_t inbuflen)
285 : {
286 10210 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
287 10210 : size_t blocksize = c->spec->blocksize;
288 : unsigned int burn, nburn;
289 : unsigned char appendee;
290 :
291 10210 : if (outbuflen < inbuflen)
292 0 : return GPG_ERR_BUFFER_TOO_SHORT;
293 :
294 10210 : burn = 0;
295 :
296 2549824 : while (inbuflen > 0)
297 : {
298 : int i;
299 :
300 : /* Encrypt the IV. */
301 2529404 : nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
302 2529404 : burn = nburn > burn ? nburn : burn;
303 :
304 : /* inbuf might == outbuf, make sure we keep the value
305 : so we can append it later */
306 2529404 : appendee = inbuf[0];
307 :
308 2529404 : outbuf[0] = inbuf[0] ^ c->lastiv[0];
309 :
310 : /* Bitshift iv by 8 bit to the left */
311 33015424 : for (i = 0; i < blocksize-1; i++)
312 30486020 : c->u_iv.iv[i] = c->u_iv.iv[i+1];
313 :
314 2529404 : c->u_iv.iv[blocksize-1] = appendee;
315 :
316 2529404 : outbuf += 1;
317 2529404 : inbuf += 1;
318 2529404 : inbuflen -= 1;
319 : }
320 :
321 10210 : if (burn > 0)
322 9427 : _gcry_burn_stack (burn + 4 * sizeof(void *));
323 :
324 10210 : return 0;
325 : }
|