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