SHA-512: Add AVX and AVX2 implementations for x86-64
[libgcrypt.git] / cipher / cipher-cmac.c
1 /* cmac.c - CMAC, Cipher-based MAC.
2  * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
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
25 #include "g10lib.h"
26 #include "cipher.h"
27 #include "cipher-internal.h"
28 #include "bufhelp.h"
29
30
31 #define set_burn(burn, nburn) do { \
32   unsigned int __nburn = (nburn); \
33   (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0)
34
35
36 static void
37 cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
38 {
39   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
40   const unsigned int blocksize = c->spec->blocksize;
41   byte outbuf[MAX_BLOCKSIZE];
42   unsigned int burn = 0;
43   unsigned int nblocks;
44
45   if (!inlen || !inbuf)
46     return;
47
48   /* Last block is needed for cmac_final.  */
49   if (c->unused + inlen <= blocksize)
50     {
51       for (; inlen && c->unused < blocksize; inlen--)
52         c->lastiv[c->unused++] = *inbuf++;
53       return;
54     }
55
56   if (c->unused)
57     {
58       for (; inlen && c->unused < blocksize; inlen--)
59         c->lastiv[c->unused++] = *inbuf++;
60
61       buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
62       set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
63
64       c->unused = 0;
65     }
66
67   if (c->bulk.cbc_enc && inlen > blocksize)
68     {
69       nblocks = inlen / blocksize;
70       nblocks -= (nblocks * blocksize == inlen);
71
72       c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, 1);
73       inbuf += nblocks * blocksize;
74       inlen -= nblocks * blocksize;
75
76       wipememory (outbuf, sizeof (outbuf));
77     }
78   else
79     while (inlen > blocksize)
80       {
81         buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
82         set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
83         inlen -= blocksize;
84         inbuf += blocksize;
85       }
86
87   /* Make sure that last block is passed to cmac_final.  */
88   if (inlen == 0)
89     BUG ();
90
91   for (; inlen && c->unused < blocksize; inlen--)
92     c->lastiv[c->unused++] = *inbuf++;
93
94   if (burn)
95     _gcry_burn_stack (burn + 4 * sizeof (void *));
96 }
97
98
99 static void
100 cmac_generate_subkeys (gcry_cipher_hd_t c)
101 {
102   const unsigned int blocksize = c->spec->blocksize;
103   byte rb, carry, t, bi;
104   unsigned int burn;
105   int i, j;
106   union
107   {
108     size_t _aligned;
109     byte buf[MAX_BLOCKSIZE];
110   } u;
111
112   if (MAX_BLOCKSIZE < blocksize)
113     BUG ();
114
115   /* encrypt zero block */
116   memset (u.buf, 0, blocksize);
117   burn = c->spec->encrypt (&c->context.c, u.buf, u.buf);
118
119   /* Currently supported blocksizes are 16 and 8. */
120   rb = blocksize == 16 ? 0x87 : 0x1B /*blocksize == 8 */ ;
121
122   for (j = 0; j < 2; j++)
123     {
124       /* Generate subkeys K1 and K2 */
125       carry = 0;
126       for (i = blocksize - 1; i >= 0; i--)
127         {
128           bi = u.buf[i];
129           t = carry | (bi << 1);
130           carry = bi >> 7;
131           u.buf[i] = t & 0xff;
132           c->u_mode.cmac.subkeys[j][i] = u.buf[i];
133         }
134       u.buf[blocksize - 1] ^= carry ? rb : 0;
135       c->u_mode.cmac.subkeys[j][blocksize - 1] = u.buf[blocksize - 1];
136     }
137
138   wipememory (&u, sizeof (u));
139   if (burn)
140     _gcry_burn_stack (burn + 4 * sizeof (void *));
141 }
142
143
144 static void
145 cmac_final (gcry_cipher_hd_t c)
146 {
147   const unsigned int blocksize = c->spec->blocksize;
148   unsigned int count = c->unused;
149   unsigned int burn;
150   byte *subkey;
151
152   if (count == blocksize)
153     subkey = c->u_mode.cmac.subkeys[0];        /* K1 */
154   else
155     {
156       subkey = c->u_mode.cmac.subkeys[1];      /* K2 */
157       c->lastiv[count++] = 0x80;
158       while (count < blocksize)
159         c->lastiv[count++] = 0;
160     }
161
162   buf_xor (c->lastiv, c->lastiv, subkey, blocksize);
163
164   buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
165   burn = c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_iv.iv);
166   if (burn)
167     _gcry_burn_stack (burn + 4 * sizeof (void *));
168
169   c->unused = 0;
170 }
171
172
173 static gcry_err_code_t
174 cmac_tag (gcry_cipher_hd_t c, unsigned char *tag, size_t taglen, int check)
175 {
176   if (!tag || taglen == 0 || taglen > c->spec->blocksize)
177     return GPG_ERR_INV_ARG;
178
179   if (!c->u_mode.cmac.tag)
180     {
181       cmac_final (c);
182       c->u_mode.cmac.tag = 1;
183     }
184
185   if (!check)
186     {
187       memcpy (tag, c->u_iv.iv, taglen);
188       return GPG_ERR_NO_ERROR;
189     }
190   else
191     {
192       return buf_eq_const (tag, c->u_iv.iv, taglen) ?
193         GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
194     }
195 }
196
197
198 gcry_err_code_t
199 _gcry_cipher_cmac_authenticate (gcry_cipher_hd_t c,
200                                 const unsigned char *abuf, size_t abuflen)
201 {
202   if (abuflen > 0 && !abuf)
203     return GPG_ERR_INV_ARG;
204   if (c->u_mode.cmac.tag)
205     return GPG_ERR_INV_STATE;
206   /* To support new blocksize, update cmac_generate_subkeys() then add new
207      blocksize here. */
208   if (c->spec->blocksize != 16 && c->spec->blocksize != 8)
209     return GPG_ERR_INV_CIPHER_MODE;
210
211   cmac_write (c, abuf, abuflen);
212
213   return GPG_ERR_NO_ERROR;
214 }
215
216
217 gcry_err_code_t
218 _gcry_cipher_cmac_get_tag (gcry_cipher_hd_t c,
219                            unsigned char *outtag, size_t taglen)
220 {
221   return cmac_tag (c, outtag, taglen, 0);
222 }
223
224
225 gcry_err_code_t
226 _gcry_cipher_cmac_check_tag (gcry_cipher_hd_t c,
227                              const unsigned char *intag, size_t taglen)
228 {
229   return cmac_tag (c, (unsigned char *) intag, taglen, 1);
230 }
231
232 gcry_err_code_t
233 _gcry_cipher_cmac_set_subkeys (gcry_cipher_hd_t c)
234 {
235   cmac_generate_subkeys (c);
236
237   return GPG_ERR_NO_ERROR;
238 }