Coverage Report

Created: 2022-12-08 06:10

/src/libgcrypt/cipher/cipher-cbc.c
Line
Count
Source (jump to first uncovered line)
1
/* cipher-cbc.c  - Generic CBC 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 "./cipher-internal.h"
30
#include "bufhelp.h"
31
32
33
34
static inline unsigned int
35
cbc_encrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf,
36
                  const unsigned char *inbuf, size_t nblocks, size_t blocksize,
37
                  int is_cbc_cmac)
38
0
{
39
40
0
  unsigned int burn, nburn;
41
0
  size_t n;
42
43
0
  burn = 0;
44
45
0
  if (c->bulk.cbc_enc)
46
0
    {
47
0
      c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks,
48
0
                       is_cbc_cmac);
49
0
    }
50
0
  else
51
0
    {
52
0
      gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
53
0
      unsigned char *ivp;
54
55
0
      ivp = c->u_iv.iv;
56
57
0
      for (n=0; n < nblocks; n++ )
58
0
        {
59
0
          cipher_block_xor (outbuf, inbuf, ivp, blocksize);
60
0
          nburn = enc_fn ( &c->context.c, outbuf, outbuf );
61
0
          burn = nburn > burn ? nburn : burn;
62
0
          ivp = outbuf;
63
0
          inbuf += blocksize;
64
0
          if (!is_cbc_cmac)
65
0
            outbuf += blocksize;
66
0
        }
67
68
0
      if (ivp != c->u_iv.iv)
69
0
        cipher_block_cpy (c->u_iv.iv, ivp, blocksize);
70
0
    }
71
72
0
  return burn;
73
0
}
74
75
76
gcry_err_code_t
77
_gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c,
78
                          unsigned char *outbuf, size_t outbuflen,
79
                          const unsigned char *inbuf, size_t inbuflen)
80
0
{
81
0
  size_t blocksize_shift = _gcry_blocksize_shift(c);
82
0
  size_t blocksize = 1 << blocksize_shift;
83
0
  size_t blocksize_mask = blocksize - 1;
84
0
  size_t nblocks = inbuflen >> blocksize_shift;
85
0
  int is_cbc_cmac = !!(c->flags & GCRY_CIPHER_CBC_MAC);
86
0
  unsigned int burn;
87
88
0
  if (outbuflen < (is_cbc_cmac ? blocksize : inbuflen))
89
0
    return GPG_ERR_BUFFER_TOO_SHORT;
90
91
0
  if (inbuflen & blocksize_mask)
92
0
    return GPG_ERR_INV_LENGTH;
93
94
0
  burn = cbc_encrypt_inner(c, outbuf, inbuf, nblocks, blocksize, is_cbc_cmac);
95
96
0
  if (burn > 0)
97
0
    _gcry_burn_stack (burn + 4 * sizeof(void *));
98
99
0
  return 0;
100
0
}
101
102
103
gcry_err_code_t
104
_gcry_cipher_cbc_cts_encrypt (gcry_cipher_hd_t c,
105
                              unsigned char *outbuf, size_t outbuflen,
106
                              const unsigned char *inbuf, size_t inbuflen)
107
0
{
108
0
  size_t blocksize_shift = _gcry_blocksize_shift(c);
109
0
  size_t blocksize = 1 << blocksize_shift;
110
0
  size_t blocksize_mask = blocksize - 1;
111
0
  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
112
0
  size_t nblocks = inbuflen >> blocksize_shift;
113
0
  unsigned int burn, nburn;
114
0
  unsigned char *ivp;
115
0
  int i;
116
117
0
  if (outbuflen < inbuflen)
118
0
    return GPG_ERR_BUFFER_TOO_SHORT;
119
120
0
  if ((inbuflen & blocksize_mask) && !(inbuflen > blocksize))
121
0
    return GPG_ERR_INV_LENGTH;
122
123
0
  burn = 0;
124
125
0
  if (inbuflen > blocksize)
126
0
    {
127
0
      if ((inbuflen & blocksize_mask) == 0)
128
0
  nblocks--;
129
0
    }
130
131
0
  burn = cbc_encrypt_inner(c, outbuf, inbuf, nblocks, blocksize, 0);
132
0
  inbuf += nblocks << blocksize_shift;
133
0
  outbuf += nblocks << blocksize_shift;
134
135
0
  if (inbuflen > blocksize)
136
0
    {
137
      /* We have to be careful here, since outbuf might be equal to
138
         inbuf.  */
139
0
      size_t restbytes;
140
0
      unsigned char b;
141
142
0
      if ((inbuflen & blocksize_mask) == 0)
143
0
        restbytes = blocksize;
144
0
      else
145
0
        restbytes = inbuflen & blocksize_mask;
146
147
0
      outbuf -= blocksize;
148
0
      for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++)
149
0
        {
150
0
          b = inbuf[i];
151
0
          outbuf[blocksize + i] = outbuf[i];
152
0
          outbuf[i] = b ^ *ivp++;
153
0
        }
154
0
      for (; i < blocksize; i++)
155
0
        outbuf[i] = 0 ^ *ivp++;
156
157
0
      nburn = enc_fn (&c->context.c, outbuf, outbuf);
158
0
      burn = nburn > burn ? nburn : burn;
159
0
      cipher_block_cpy (c->u_iv.iv, outbuf, blocksize);
160
0
    }
161
162
0
  if (burn > 0)
163
0
    _gcry_burn_stack (burn + 4 * sizeof(void *));
164
165
0
  return 0;
166
0
}
167
168
169
static inline unsigned int
170
cbc_decrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf,
171
                  const unsigned char *inbuf, size_t nblocks, size_t blocksize)
172
0
{
173
0
  unsigned int burn, nburn;
174
0
  size_t n;
175
176
0
  burn = 0;
177
178
0
  if (c->bulk.cbc_dec)
179
0
    {
180
0
      c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
181
0
    }
182
0
  else
183
0
    {
184
0
      gcry_cipher_decrypt_t dec_fn = c->spec->decrypt;
185
186
0
      for (n = 0; n < nblocks; n++)
187
0
        {
188
          /* Because outbuf and inbuf might be the same, we must not overwrite
189
             the original ciphertext block.  We use LASTIV as intermediate
190
             storage here because it is not used otherwise.  */
191
0
          nburn = dec_fn ( &c->context.c, c->lastiv, inbuf );
192
0
          burn = nburn > burn ? nburn : burn;
193
0
          cipher_block_xor_n_copy_2 (outbuf, c->lastiv, c->u_iv.iv, inbuf,
194
0
                                     blocksize);
195
0
          inbuf  += blocksize;
196
0
          outbuf += blocksize;
197
0
        }
198
0
    }
199
200
0
  return burn;
201
0
}
202
203
204
gcry_err_code_t
205
_gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c,
206
                          unsigned char *outbuf, size_t outbuflen,
207
                          const unsigned char *inbuf, size_t inbuflen)
208
0
{
209
0
  size_t blocksize_shift = _gcry_blocksize_shift(c);
210
0
  size_t blocksize = 1 << blocksize_shift;
211
0
  size_t blocksize_mask = blocksize - 1;
212
0
  size_t nblocks = inbuflen >> blocksize_shift;
213
0
  unsigned int burn;
214
215
0
  if (outbuflen < inbuflen)
216
0
    return GPG_ERR_BUFFER_TOO_SHORT;
217
218
0
  if (inbuflen & blocksize_mask)
219
0
    return GPG_ERR_INV_LENGTH;
220
221
0
  burn = cbc_decrypt_inner(c, outbuf, inbuf, nblocks, blocksize);
222
223
0
  if (burn > 0)
224
0
    _gcry_burn_stack (burn + 4 * sizeof(void *));
225
226
0
  return 0;
227
0
}
228
229
230
gcry_err_code_t
231
_gcry_cipher_cbc_cts_decrypt (gcry_cipher_hd_t c,
232
                              unsigned char *outbuf, size_t outbuflen,
233
                              const unsigned char *inbuf, size_t inbuflen)
234
0
{
235
0
  size_t blocksize_shift = _gcry_blocksize_shift(c);
236
0
  size_t blocksize = 1 << blocksize_shift;
237
0
  size_t blocksize_mask = blocksize - 1;
238
0
  gcry_cipher_decrypt_t dec_fn = c->spec->decrypt;
239
0
  size_t nblocks = inbuflen >> blocksize_shift;
240
0
  unsigned int burn, nburn;
241
0
  int i;
242
243
0
  if (outbuflen < inbuflen)
244
0
    return GPG_ERR_BUFFER_TOO_SHORT;
245
246
0
  if ((inbuflen & blocksize_mask) && !(inbuflen > blocksize))
247
0
    return GPG_ERR_INV_LENGTH;
248
249
0
  burn = 0;
250
251
0
  if (inbuflen > blocksize)
252
0
    {
253
0
      nblocks--;
254
0
      if ((inbuflen & blocksize_mask) == 0)
255
0
  nblocks--;
256
0
      cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize);
257
0
    }
258
259
0
  burn = cbc_decrypt_inner(c, outbuf, inbuf, nblocks, blocksize);
260
0
  inbuf  += nblocks << blocksize_shift;
261
0
  outbuf += nblocks << blocksize_shift;
262
263
0
  if (inbuflen > blocksize)
264
0
    {
265
0
      size_t restbytes;
266
267
0
      if ((inbuflen & blocksize_mask) == 0)
268
0
        restbytes = blocksize;
269
0
      else
270
0
        restbytes = inbuflen & blocksize_mask;
271
272
0
      cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */
273
0
      buf_cpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */
274
275
0
      nburn = dec_fn ( &c->context.c, outbuf, inbuf );
276
0
      burn = nburn > burn ? nburn : burn;
277
0
      buf_xor(outbuf, outbuf, c->u_iv.iv, restbytes);
278
279
0
      buf_cpy (outbuf + blocksize, outbuf, restbytes);
280
0
      for(i=restbytes; i < blocksize; i++)
281
0
        c->u_iv.iv[i] = outbuf[i];
282
0
      nburn = dec_fn (&c->context.c, outbuf, c->u_iv.iv);
283
0
      burn = nburn > burn ? nburn : burn;
284
0
      cipher_block_xor(outbuf, outbuf, c->lastiv, blocksize);
285
      /* c->lastiv is now really lastlastiv, does this matter? */
286
0
    }
287
288
0
  if (burn > 0)
289
0
    _gcry_burn_stack (burn + 4 * sizeof(void *));
290
291
0
  return 0;
292
0
}