Replace ath based mutexes by gpgrt based locks.
[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 "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 _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   if (c->spec->blocksize != 16)
51     return GPG_ERR_INV_LENGTH;
52
53   /* The output buffer must be able to hold the input data plus one
54      additional block.  */
55   if (outbuflen < inbuflen + 8)
56     return GPG_ERR_BUFFER_TOO_SHORT;
57   /* Input data must be multiple of 64 bits.  */
58   if (inbuflen % 8)
59     return GPG_ERR_INV_ARG;
60
61   n = inbuflen / 8;
62
63   /* We need at least two 64 bit blocks.  */
64   if (n < 2)
65     return GPG_ERR_INV_ARG;
66
67   burn = 0;
68
69   r = outbuf;
70   a = outbuf;  /* We store A directly in OUTBUF.  */
71   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   if (c->marks.iv)
76     memcpy (a, c->u_iv.iv, 8);
77   else
78     memset (a, 0xa6, 8);
79
80   /* Copy the inbuf to the outbuf. */
81   memmove (r+8, inbuf, inbuflen);
82
83   memset (t, 0, sizeof t); /* t := 0.  */
84
85   for (j = 0; j <= 5; j++)
86     {
87       for (i = 1; i <= n; i++)
88         {
89           /* B := AES_k( A | R[i] ) */
90           memcpy (b, a, 8);
91           memcpy (b+8, r+i*8, 8);
92           nburn = c->spec->encrypt (&c->context.c, b, b);
93           burn = nburn > burn ? nburn : burn;
94           /* t := t + 1  */
95           for (x = 7; x >= 0; x--)
96             {
97               t[x]++;
98               if (t[x])
99                 break;
100             }
101           /* A := MSB_64(B) ^ t */
102           buf_xor(a, b, t, 8);
103           /* R[i] := LSB_64(B) */
104           memcpy (r+i*8, b+8, 8);
105         }
106    }
107
108   if (burn > 0)
109     _gcry_burn_stack (burn + 4 * sizeof(void *));
110
111   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 _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   if (c->spec->blocksize != 16)
133     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   if (outbuflen + 8  < inbuflen)
139     return GPG_ERR_BUFFER_TOO_SHORT;
140   /* Input data must be multiple of 64 bits.  */
141   if (inbuflen % 8)
142     return GPG_ERR_INV_ARG;
143
144   n = inbuflen / 8;
145
146   /* We need at least three 64 bit blocks.  */
147   if (n < 3)
148     return GPG_ERR_INV_ARG;
149
150   burn = 0;
151
152   r = outbuf;
153   a = c->lastiv;  /* We use c->LASTIV as buffer for A.  */
154   b = c->u_ctr.ctr;     /* B is also used to concatenate stuff.  */
155
156   /* Copy the inbuf to the outbuf and save A. */
157   memcpy (a, inbuf, 8);
158   memmove (r, inbuf+8, inbuflen-8);
159   n--; /* Reduce to actual number of data blocks.  */
160
161   /* t := 6 * n  */
162   i = n * 6;  /* The range is valid because: n = inbuflen / 8 - 1.  */
163   for (x=0; x < 8 && x < sizeof (i); x++)
164     t[7-x] = i >> (8*x);
165   for (; x < 8; x++)
166     t[7-x] = 0;
167
168   for (j = 5; j >= 0; j--)
169     {
170       for (i = n; i >= 1; i--)
171         {
172           /* B := AES_k^1( (A ^ t)| R[i] ) */
173           buf_xor(b, a, t, 8);
174           memcpy (b+8, r+(i-1)*8, 8);
175           nburn = c->spec->decrypt (&c->context.c, b, b);
176           burn = nburn > burn ? nburn : burn;
177           /* t := t - 1  */
178           for (x = 7; x >= 0; x--)
179             {
180               t[x]--;
181               if (t[x] != 0xff)
182                 break;
183             }
184           /* A := MSB_64(B) */
185           memcpy (a, b, 8);
186           /* R[i] := LSB_64(B) */
187           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   if (c->marks.iv)
194     j = memcmp (a, c->u_iv.iv, 8);
195   else
196     {
197       for (j=0, x=0; x < 8; x++)
198         if (a[x] != 0xa6)
199           {
200             j=1;
201             break;
202           }
203     }
204
205   if (burn > 0)
206     _gcry_burn_stack (burn + 4 * sizeof(void *));
207
208   return j? GPG_ERR_CHECKSUM : 0;
209 }