1 /* cipher-aeswrap.c - Generic AESWRAP mode implementation
2 * Copyright (C) 2009, 2011 Free Software Foundation, Inc.
4 * This file is part of Libgcrypt.
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.
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.
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/>.
30 #include "./cipher-internal.h"
33 /* Perform the AES-Wrap algorithm as specified by RFC3394. We
34 implement this as a mode usable with any cipher algorithm of
37 _gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c,
38 byte *outbuf, size_t outbuflen,
39 const byte *inbuf, size_t inbuflen )
43 unsigned char *r, *a, *b;
45 unsigned int burn, nburn;
48 #error Invalid block size
50 /* We require a cipher with a 128 bit block length. */
51 if (c->spec->blocksize != 16)
52 return GPG_ERR_INV_LENGTH;
54 /* The output buffer must be able to hold the input data plus one
56 if (outbuflen < inbuflen + 8)
57 return GPG_ERR_BUFFER_TOO_SHORT;
58 /* Input data must be multiple of 64 bits. */
60 return GPG_ERR_INV_ARG;
64 /* We need at least two 64 bit blocks. */
66 return GPG_ERR_INV_ARG;
71 a = outbuf; /* We store A directly in OUTBUF. */
72 b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
74 /* If an IV has been set we use that IV as the Alternative Initial
75 Value; if it has not been set we use the standard value. */
77 memcpy (a, c->u_iv.iv, 8);
81 /* Copy the inbuf to the outbuf. */
82 memmove (r+8, inbuf, inbuflen);
84 memset (t, 0, sizeof t); /* t := 0. */
86 for (j = 0; j <= 5; j++)
88 for (i = 1; i <= n; i++)
90 /* B := AES_k( A | R[i] ) */
92 memcpy (b+8, r+i*8, 8);
93 nburn = c->spec->encrypt (&c->context.c, b, b);
94 burn = nburn > burn ? nburn : burn;
96 for (x = 7; x >= 0; x--)
102 /* A := MSB_64(B) ^ t */
104 /* R[i] := LSB_64(B) */
105 memcpy (r+i*8, b+8, 8);
110 _gcry_burn_stack (burn + 4 * sizeof(void *));
115 /* Perform the AES-Unwrap algorithm as specified by RFC3394. We
116 implement this as a mode usable with any cipher algorithm of
119 _gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c,
120 byte *outbuf, size_t outbuflen,
121 const byte *inbuf, size_t inbuflen)
125 unsigned char *r, *a, *b;
127 unsigned int burn, nburn;
129 #if MAX_BLOCKSIZE < 8
130 #error Invalid block size
132 /* We require a cipher with a 128 bit block length. */
133 if (c->spec->blocksize != 16)
134 return GPG_ERR_INV_LENGTH;
136 /* The output buffer must be able to hold the input data minus one
137 additional block. Fixme: The caller has more restrictive checks
138 - we may want to fix them for this mode. */
139 if (outbuflen + 8 < inbuflen)
140 return GPG_ERR_BUFFER_TOO_SHORT;
141 /* Input data must be multiple of 64 bits. */
143 return GPG_ERR_INV_ARG;
147 /* We need at least three 64 bit blocks. */
149 return GPG_ERR_INV_ARG;
154 a = c->lastiv; /* We use c->LASTIV as buffer for A. */
155 b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
157 /* Copy the inbuf to the outbuf and save A. */
158 memcpy (a, inbuf, 8);
159 memmove (r, inbuf+8, inbuflen-8);
160 n--; /* Reduce to actual number of data blocks. */
163 i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */
164 for (x=0; x < 8 && x < sizeof (i); x++)
169 for (j = 5; j >= 0; j--)
171 for (i = n; i >= 1; i--)
173 /* B := AES_k^1( (A ^ t)| R[i] ) */
175 memcpy (b+8, r+(i-1)*8, 8);
176 nburn = c->spec->decrypt (&c->context.c, b, b);
177 burn = nburn > burn ? nburn : burn;
179 for (x = 7; x >= 0; x--)
187 /* R[i] := LSB_64(B) */
188 memcpy (r+(i-1)*8, b+8, 8);
192 /* If an IV has been set we compare against this Alternative Initial
193 Value; if it has not been set we compare against the standard IV. */
195 j = memcmp (a, c->u_iv.iv, 8);
198 for (j=0, x=0; x < 8; x++)
207 _gcry_burn_stack (burn + 4 * sizeof(void *));
209 return j? GPG_ERR_CHECKSUM : 0;