Add carryless 8-bit addition fast-path for AES-NI CTR mode
[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   if (outbuflen < inbuflen)
45     return GPG_ERR_BUFFER_TOO_SHORT;
46
47   if ( inbuflen <= c->unused )
48     {
49       /* Short enough to be encoded by the remaining XOR mask. */
50       /* XOR the input with the IV and store input into IV. */
51       ivp = c->u_iv.iv + blocksize - c->unused;
52       buf_xor_2dst(outbuf, ivp, inbuf, inbuflen);
53       c->unused -= inbuflen;
54       return 0;
55     }
56
57   burn = 0;
58
59   if ( c->unused )
60     {
61       /* XOR the input with the IV and store input into IV */
62       inbuflen -= c->unused;
63       ivp = c->u_iv.iv + blocksize - c->unused;
64       buf_xor_2dst(outbuf, ivp, inbuf, c->unused);
65       outbuf += c->unused;
66       inbuf += c->unused;
67       c->unused = 0;
68     }
69
70   /* Now we can process complete blocks.  We use a loop as long as we
71      have at least 2 blocks and use conditions for the rest.  This
72      also allows to use a bulk encryption function if available.  */
73   if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc)
74     {
75       size_t nblocks = inbuflen / blocksize;
76       c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
77       outbuf += nblocks * blocksize;
78       inbuf  += nblocks * blocksize;
79       inbuflen -= nblocks * blocksize;
80     }
81   else
82     {
83       while ( inbuflen >= blocksize_x_2 )
84         {
85           /* Encrypt the IV. */
86           nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
87           burn = nburn > burn ? nburn : burn;
88           /* XOR the input with the IV and store input into IV.  */
89           buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
90           outbuf += blocksize;
91           inbuf += blocksize;
92           inbuflen -= blocksize;
93         }
94     }
95
96   if ( inbuflen >= blocksize )
97     {
98       /* Save the current IV and then encrypt the IV. */
99       buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
100       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
101       burn = nburn > burn ? nburn : burn;
102       /* XOR the input with the IV and store input into IV */
103       buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
104       outbuf += blocksize;
105       inbuf += blocksize;
106       inbuflen -= blocksize;
107     }
108   if ( inbuflen )
109     {
110       /* Save the current IV and then encrypt the IV. */
111       buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
112       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
113       burn = nburn > burn ? nburn : burn;
114       c->unused = blocksize;
115       /* Apply the XOR. */
116       c->unused -= inbuflen;
117       buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen);
118       outbuf += inbuflen;
119       inbuf += inbuflen;
120       inbuflen = 0;
121     }
122
123   if (burn > 0)
124     _gcry_burn_stack (burn + 4 * sizeof(void *));
125
126   return 0;
127 }
128
129
130 gcry_err_code_t
131 _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
132                           unsigned char *outbuf, size_t outbuflen,
133                           const unsigned char *inbuf, size_t inbuflen)
134 {
135   unsigned char *ivp;
136   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
137   size_t blocksize = c->spec->blocksize;
138   size_t blocksize_x_2 = blocksize + blocksize;
139   unsigned int burn, nburn;
140
141   if (outbuflen < inbuflen)
142     return GPG_ERR_BUFFER_TOO_SHORT;
143
144   if (inbuflen <= c->unused)
145     {
146       /* Short enough to be encoded by the remaining XOR mask. */
147       /* XOR the input with the IV and store input into IV. */
148       ivp = c->u_iv.iv + blocksize - c->unused;
149       buf_xor_n_copy(outbuf, ivp, inbuf, inbuflen);
150       c->unused -= inbuflen;
151       return 0;
152     }
153
154   burn = 0;
155
156   if (c->unused)
157     {
158       /* XOR the input with the IV and store input into IV. */
159       inbuflen -= c->unused;
160       ivp = c->u_iv.iv + blocksize - c->unused;
161       buf_xor_n_copy(outbuf, ivp, inbuf, c->unused);
162       outbuf += c->unused;
163       inbuf += c->unused;
164       c->unused = 0;
165     }
166
167   /* Now we can process complete blocks.  We use a loop as long as we
168      have at least 2 blocks and use conditions for the rest.  This
169      also allows to use a bulk encryption function if available.  */
170   if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec)
171     {
172       size_t nblocks = inbuflen / blocksize;
173       c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
174       outbuf += nblocks * blocksize;
175       inbuf  += nblocks * blocksize;
176       inbuflen -= nblocks * blocksize;
177     }
178   else
179     {
180       while (inbuflen >= blocksize_x_2 )
181         {
182           /* Encrypt the IV. */
183           nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
184           burn = nburn > burn ? nburn : burn;
185           /* XOR the input with the IV and store input into IV. */
186           buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
187           outbuf += blocksize;
188           inbuf += blocksize;
189           inbuflen -= blocksize;
190         }
191     }
192
193   if (inbuflen >= blocksize )
194     {
195       /* Save the current IV and then encrypt the IV. */
196       buf_cpy ( c->lastiv, c->u_iv.iv, blocksize);
197       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
198       burn = nburn > burn ? nburn : burn;
199       /* XOR the input with the IV and store input into IV */
200       buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
201       outbuf += blocksize;
202       inbuf += blocksize;
203       inbuflen -= blocksize;
204     }
205
206   if (inbuflen)
207     {
208       /* Save the current IV and then encrypt the IV. */
209       buf_cpy ( c->lastiv, c->u_iv.iv, blocksize );
210       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
211       burn = nburn > burn ? nburn : burn;
212       c->unused = blocksize;
213       /* Apply the XOR. */
214       c->unused -= inbuflen;
215       buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, inbuflen);
216       outbuf += inbuflen;
217       inbuf += inbuflen;
218       inbuflen = 0;
219     }
220
221   if (burn > 0)
222     _gcry_burn_stack (burn + 4 * sizeof(void *));
223
224   return 0;
225 }