Coverage Report

Created: 2022-12-08 06:09

/src/libgcrypt/cipher/cipher-aeswrap.c
Line
Count
Source (jump to first uncovered line)
1
/* cipher-aeswrap.c  - Generic AESWRAP mode implementation
2
 * Copyright (C) 2009, 2011 Free Software Foundation, Inc.
3
 *
4
 * This file is part of Libgcrypt.
5
 *
6
 * Libgcrypt is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser general Public License as
8
 * published by the Free Software Foundation; either version 2.1 of
9
 * the License, or (at your option) any later version.
10
 *
11
 * Libgcrypt is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include <config.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <errno.h>
25
26
#include "g10lib.h"
27
#include "cipher.h"
28
#include "bufhelp.h"
29
#include "./cipher-internal.h"
30
31
/* Perform the wrap algorithm W as specified by NIST SP 800-38F.
32
   Cipher block size must be 128-bit.  */
33
static gcry_err_code_t
34
wrap (gcry_cipher_hd_t c, byte *outbuf, size_t inbuflen)
35
0
{
36
0
  int j, x;
37
0
  size_t n, i;
38
0
  unsigned char *r, *a, *b;
39
0
  unsigned char t[8];
40
0
  unsigned int burn, nburn;
41
42
#if MAX_BLOCKSIZE < 8
43
#error Invalid block size
44
#endif
45
  /* We require a cipher with a 128 bit block length.  */
46
0
  if (c->spec->blocksize != 16)
47
0
    return GPG_ERR_INV_LENGTH;
48
49
  /* Input data must be multiple of 64 bits.  */
50
0
  if (inbuflen % 8)
51
0
    return GPG_ERR_INV_ARG;
52
53
0
  n = inbuflen / 8;
54
55
  /* We need at least three 64 bit blocks.  */
56
0
  if (n < 3)
57
0
    return GPG_ERR_INV_ARG;
58
59
0
  burn = 0;
60
61
0
  r = outbuf;
62
0
  a = outbuf;  /* We store A directly in OUTBUF.  */
63
0
  b = c->u_ctr.ctr;  /* B is also used to concatenate stuff.  */
64
65
0
  memset (t, 0, sizeof t); /* t := 0.  */
66
67
0
  for (j = 0; j <= 5; j++)
68
0
    {
69
0
      for (i = 1; i < n; i++)
70
0
        {
71
          /* B := CIPH_k( A | R[i] ) */
72
0
          memcpy (b, a, 8);
73
0
          memcpy (b+8, r+i*8, 8);
74
0
          nburn = c->spec->encrypt (&c->context.c, b, b);
75
0
          burn = nburn > burn ? nburn : burn;
76
          /* t := t + 1  */
77
0
          for (x = 7; x >= 0; x--)
78
0
            if (++t[x])
79
0
              break;
80
          /* A := MSB_64(B) ^ t */
81
0
          cipher_block_xor (a, b, t, 8);
82
          /* R[i] := LSB_64(B) */
83
0
          memcpy (r+i*8, b+8, 8);
84
0
        }
85
0
   }
86
87
0
  if (burn > 0)
88
0
    _gcry_burn_stack (burn + 4 * sizeof(void *));
89
90
0
  return 0;
91
0
}
92
93
94
/* Perform the Key Wrap algorithm as specified by RFC3394.  We
95
   implement this as a mode usable with any cipher algorithm of
96
   blocksize 128.  */
97
gcry_err_code_t
98
_gcry_cipher_keywrap_encrypt (gcry_cipher_hd_t c,
99
                              byte *outbuf, size_t outbuflen,
100
                              const byte *inbuf, size_t inbuflen)
101
0
{
102
0
  gcry_err_code_t err;
103
0
  unsigned char *r = outbuf;
104
105
  /* We require a cipher with a 128 bit block length.  */
106
0
  if (c->spec->blocksize != 16)
107
0
    return GPG_ERR_INV_LENGTH;
108
109
  /* The output buffer must be able to hold the input data plus one
110
     additional block.  */
111
0
  if (outbuflen < inbuflen + 8)
112
0
    return GPG_ERR_BUFFER_TOO_SHORT;
113
  /* Input data must be multiple of 64 bits.  */
114
0
  if (inbuflen % 8)
115
0
    return GPG_ERR_INV_ARG;
116
117
  /* We need at least two 64 bit blocks.  */
118
0
  if ((inbuflen / 8) < 2)
119
0
    return GPG_ERR_INV_ARG;
120
121
  /* Copy the inbuf to the outbuf. */
122
0
  memmove (r+8, inbuf, inbuflen);
123
124
  /* If an IV has been set we use that IV as the Alternative Initial
125
     Value; if it has not been set we use the standard value.  */
126
0
  if (c->marks.iv)
127
0
    memcpy (r, c->u_iv.iv, 8);
128
0
  else
129
0
    memset (r, 0xa6, 8);
130
131
0
  err = wrap (c, r, inbuflen + 8);
132
133
0
  return err;
134
0
}
135
136
137
static const unsigned char icv2[] = { 0xA6, 0x59, 0x59, 0xA6 };
138
139
/* Perform the Key Wrap algorithm as specified by RFC5649.  */
140
gcry_err_code_t
141
_gcry_cipher_keywrap_encrypt_padding (gcry_cipher_hd_t c,
142
                                      byte *outbuf, size_t outbuflen,
143
                                      const byte *inbuf, size_t inbuflen)
144
0
{
145
0
  gcry_err_code_t err;
146
0
  unsigned char *r = outbuf;
147
0
  unsigned int padlen;
148
149
  /* We require a cipher with a 128 bit block length.  */
150
0
  if (c->spec->blocksize != 16)
151
0
    return GPG_ERR_INV_LENGTH;
152
153
  /* The output buffer must be able to hold the input data plus one
154
     additional block and padding.  */
155
0
  if (outbuflen < ((inbuflen + 7)/8)*8 + 8)
156
0
    return GPG_ERR_BUFFER_TOO_SHORT;
157
158
0
  if (inbuflen % 8)
159
0
    padlen = 8 - (inbuflen % 8);
160
0
  else
161
0
    padlen = 0;
162
163
0
  memcpy (r, icv2, 4);
164
0
  r[4] = ((inbuflen >> 24) & 0xff);
165
0
  r[5] = ((inbuflen >> 16) & 0xff);
166
0
  r[6] = ((inbuflen >> 8) & 0xff);
167
0
  r[7] = (inbuflen & 0xff);
168
0
  memcpy (r+8, inbuf, inbuflen);
169
0
  if (padlen)
170
0
    memset (r+8+inbuflen, 0, padlen);
171
172
0
  if (inbuflen <= 8)
173
0
    {
174
0
      unsigned int burn;
175
176
0
      burn = c->spec->encrypt (&c->context.c, r, r);
177
0
      if (burn > 0)
178
0
        _gcry_burn_stack (burn + 4 * sizeof(void *));
179
0
      err = 0;
180
0
    }
181
0
  else
182
0
    err = wrap (c, r, ((inbuflen + 7)/8)*8 + 8);
183
184
0
  return err;
185
0
}
186
187
188
/* Perform the unwrap algorithm W^-1 as specified by NIST SP 800-38F.
189
   Cipher block size must be 128-bit.  */
190
static gcry_err_code_t
191
unwrap (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, size_t inbuflen)
192
0
{
193
0
  int j, x;
194
0
  size_t n, i;
195
0
  unsigned char *r, *a, *b;
196
0
  unsigned char t[8];
197
0
  unsigned int burn, nburn;
198
199
#if MAX_BLOCKSIZE < 8
200
#error Invalid block size
201
#endif
202
  /* We require a cipher with a 128 bit block length.  */
203
0
  if (c->spec->blocksize != 16)
204
0
    return GPG_ERR_INV_LENGTH;
205
206
  /* Input data must be multiple of 64 bits.  */
207
0
  if (inbuflen % 8)
208
0
    return GPG_ERR_INV_ARG;
209
210
0
  n = inbuflen / 8;
211
212
  /* We need at least three 64 bit blocks.  */
213
0
  if (n < 3)
214
0
    return GPG_ERR_INV_ARG;
215
216
0
  burn = 0;
217
218
0
  r = outbuf;
219
0
  a = c->lastiv;  /* We use c->LASTIV as buffer for A.  */
220
0
  b = c->u_ctr.ctr;     /* B is also used to concatenate stuff.  */
221
222
  /* Copy the inbuf to the outbuf and save A. */
223
0
  memcpy (a, inbuf, 8);
224
0
  memmove (r, inbuf+8, inbuflen-8);
225
0
  n--; /* Reduce to actual number of data blocks.  */
226
227
  /* t := 6 * n  */
228
0
  i = n * 6;  /* The range is valid because: n = inbuflen / 8 - 1.  */
229
0
  for (x=0; x < 8 && x < sizeof (i); x++)
230
0
    t[7-x] = i >> (8*x);
231
0
  for (; x < 8; x++)
232
0
    t[7-x] = 0;
233
234
0
  for (j = 5; j >= 0; j--)
235
0
    {
236
0
      for (i = n; i >= 1; i--)
237
0
        {
238
          /* B := CIPH_k^-1( (A ^ t)| R[i] ) */
239
0
          cipher_block_xor (b, a, t, 8);
240
0
          memcpy (b+8, r+(i-1)*8, 8);
241
0
          nburn = c->spec->decrypt (&c->context.c, b, b);
242
0
          burn = nburn > burn ? nburn : burn;
243
          /* t := t - 1  */
244
0
          for (x = 7; x >= 0; x--)
245
0
            if (--t[x] != 0xff)
246
0
              break;
247
          /* A := MSB_64(B) */
248
0
          memcpy (a, b, 8);
249
          /* R[i] := LSB_64(B) */
250
0
          memcpy (r+(i-1)*8, b+8, 8);
251
0
        }
252
0
   }
253
0
  wipememory (b, 16);  /* Clear scratch area.  */
254
255
0
  if (burn > 0)
256
0
    _gcry_burn_stack (burn + 4 * sizeof(void *));
257
258
0
  return 0;
259
0
}
260
261
262
/* Perform the Key Unwrap algorithm as specified by RFC3394 and
263
   RFC5649.  */
264
gcry_err_code_t
265
_gcry_cipher_keywrap_decrypt_auto (gcry_cipher_hd_t c,
266
                                   byte *outbuf, size_t outbuflen,
267
                                   const byte *inbuf, size_t inbuflen)
268
0
{
269
0
  gcry_err_code_t err;
270
271
  /* We require a cipher with a 128 bit block length.  */
272
0
  if (c->spec->blocksize != 16)
273
0
    return GPG_ERR_INV_LENGTH;
274
275
  /* The output buffer must be able to hold the input data minus one
276
     additional block.  Fixme: The caller has more restrictive checks
277
     - we may want to fix them for this mode.  */
278
0
  if (outbuflen + 8 < inbuflen)
279
0
    return GPG_ERR_BUFFER_TOO_SHORT;
280
  /* Input data must be multiple of 64 bits.  */
281
0
  if (inbuflen % 8)
282
0
    return GPG_ERR_INV_ARG;
283
284
0
  if (inbuflen == 16)
285
0
    {
286
0
      unsigned int burn;
287
0
      unsigned char t[16];
288
289
0
      if (!(c->flags & GCRY_CIPHER_EXTENDED))
290
0
        return GPG_ERR_BUFFER_TOO_SHORT;
291
292
0
      burn = c->spec->decrypt (&c->context.c, t, inbuf);
293
0
      if (burn > 0)
294
0
        _gcry_burn_stack (burn + 4 * sizeof(void *));
295
296
0
      if (memcmp (t, icv2, 4))
297
0
        err = GPG_ERR_CHECKSUM;
298
0
      else
299
0
        {
300
0
          unsigned int plen = (t[4]<<24) | (t[5]<<16) | (t[6]<<8) | t[7];
301
302
0
          err = 0;
303
0
          if (plen > 8)
304
0
            err = GPG_ERR_CHECKSUM;
305
0
          else if (plen)
306
0
            {
307
0
              int i;
308
309
0
              for (i = 0; i < 16 - (8+plen); i++)
310
0
                if (t[8+plen+i])
311
0
                  {
312
0
                    err = GPG_ERR_CHECKSUM;
313
0
                    break;
314
0
                  }
315
0
              if (!err)
316
0
                {
317
0
                  memcpy (outbuf, t+8, 8);
318
0
                  memcpy (c->u_mode.wrap.plen, t+4, 4);
319
0
                }
320
0
            }
321
0
        }
322
0
    }
323
0
  else
324
0
    {
325
      /* We need at least three 64 bit blocks.  */
326
0
      if ((inbuflen / 8) < 3)
327
0
        return GPG_ERR_INV_ARG;
328
329
0
      err = unwrap (c, outbuf, inbuf, inbuflen);
330
0
      if (!err)
331
0
        {
332
0
          unsigned char *a;
333
334
0
          a = c->lastiv;  /* We use c->LASTIV as buffer for A.  */
335
336
          /* If an IV has been set we compare against this Alternative Initial
337
             Value; if it has not been set we compare against the standard IV.  */
338
0
          if (c->marks.iv && !memcmp (a, c->u_iv.iv, 8))
339
0
            memset (c->u_mode.wrap.plen, 0, 4);
340
0
          else if (!memcmp (a, icv2, 4)) /* It's a packet wrapped by KWP.  */
341
0
            {
342
0
              unsigned int plen = (a[4]<<24) | (a[5]<<16) | (a[6]<<8) | a[7];
343
0
              int padlen = inbuflen - 8 - plen;
344
345
0
              if (!(c->flags & GCRY_CIPHER_EXTENDED))
346
0
                err = GPG_ERR_CHECKSUM;
347
0
              else if (padlen < 0 || padlen > 7)
348
0
                err = GPG_ERR_CHECKSUM;
349
0
              else if (padlen)
350
0
                {
351
0
                  int i;
352
353
0
                  for (i = 0; i < padlen; i++)
354
0
                    if (outbuf[plen+i])
355
0
                      {
356
0
                        err = GPG_ERR_CHECKSUM;
357
0
                        break;
358
0
                      }
359
0
                }
360
0
              if (!err)
361
0
                memcpy (c->u_mode.wrap.plen, a+4, 4);
362
0
            }
363
0
          else                  /* It's a packet wrapped by KW.  */
364
0
            {
365
0
              int i;
366
367
0
              for (i = 0; i < 8; i++)
368
0
                if (a[i] != 0xa6)
369
0
                  {
370
0
                    err = GPG_ERR_CHECKSUM;
371
0
                    break;
372
0
                  }
373
0
              if (!err)
374
0
                memset (c->u_mode.wrap.plen, 0, 4);
375
0
            }
376
0
        }
377
0
    }
378
379
0
  return err;
380
0
}