Line data Source code
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 :
32 : /* Perform the AES-Wrap algorithm as specified by RFC3394. We
33 : implement this as a mode usable with any cipher algorithm of
34 : blocksize 128. */
35 : gcry_err_code_t
36 6 : _gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c,
37 : byte *outbuf, size_t outbuflen,
38 : const byte *inbuf, size_t inbuflen )
39 : {
40 : int j, x;
41 : size_t n, i;
42 : unsigned char *r, *a, *b;
43 : unsigned char t[8];
44 : unsigned int burn, nburn;
45 :
46 : #if MAX_BLOCKSIZE < 8
47 : #error Invalid block size
48 : #endif
49 : /* We require a cipher with a 128 bit block length. */
50 6 : if (c->spec->blocksize != 16)
51 0 : return GPG_ERR_INV_LENGTH;
52 :
53 : /* The output buffer must be able to hold the input data plus one
54 : additional block. */
55 6 : if (outbuflen < inbuflen + 8)
56 0 : return GPG_ERR_BUFFER_TOO_SHORT;
57 : /* Input data must be multiple of 64 bits. */
58 6 : if (inbuflen % 8)
59 0 : return GPG_ERR_INV_ARG;
60 :
61 6 : n = inbuflen / 8;
62 :
63 : /* We need at least two 64 bit blocks. */
64 6 : if (n < 2)
65 0 : return GPG_ERR_INV_ARG;
66 :
67 6 : burn = 0;
68 :
69 6 : r = outbuf;
70 6 : a = outbuf; /* We store A directly in OUTBUF. */
71 6 : b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
72 :
73 : /* If an IV has been set we use that IV as the Alternative Initial
74 : Value; if it has not been set we use the standard value. */
75 6 : if (c->marks.iv)
76 0 : memcpy (a, c->u_iv.iv, 8);
77 : else
78 6 : memset (a, 0xa6, 8);
79 :
80 : /* Copy the inbuf to the outbuf. */
81 6 : memmove (r+8, inbuf, inbuflen);
82 :
83 6 : memset (t, 0, sizeof t); /* t := 0. */
84 :
85 42 : for (j = 0; j <= 5; j++)
86 : {
87 132 : for (i = 1; i <= n; i++)
88 : {
89 : /* B := AES_k( A | R[i] ) */
90 96 : memcpy (b, a, 8);
91 96 : memcpy (b+8, r+i*8, 8);
92 96 : nburn = c->spec->encrypt (&c->context.c, b, b);
93 96 : burn = nburn > burn ? nburn : burn;
94 : /* t := t + 1 */
95 96 : for (x = 7; x >= 0; x--)
96 : {
97 96 : t[x]++;
98 96 : if (t[x])
99 96 : break;
100 : }
101 : /* A := MSB_64(B) ^ t */
102 96 : buf_xor(a, b, t, 8);
103 : /* R[i] := LSB_64(B) */
104 96 : memcpy (r+i*8, b+8, 8);
105 : }
106 : }
107 :
108 6 : if (burn > 0)
109 0 : _gcry_burn_stack (burn + 4 * sizeof(void *));
110 :
111 6 : return 0;
112 : }
113 :
114 : /* Perform the AES-Unwrap algorithm as specified by RFC3394. We
115 : implement this as a mode usable with any cipher algorithm of
116 : blocksize 128. */
117 : gcry_err_code_t
118 18 : _gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c,
119 : byte *outbuf, size_t outbuflen,
120 : const byte *inbuf, size_t inbuflen)
121 : {
122 : int j, x;
123 : size_t n, i;
124 : unsigned char *r, *a, *b;
125 : unsigned char t[8];
126 : unsigned int burn, nburn;
127 :
128 : #if MAX_BLOCKSIZE < 8
129 : #error Invalid block size
130 : #endif
131 : /* We require a cipher with a 128 bit block length. */
132 18 : if (c->spec->blocksize != 16)
133 0 : return GPG_ERR_INV_LENGTH;
134 :
135 : /* The output buffer must be able to hold the input data minus one
136 : additional block. Fixme: The caller has more restrictive checks
137 : - we may want to fix them for this mode. */
138 18 : if (outbuflen + 8 < inbuflen)
139 0 : return GPG_ERR_BUFFER_TOO_SHORT;
140 : /* Input data must be multiple of 64 bits. */
141 18 : if (inbuflen % 8)
142 0 : return GPG_ERR_INV_ARG;
143 :
144 18 : n = inbuflen / 8;
145 :
146 : /* We need at least three 64 bit blocks. */
147 18 : if (n < 3)
148 0 : return GPG_ERR_INV_ARG;
149 :
150 18 : burn = 0;
151 :
152 18 : r = outbuf;
153 18 : a = c->lastiv; /* We use c->LASTIV as buffer for A. */
154 18 : b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
155 :
156 : /* Copy the inbuf to the outbuf and save A. */
157 18 : memcpy (a, inbuf, 8);
158 18 : memmove (r, inbuf+8, inbuflen-8);
159 18 : n--; /* Reduce to actual number of data blocks. */
160 :
161 : /* t := 6 * n */
162 18 : i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */
163 162 : for (x=0; x < 8 && x < sizeof (i); x++)
164 144 : t[7-x] = i >> (8*x);
165 18 : for (; x < 8; x++)
166 0 : t[7-x] = 0;
167 :
168 126 : for (j = 5; j >= 0; j--)
169 : {
170 396 : for (i = n; i >= 1; i--)
171 : {
172 : /* B := AES_k^1( (A ^ t)| R[i] ) */
173 288 : buf_xor(b, a, t, 8);
174 288 : memcpy (b+8, r+(i-1)*8, 8);
175 288 : nburn = c->spec->decrypt (&c->context.c, b, b);
176 288 : burn = nburn > burn ? nburn : burn;
177 : /* t := t - 1 */
178 288 : for (x = 7; x >= 0; x--)
179 : {
180 288 : t[x]--;
181 288 : if (t[x] != 0xff)
182 288 : break;
183 : }
184 : /* A := MSB_64(B) */
185 288 : memcpy (a, b, 8);
186 : /* R[i] := LSB_64(B) */
187 288 : memcpy (r+(i-1)*8, b+8, 8);
188 : }
189 : }
190 :
191 : /* If an IV has been set we compare against this Alternative Initial
192 : Value; if it has not been set we compare against the standard IV. */
193 18 : if (c->marks.iv)
194 0 : j = memcmp (a, c->u_iv.iv, 8);
195 : else
196 : {
197 162 : for (j=0, x=0; x < 8; x++)
198 144 : if (a[x] != 0xa6)
199 : {
200 0 : j=1;
201 0 : break;
202 : }
203 : }
204 :
205 18 : if (burn > 0)
206 0 : _gcry_burn_stack (burn + 4 * sizeof(void *));
207 :
208 18 : return j? GPG_ERR_CHECKSUM : 0;
209 : }
|