Factor cipher mode code out to separate files.
[libgcrypt.git] / cipher / cipher-ofb.c
1 /* cipher-ofb.c  - Generic OFB 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_ofb_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
41   if (outbuflen < inbuflen)
42     return GPG_ERR_BUFFER_TOO_SHORT;
43
44   if ( inbuflen <= c->unused )
45     {
46       /* Short enough to be encoded by the remaining XOR mask. */
47       /* XOR the input with the IV */
48       for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused;
49            inbuflen;
50            inbuflen--, c->unused-- )
51         *outbuf++ = (*ivp++ ^ *inbuf++);
52       return 0;
53     }
54
55   if( c->unused )
56     {
57       inbuflen -= c->unused;
58       for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
59         *outbuf++ = (*ivp++ ^ *inbuf++);
60     }
61
62   /* Now we can process complete blocks. */
63   while ( inbuflen >= blocksize )
64     {
65       int i;
66       /* Encrypt the IV (and save the current one). */
67       memcpy( c->lastiv, c->u_iv.iv, blocksize );
68       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
69
70       for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
71         *outbuf++ = (*ivp++ ^ *inbuf++);
72       inbuflen -= blocksize;
73     }
74   if ( inbuflen )
75     { /* process the remaining bytes */
76       memcpy( c->lastiv, c->u_iv.iv, blocksize );
77       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
78       c->unused = blocksize;
79       c->unused -= inbuflen;
80       for(ivp=c->u_iv.iv; inbuflen; inbuflen-- )
81         *outbuf++ = (*ivp++ ^ *inbuf++);
82     }
83   return 0;
84 }
85
86
87 gcry_err_code_t
88 _gcry_cipher_ofb_decrypt (gcry_cipher_hd_t c,
89                           unsigned char *outbuf, unsigned int outbuflen,
90                           const unsigned char *inbuf, unsigned int inbuflen)
91 {
92   unsigned char *ivp;
93   size_t blocksize = c->cipher->blocksize;
94
95   if (outbuflen < inbuflen)
96     return GPG_ERR_BUFFER_TOO_SHORT;
97
98   if( inbuflen <= c->unused )
99     {
100       /* Short enough to be encoded by the remaining XOR mask. */
101       for (ivp=c->u_iv.iv+blocksize - c->unused; inbuflen; inbuflen--,c->unused--)
102         *outbuf++ = *ivp++ ^ *inbuf++;
103       return 0;
104     }
105
106   if ( c->unused )
107     {
108       inbuflen -= c->unused;
109       for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
110         *outbuf++ = *ivp++ ^ *inbuf++;
111     }
112
113   /* Now we can process complete blocks. */
114   while ( inbuflen >= blocksize )
115     {
116       int i;
117       /* Encrypt the IV (and save the current one). */
118       memcpy( c->lastiv, c->u_iv.iv, blocksize );
119       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
120       for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
121         *outbuf++ = *ivp++ ^ *inbuf++;
122       inbuflen -= blocksize;
123     }
124   if ( inbuflen )
125     { /* Process the remaining bytes. */
126       /* Encrypt the IV (and save the current one). */
127       memcpy( c->lastiv, c->u_iv.iv, blocksize );
128       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
129       c->unused = blocksize;
130       c->unused -= inbuflen;
131       for (ivp=c->u_iv.iv; inbuflen; inbuflen-- )
132         *outbuf++ = *ivp++ ^ *inbuf++;
133     }
134   return 0;
135 }