Line data Source code
1 : /* cmac.c - CMAC, Cipher-based MAC.
2 : * Copyright (C) 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 1245942 : cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
38 : {
39 1245942 : gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
40 1245942 : const unsigned int blocksize = c->spec->blocksize;
41 : byte outbuf[MAX_BLOCKSIZE];
42 1245942 : unsigned int burn = 0;
43 : unsigned int nblocks;
44 :
45 : /* Tell compiler that we require a cipher with a 64bit or 128 bit block
46 : * length, to allow better optimization of this function. */
47 1245942 : if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
48 189567 : return;
49 :
50 1245942 : if (!inlen || !inbuf)
51 12 : return;
52 :
53 : /* Last block is needed for cmac_final. */
54 1245930 : if (c->unused + inlen <= blocksize)
55 : {
56 2079271 : for (; inlen && c->unused < blocksize; inlen--)
57 1889716 : c->lastiv[c->unused++] = *inbuf++;
58 189555 : return;
59 : }
60 :
61 1056375 : if (c->unused)
62 : {
63 4616083 : for (; inlen && c->unused < blocksize; inlen--)
64 3569694 : c->lastiv[c->unused++] = *inbuf++;
65 :
66 1046389 : buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
67 1046389 : set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
68 :
69 1046389 : c->unused = 0;
70 : }
71 :
72 1056375 : if (c->bulk.cbc_enc && inlen > blocksize)
73 : {
74 16988 : nblocks = inlen / blocksize;
75 16988 : nblocks -= (nblocks * blocksize == inlen);
76 :
77 16988 : c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, 1);
78 16988 : inbuf += nblocks * blocksize;
79 16988 : inlen -= nblocks * blocksize;
80 :
81 16988 : wipememory (outbuf, sizeof (outbuf));
82 : }
83 : else
84 5969842 : while (inlen > blocksize)
85 : {
86 3891068 : buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
87 3891068 : set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
88 3891068 : inlen -= blocksize;
89 3891068 : inbuf += blocksize;
90 : }
91 :
92 : /* Make sure that last block is passed to cmac_final. */
93 1056375 : if (inlen == 0)
94 0 : BUG ();
95 :
96 7120501 : for (; inlen && c->unused < blocksize; inlen--)
97 6064126 : c->lastiv[c->unused++] = *inbuf++;
98 :
99 1056375 : if (burn)
100 978916 : _gcry_burn_stack (burn + 4 * sizeof (void *));
101 : }
102 :
103 :
104 : static void
105 124 : cmac_generate_subkeys (gcry_cipher_hd_t c)
106 : {
107 124 : const unsigned int blocksize = c->spec->blocksize;
108 : byte rb, carry, t, bi;
109 : unsigned int burn;
110 : int i, j;
111 : union
112 : {
113 : size_t _aligned;
114 : byte buf[MAX_BLOCKSIZE];
115 : } u;
116 :
117 : /* Tell compiler that we require a cipher with a 64bit or 128 bit block
118 : * length, to allow better optimization of this function. */
119 124 : if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
120 0 : return;
121 :
122 124 : if (MAX_BLOCKSIZE < blocksize)
123 0 : BUG ();
124 :
125 : /* encrypt zero block */
126 124 : memset (u.buf, 0, blocksize);
127 124 : burn = c->spec->encrypt (&c->context.c, u.buf, u.buf);
128 :
129 : /* Currently supported blocksizes are 16 and 8. */
130 124 : rb = blocksize == 16 ? 0x87 : 0x1B /*blocksize == 8 */ ;
131 :
132 372 : for (j = 0; j < 2; j++)
133 : {
134 : /* Generate subkeys K1 and K2 */
135 248 : carry = 0;
136 3480 : for (i = blocksize - 1; i >= 0; i--)
137 : {
138 3232 : bi = u.buf[i];
139 3232 : t = carry | (bi << 1);
140 3232 : carry = bi >> 7;
141 3232 : u.buf[i] = t & 0xff;
142 3232 : c->u_mode.cmac.subkeys[j][i] = u.buf[i];
143 : }
144 248 : u.buf[blocksize - 1] ^= carry ? rb : 0;
145 248 : c->u_mode.cmac.subkeys[j][blocksize - 1] = u.buf[blocksize - 1];
146 : }
147 :
148 124 : wipememory (&u, sizeof (u));
149 124 : if (burn)
150 97 : _gcry_burn_stack (burn + 4 * sizeof (void *));
151 : }
152 :
153 :
154 : static void
155 10869 : cmac_final (gcry_cipher_hd_t c)
156 : {
157 10869 : const unsigned int blocksize = c->spec->blocksize;
158 10869 : unsigned int count = c->unused;
159 : unsigned int burn;
160 : byte *subkey;
161 :
162 : /* Tell compiler that we require a cipher with a 64bit or 128 bit block
163 : * length, to allow better optimization of this function. */
164 10869 : if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
165 0 : return;
166 :
167 10869 : if (count == blocksize)
168 10821 : subkey = c->u_mode.cmac.subkeys[0]; /* K1 */
169 : else
170 : {
171 48 : subkey = c->u_mode.cmac.subkeys[1]; /* K2 */
172 48 : c->lastiv[count++] = 0x80;
173 528 : while (count < blocksize)
174 432 : c->lastiv[count++] = 0;
175 : }
176 :
177 10869 : buf_xor (c->lastiv, c->lastiv, subkey, blocksize);
178 :
179 10869 : buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
180 10869 : burn = c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_iv.iv);
181 10869 : if (burn)
182 8811 : _gcry_burn_stack (burn + 4 * sizeof (void *));
183 :
184 10869 : c->unused = 0;
185 : }
186 :
187 :
188 : static gcry_err_code_t
189 10971 : cmac_tag (gcry_cipher_hd_t c, unsigned char *tag, size_t taglen, int check)
190 : {
191 10971 : if (!tag || taglen == 0 || taglen > c->spec->blocksize)
192 0 : return GPG_ERR_INV_ARG;
193 :
194 10971 : if (!c->u_mode.cmac.tag)
195 : {
196 10869 : cmac_final (c);
197 10869 : c->u_mode.cmac.tag = 1;
198 : }
199 :
200 10971 : if (!check)
201 : {
202 10869 : memcpy (tag, c->u_iv.iv, taglen);
203 10869 : return GPG_ERR_NO_ERROR;
204 : }
205 : else
206 : {
207 102 : return buf_eq_const (tag, c->u_iv.iv, taglen) ?
208 102 : GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
209 : }
210 : }
211 :
212 :
213 : gcry_err_code_t
214 1245942 : _gcry_cipher_cmac_authenticate (gcry_cipher_hd_t c,
215 : const unsigned char *abuf, size_t abuflen)
216 : {
217 1245942 : if (abuflen > 0 && !abuf)
218 0 : return GPG_ERR_INV_ARG;
219 1245942 : if (c->u_mode.cmac.tag)
220 0 : return GPG_ERR_INV_STATE;
221 : /* To support new blocksize, update cmac_generate_subkeys() then add new
222 : blocksize here. */
223 1245942 : if (c->spec->blocksize != 16 && c->spec->blocksize != 8)
224 0 : return GPG_ERR_INV_CIPHER_MODE;
225 :
226 1245942 : cmac_write (c, abuf, abuflen);
227 :
228 1245942 : return GPG_ERR_NO_ERROR;
229 : }
230 :
231 :
232 : gcry_err_code_t
233 10869 : _gcry_cipher_cmac_get_tag (gcry_cipher_hd_t c,
234 : unsigned char *outtag, size_t taglen)
235 : {
236 10869 : return cmac_tag (c, outtag, taglen, 0);
237 : }
238 :
239 :
240 : gcry_err_code_t
241 102 : _gcry_cipher_cmac_check_tag (gcry_cipher_hd_t c,
242 : const unsigned char *intag, size_t taglen)
243 : {
244 102 : return cmac_tag (c, (unsigned char *) intag, taglen, 1);
245 : }
246 :
247 : gcry_err_code_t
248 124 : _gcry_cipher_cmac_set_subkeys (gcry_cipher_hd_t c)
249 : {
250 124 : cmac_generate_subkeys (c);
251 :
252 124 : return GPG_ERR_NO_ERROR;
253 : }
|