/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 | } |