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