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