ecc: Fix ec_mulm_25519.
[libgcrypt.git] / cipher / cipher-cfb.c
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 _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   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
40   size_t blocksize = c->spec->blocksize;
41   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   if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
47     return GPG_ERR_INV_LENGTH;
48
49   if (outbuflen < inbuflen)
50     return GPG_ERR_BUFFER_TOO_SHORT;
51
52   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       ivp = c->u_iv.iv + blocksize - c->unused;
57       buf_xor_2dst(outbuf, ivp, inbuf, inbuflen);
58       c->unused -= inbuflen;
59       return 0;
60     }
61
62   burn = 0;
63
64   if ( c->unused )
65     {
66       /* XOR the input with the IV and store input into IV */
67       inbuflen -= c->unused;
68       ivp = c->u_iv.iv + blocksize - c->unused;
69       buf_xor_2dst(outbuf, ivp, inbuf, c->unused);
70       outbuf += c->unused;
71       inbuf += c->unused;
72       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   if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc)
79     {
80       size_t nblocks = inbuflen / blocksize;
81       c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
82       outbuf += nblocks * blocksize;
83       inbuf  += nblocks * blocksize;
84       inbuflen -= nblocks * blocksize;
85     }
86   else
87     {
88       while ( inbuflen >= blocksize_x_2 )
89         {
90           /* Encrypt the IV. */
91           nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
92           burn = nburn > burn ? nburn : burn;
93           /* XOR the input with the IV and store input into IV.  */
94           buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
95           outbuf += blocksize;
96           inbuf += blocksize;
97           inbuflen -= blocksize;
98         }
99     }
100
101   if ( inbuflen >= blocksize )
102     {
103       /* Save the current IV and then encrypt the IV. */
104       buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
105       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
106       burn = nburn > burn ? nburn : burn;
107       /* XOR the input with the IV and store input into IV */
108       buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
109       outbuf += blocksize;
110       inbuf += blocksize;
111       inbuflen -= blocksize;
112     }
113   if ( inbuflen )
114     {
115       /* Save the current IV and then encrypt the IV. */
116       buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
117       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
118       burn = nburn > burn ? nburn : burn;
119       c->unused = blocksize;
120       /* Apply the XOR. */
121       c->unused -= inbuflen;
122       buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen);
123       outbuf += inbuflen;
124       inbuf += inbuflen;
125       inbuflen = 0;
126     }
127
128   if (burn > 0)
129     _gcry_burn_stack (burn + 4 * sizeof(void *));
130
131   return 0;
132 }
133
134
135 gcry_err_code_t
136 _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   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
142   size_t blocksize = c->spec->blocksize;
143   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   if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
149     return GPG_ERR_INV_LENGTH;
150
151   if (outbuflen < inbuflen)
152     return GPG_ERR_BUFFER_TOO_SHORT;
153
154   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       ivp = c->u_iv.iv + blocksize - c->unused;
159       buf_xor_n_copy(outbuf, ivp, inbuf, inbuflen);
160       c->unused -= inbuflen;
161       return 0;
162     }
163
164   burn = 0;
165
166   if (c->unused)
167     {
168       /* XOR the input with the IV and store input into IV. */
169       inbuflen -= c->unused;
170       ivp = c->u_iv.iv + blocksize - c->unused;
171       buf_xor_n_copy(outbuf, ivp, inbuf, c->unused);
172       outbuf += c->unused;
173       inbuf += c->unused;
174       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   if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec)
181     {
182       size_t nblocks = inbuflen / blocksize;
183       c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
184       outbuf += nblocks * blocksize;
185       inbuf  += nblocks * blocksize;
186       inbuflen -= nblocks * blocksize;
187     }
188   else
189     {
190       while (inbuflen >= blocksize_x_2 )
191         {
192           /* Encrypt the IV. */
193           nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
194           burn = nburn > burn ? nburn : burn;
195           /* XOR the input with the IV and store input into IV. */
196           buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
197           outbuf += blocksize;
198           inbuf += blocksize;
199           inbuflen -= blocksize;
200         }
201     }
202
203   if (inbuflen >= blocksize )
204     {
205       /* Save the current IV and then encrypt the IV. */
206       buf_cpy ( c->lastiv, c->u_iv.iv, blocksize);
207       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
208       burn = nburn > burn ? nburn : burn;
209       /* XOR the input with the IV and store input into IV */
210       buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
211       outbuf += blocksize;
212       inbuf += blocksize;
213       inbuflen -= blocksize;
214     }
215
216   if (inbuflen)
217     {
218       /* Save the current IV and then encrypt the IV. */
219       buf_cpy ( c->lastiv, c->u_iv.iv, blocksize );
220       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
221       burn = nburn > burn ? nburn : burn;
222       c->unused = blocksize;
223       /* Apply the XOR. */
224       c->unused -= inbuflen;
225       buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, inbuflen);
226       outbuf += inbuflen;
227       inbuf += inbuflen;
228       inbuflen = 0;
229     }
230
231   if (burn > 0)
232     _gcry_burn_stack (burn + 4 * sizeof(void *));
233
234   return 0;
235 }
236
237
238 gcry_err_code_t
239 _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   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
244   size_t blocksize = c->spec->blocksize;
245   unsigned int burn, nburn;
246
247   if (outbuflen < inbuflen)
248     return GPG_ERR_BUFFER_TOO_SHORT;
249
250   burn = 0;
251
252   while ( inbuflen > 0)
253     {
254       int i;
255
256       /* Encrypt the IV. */
257       nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
258       burn = nburn > burn ? nburn : burn;
259
260       outbuf[0] = c->lastiv[0] ^ inbuf[0];
261
262       /* Bitshift iv by 8 bit to the left */
263       for (i = 0; i < blocksize-1; i++)
264         c->u_iv.iv[i] = c->u_iv.iv[i+1];
265
266       /* append cipher text to iv */
267       c->u_iv.iv[blocksize-1] = outbuf[0];
268
269       outbuf += 1;
270       inbuf += 1;
271       inbuflen -= 1;
272     }
273
274   if (burn > 0)
275     _gcry_burn_stack (burn + 4 * sizeof(void *));
276
277   return 0;
278 }
279
280
281 gcry_err_code_t
282 _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   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
287   size_t blocksize = c->spec->blocksize;
288   unsigned int burn, nburn;
289   unsigned char appendee;
290
291   if (outbuflen < inbuflen)
292     return GPG_ERR_BUFFER_TOO_SHORT;
293
294   burn = 0;
295
296   while (inbuflen > 0)
297     {
298       int i;
299
300       /* Encrypt the IV. */
301       nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
302       burn = nburn > burn ? nburn : burn;
303
304       /* inbuf might == outbuf, make sure we keep the value
305          so we can append it later */
306       appendee = inbuf[0];
307
308       outbuf[0] = inbuf[0] ^ c->lastiv[0];
309
310       /* Bitshift iv by 8 bit to the left */
311       for (i = 0; i < blocksize-1; i++)
312         c->u_iv.iv[i] = c->u_iv.iv[i+1];
313
314       c->u_iv.iv[blocksize-1] = appendee;
315
316       outbuf += 1;
317       inbuf += 1;
318       inbuflen -= 1;
319     }
320
321   if (burn > 0)
322     _gcry_burn_stack (burn + 4 * sizeof(void *));
323
324   return 0;
325 }