Coverage Report

Created: 2022-12-08 06:09

/src/libgcrypt/cipher/cipher-eax.c
Line
Count
Source (jump to first uncovered line)
1
/* cipher-eax.c  -  EAX implementation
2
 * Copyright (C) 2018 Jussi Kivilinna <jussi.kivilinna@iki.fi>
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
32
gcry_err_code_t
33
_gcry_cipher_eax_encrypt (gcry_cipher_hd_t c,
34
                          byte *outbuf, size_t outbuflen,
35
                          const byte *inbuf, size_t inbuflen)
36
0
{
37
0
  gcry_err_code_t err;
38
39
0
  if (outbuflen < inbuflen)
40
0
    return GPG_ERR_BUFFER_TOO_SHORT;
41
0
  if (c->marks.tag)
42
0
    return GPG_ERR_INV_STATE;
43
44
0
  if (!c->marks.iv)
45
0
    {
46
0
      err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
47
0
      if (err != 0)
48
0
  return err;
49
0
    }
50
51
0
  while (inbuflen)
52
0
    {
53
0
      size_t currlen = inbuflen;
54
55
      /* Since checksumming is done after encryption, process input in 24KiB
56
       * chunks to keep data loaded in L1 cache for checksumming. However
57
       * only do splitting if input is large enough so that last chunks does
58
       * not end up being short.*/
59
0
      if (currlen > 32 * 1024)
60
0
  currlen = 24 * 1024;
61
62
0
      err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen);
63
0
      if (err != 0)
64
0
  return err;
65
66
0
      err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, outbuf,
67
0
            currlen);
68
0
      if (err != 0)
69
0
  return err;
70
71
0
      outbuf += currlen;
72
0
      inbuf += currlen;
73
0
      outbuflen -= currlen;
74
0
      inbuflen -= currlen;
75
0
    }
76
77
0
  return 0;
78
0
}
79
80
81
gcry_err_code_t
82
_gcry_cipher_eax_decrypt (gcry_cipher_hd_t c,
83
                          byte *outbuf, size_t outbuflen,
84
                          const byte *inbuf, size_t inbuflen)
85
0
{
86
0
  gcry_err_code_t err;
87
88
0
  if (outbuflen < inbuflen)
89
0
    return GPG_ERR_BUFFER_TOO_SHORT;
90
0
  if (c->marks.tag)
91
0
    return GPG_ERR_INV_STATE;
92
93
0
  if (!c->marks.iv)
94
0
    {
95
0
      err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
96
0
      if (err != 0)
97
0
  return err;
98
0
    }
99
100
0
  while (inbuflen)
101
0
    {
102
0
      size_t currlen = inbuflen;
103
104
      /* Since checksumming is done before decryption, process input in 24KiB
105
       * chunks to keep data loaded in L1 cache for decryption.  However only
106
       * do splitting if input is large enough so that last chunks does not
107
       * end up being short. */
108
0
      if (currlen > 32 * 1024)
109
0
  currlen = 24 * 1024;
110
111
0
      err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, inbuf,
112
0
            currlen);
113
0
      if (err != 0)
114
0
  return err;
115
116
0
      err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen);
117
0
      if (err != 0)
118
0
  return err;
119
120
0
      outbuf += currlen;
121
0
      inbuf += currlen;
122
0
      outbuflen -= currlen;
123
0
      inbuflen -= currlen;
124
0
    }
125
126
0
  return 0;
127
0
}
128
129
130
gcry_err_code_t
131
_gcry_cipher_eax_authenticate (gcry_cipher_hd_t c,
132
                               const byte * aadbuf, size_t aadbuflen)
133
0
{
134
0
  gcry_err_code_t err;
135
136
0
  if (c->marks.tag)
137
0
    return GPG_ERR_INV_STATE;
138
139
0
  if (!c->marks.iv)
140
0
    {
141
0
      err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
142
0
      if (err != 0)
143
0
  return err;
144
0
    }
145
146
0
  return _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, aadbuf, aadbuflen);
147
0
}
148
149
150
gcry_err_code_t
151
_gcry_cipher_eax_setkey (gcry_cipher_hd_t c)
152
0
{
153
0
  gcry_err_code_t err;
154
155
0
  err = _gcry_cmac_generate_subkeys (c, &c->u_mode.eax.cmac_header);
156
0
  if (err != 0)
157
0
    return err;
158
159
0
  buf_cpy (c->u_mode.eax.cmac_ciphertext.subkeys,
160
0
     c->u_mode.eax.cmac_header.subkeys,
161
0
     sizeof(c->u_mode.eax.cmac_header.subkeys));
162
163
0
  return 0;
164
0
}
165
166
167
gcry_err_code_t
168
_gcry_cipher_eax_set_nonce (gcry_cipher_hd_t c, const byte *nonce,
169
          size_t noncelen)
170
0
{
171
0
  gcry_cmac_context_t nonce_cmac;
172
0
  unsigned char initbuf[MAX_BLOCKSIZE];
173
0
  gcry_err_code_t err;
174
175
0
  c->marks.iv = 0;
176
0
  c->marks.tag = 0;
177
178
0
  _gcry_cmac_reset (&c->u_mode.eax.cmac_header);
179
0
  _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext);
180
181
  /* Calculate nonce CMAC */
182
183
0
  memset(&nonce_cmac, 0, sizeof(nonce_cmac));
184
0
  memset(&initbuf, 0, sizeof(initbuf));
185
186
0
  buf_cpy (&nonce_cmac.subkeys, c->u_mode.eax.cmac_header.subkeys,
187
0
     sizeof(c->u_mode.eax.cmac_header.subkeys));
188
189
0
  err = _gcry_cmac_write (c, &nonce_cmac, initbuf, c->spec->blocksize);
190
0
  if (err != 0)
191
0
    return err;
192
193
0
  if (noncelen != 0)
194
0
    {
195
0
      err = _gcry_cmac_write (c, &nonce_cmac, nonce, noncelen);
196
0
      if (err != 0)
197
0
        return err;
198
0
    }
199
200
0
  err = _gcry_cmac_final (c, &nonce_cmac);
201
0
  if (err != 0)
202
0
    return err;
203
204
0
  cipher_block_cpy (c->u_iv.iv, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE);
205
0
  cipher_block_cpy (c->u_ctr.ctr, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE);
206
207
0
  wipememory (&nonce_cmac, sizeof(nonce_cmac));
208
209
  /* Prepare header CMAC */
210
211
0
  initbuf[c->spec->blocksize - 1] = 1;
212
0
  err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, initbuf,
213
0
        c->spec->blocksize);
214
0
  if (err != 0)
215
0
    return err;
216
217
  /* Prepare ciphertext CMAC */
218
219
0
  initbuf[c->spec->blocksize - 1] = 2;
220
0
  err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, initbuf,
221
0
        c->spec->blocksize);
222
0
  if (err != 0)
223
0
    return err;
224
225
0
  c->marks.iv = 1;
226
0
  c->marks.tag = 0;
227
228
0
  return 0;
229
0
}
230
231
232
static gcry_err_code_t
233
_gcry_cipher_eax_tag (gcry_cipher_hd_t c,
234
                      byte *outbuf, size_t outbuflen, int check)
235
0
{
236
0
  gcry_err_code_t err;
237
238
0
  if (!c->marks.tag)
239
0
    {
240
0
      err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_header);
241
0
      if (err != 0)
242
0
  return err;
243
244
0
      err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_ciphertext);
245
0
      if (err != 0)
246
0
  return err;
247
248
0
      cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_header.u_iv.iv,
249
0
                          MAX_BLOCKSIZE);
250
0
      cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_ciphertext.u_iv.iv,
251
0
                          MAX_BLOCKSIZE);
252
253
0
      _gcry_cmac_reset (&c->u_mode.eax.cmac_header);
254
0
      _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext);
255
256
0
      c->marks.tag = 1;
257
0
    }
258
259
0
  if (!check)
260
0
    {
261
0
      if (outbuflen > c->spec->blocksize)
262
0
        outbuflen = c->spec->blocksize;
263
264
      /* NB: We already checked that OUTBUF is large enough to hold
265
       * the result or has valid truncated length.  */
266
0
      memcpy (outbuf, c->u_iv.iv, outbuflen);
267
0
    }
268
0
  else
269
0
    {
270
      /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
271
       * and thus we need to compare its length first.  */
272
0
      if (!(outbuflen <= c->spec->blocksize)
273
0
          || !buf_eq_const (outbuf, c->u_iv.iv, outbuflen))
274
0
        return GPG_ERR_CHECKSUM;
275
0
    }
276
277
0
  return 0;
278
0
}
279
280
281
gcry_err_code_t
282
_gcry_cipher_eax_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
283
                          size_t taglen)
284
0
{
285
0
  return _gcry_cipher_eax_tag (c, outtag, taglen, 0);
286
0
}
287
288
gcry_err_code_t
289
_gcry_cipher_eax_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
290
                            size_t taglen)
291
0
{
292
0
  return _gcry_cipher_eax_tag (c, (unsigned char *) intag, taglen, 1);
293
0
}