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