]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kgssapi/krb5/kcrypto_aes.c
MFV: r360512
[FreeBSD/FreeBSD.git] / sys / kgssapi / krb5 / kcrypto_aes.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5  * Authors: Doug Rabson <dfr@rabson.org>
6  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/kobj.h>
38 #include <sys/mbuf.h>
39 #include <opencrypto/cryptodev.h>
40
41 #include <kgssapi/gssapi.h>
42 #include <kgssapi/gssapi_impl.h>
43
44 #include "kcrypto.h"
45
46 struct aes_state {
47         struct mtx      as_lock;
48         crypto_session_t as_session_aes;
49         crypto_session_t as_session_sha1;
50 };
51
52 static void
53 aes_init(struct krb5_key_state *ks)
54 {
55         struct aes_state *as;
56
57         as = malloc(sizeof(struct aes_state), M_GSSAPI, M_WAITOK|M_ZERO);
58         mtx_init(&as->as_lock, "gss aes lock", NULL, MTX_DEF);
59         ks->ks_priv = as;
60 }
61
62 static void
63 aes_destroy(struct krb5_key_state *ks)
64 {
65         struct aes_state *as = ks->ks_priv;
66
67         if (as->as_session_aes != 0)
68                 crypto_freesession(as->as_session_aes);
69         if (as->as_session_sha1 != 0)
70                 crypto_freesession(as->as_session_sha1);
71         mtx_destroy(&as->as_lock);
72         free(ks->ks_priv, M_GSSAPI);
73 }
74
75 static void
76 aes_set_key(struct krb5_key_state *ks, const void *in)
77 {
78         void *kp = ks->ks_key;
79         struct aes_state *as = ks->ks_priv;
80         struct crypto_session_params csp;
81
82         if (kp != in)
83                 bcopy(in, kp, ks->ks_class->ec_keylen);
84
85         if (as->as_session_aes != 0)
86                 crypto_freesession(as->as_session_aes);
87         if (as->as_session_sha1 != 0)
88                 crypto_freesession(as->as_session_sha1);
89
90         /*
91          * We only want the first 96 bits of the HMAC.
92          */
93         memset(&csp, 0, sizeof(csp));
94         csp.csp_mode = CSP_MODE_DIGEST;
95         csp.csp_auth_alg = CRYPTO_SHA1_HMAC;
96         csp.csp_auth_klen = ks->ks_class->ec_keybits / 8;
97         csp.csp_auth_mlen = 12;
98         csp.csp_auth_key = ks->ks_key;
99         crypto_newsession(&as->as_session_sha1, &csp,
100             CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE);
101
102         memset(&csp, 0, sizeof(csp));
103         csp.csp_mode = CSP_MODE_CIPHER;
104         csp.csp_cipher_alg = CRYPTO_AES_CBC;
105         csp.csp_cipher_klen = ks->ks_class->ec_keybits / 8;
106         csp.csp_cipher_key = ks->ks_key;
107         csp.csp_ivlen = 16;
108         crypto_newsession(&as->as_session_aes, &csp,
109             CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE);
110 }
111
112 static void
113 aes_random_to_key(struct krb5_key_state *ks, const void *in)
114 {
115
116         aes_set_key(ks, in);
117 }
118
119 static int
120 aes_crypto_cb(struct cryptop *crp)
121 {
122         int error;
123         struct aes_state *as = (struct aes_state *) crp->crp_opaque;
124         
125         if (crypto_ses2caps(crp->crp_session) & CRYPTOCAP_F_SYNC)
126                 return (0);
127
128         error = crp->crp_etype;
129         if (error == EAGAIN)
130                 error = crypto_dispatch(crp);
131         mtx_lock(&as->as_lock);
132         if (error || (crp->crp_flags & CRYPTO_F_DONE))
133                 wakeup(crp);
134         mtx_unlock(&as->as_lock);
135
136         return (0);
137 }
138
139 static void
140 aes_encrypt_1(const struct krb5_key_state *ks, int buftype, void *buf,
141     size_t skip, size_t len, void *ivec, bool encrypt)
142 {
143         struct aes_state *as = ks->ks_priv;
144         struct cryptop *crp;
145         int error;
146
147         crp = crypto_getreq(as->as_session_aes, M_WAITOK);
148
149         crp->crp_payload_start = skip;
150         crp->crp_payload_length = len;
151         crp->crp_op = encrypt ? CRYPTO_OP_ENCRYPT : CRYPTO_OP_DECRYPT;
152         crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_IV_SEPARATE;
153         if (ivec) {
154                 memcpy(crp->crp_iv, ivec, 16);
155         } else {
156                 memset(crp->crp_iv, 0, 16);
157         }
158
159         crp->crp_buf_type = buftype;
160         crp->crp_buf = buf;
161         crp->crp_ilen = skip + len;
162         crp->crp_opaque = as;
163         crp->crp_callback = aes_crypto_cb;
164
165         error = crypto_dispatch(crp);
166
167         if ((crypto_ses2caps(as->as_session_aes) & CRYPTOCAP_F_SYNC) == 0) {
168                 mtx_lock(&as->as_lock);
169                 if (!error && !(crp->crp_flags & CRYPTO_F_DONE))
170                         error = msleep(crp, &as->as_lock, 0, "gssaes", 0);
171                 mtx_unlock(&as->as_lock);
172         }
173
174         crypto_freereq(crp);
175 }
176
177 static void
178 aes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout,
179     size_t skip, size_t len, void *ivec, size_t ivlen)
180 {
181         size_t blocklen = 16, plen;
182         struct {
183                 uint8_t cn_1[16], cn[16];
184         } last2;
185         int i, off;
186
187         /*
188          * AES encryption with cyphertext stealing:
189          *
190          * CTSencrypt(P[0], ..., P[n], IV, K):
191          *      len = length(P[n])
192          *      (C[0], ..., C[n-2], E[n-1]) =
193          *              CBCencrypt(P[0], ..., P[n-1], IV, K)
194          *      P = pad(P[n], 0, blocksize)
195          *      E[n] = CBCencrypt(P, E[n-1], K);
196          *      C[n-1] = E[n]
197          *      C[n] = E[n-1]{0..len-1}
198          */
199         plen = len % blocklen;
200         if (len == blocklen) {
201                 /*
202                  * Note: caller will ensure len >= blocklen.
203                  */
204                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
205                     true);
206         } else if (plen == 0) {
207                 /*
208                  * This is equivalent to CBC mode followed by swapping
209                  * the last two blocks. We assume that neither of the
210                  * last two blocks cross iov boundaries.
211                  */
212                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
213                     true);
214                 off = skip + len - 2 * blocklen;
215                 m_copydata(inout, off, 2 * blocklen, (void*) &last2);
216                 m_copyback(inout, off, blocklen, last2.cn);
217                 m_copyback(inout, off + blocklen, blocklen, last2.cn_1);
218         } else {
219                 /*
220                  * This is the difficult case. We encrypt all but the
221                  * last partial block first. We then create a padded
222                  * copy of the last block and encrypt that using the
223                  * second to last encrypted block as IV. Once we have
224                  * the encrypted versions of the last two blocks, we
225                  * reshuffle to create the final result.
226                  */
227                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len - plen,
228                     ivec, true);
229
230                 /*
231                  * Copy out the last two blocks, pad the last block
232                  * and encrypt it. Rearrange to get the final
233                  * result. The cyphertext for cn_1 is in cn. The
234                  * cyphertext for cn is the first plen bytes of what
235                  * is in cn_1 now.
236                  */
237                 off = skip + len - blocklen - plen;
238                 m_copydata(inout, off, blocklen + plen, (void*) &last2);
239                 for (i = plen; i < blocklen; i++)
240                         last2.cn[i] = 0;
241                 aes_encrypt_1(ks, CRYPTO_BUF_CONTIG, last2.cn, 0, blocklen,
242                     last2.cn_1, true);
243                 m_copyback(inout, off, blocklen, last2.cn);
244                 m_copyback(inout, off + blocklen, plen, last2.cn_1);
245         }
246 }
247
248 static void
249 aes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout,
250     size_t skip, size_t len, void *ivec, size_t ivlen)
251 {
252         size_t blocklen = 16, plen;
253         struct {
254                 uint8_t cn_1[16], cn[16];
255         } last2;
256         int i, off, t;
257
258         /*
259          * AES decryption with cyphertext stealing:
260          *
261          * CTSencrypt(C[0], ..., C[n], IV, K):
262          *      len = length(C[n])
263          *      E[n] = C[n-1]
264          *      X = decrypt(E[n], K)
265          *      P[n] = (X ^ C[n]){0..len-1}
266          *      E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]}
267          *      (P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K)
268          */
269         plen = len % blocklen;
270         if (len == blocklen) {
271                 /*
272                  * Note: caller will ensure len >= blocklen.
273                  */
274                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
275                     false);
276         } else if (plen == 0) {
277                 /*
278                  * This is equivalent to CBC mode followed by swapping
279                  * the last two blocks.
280                  */
281                 off = skip + len - 2 * blocklen;
282                 m_copydata(inout, off, 2 * blocklen, (void*) &last2);
283                 m_copyback(inout, off, blocklen, last2.cn);
284                 m_copyback(inout, off + blocklen, blocklen, last2.cn_1);
285                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
286                     false);
287         } else {
288                 /*
289                  * This is the difficult case. We first decrypt the
290                  * second to last block with a zero IV to make X. The
291                  * plaintext for the last block is the XOR of X and
292                  * the last cyphertext block.
293                  *
294                  * We derive a new cypher text for the second to last
295                  * block by mixing the unused bytes of X with the last
296                  * cyphertext block. The result of that can be
297                  * decrypted with the rest in CBC mode.
298                  */
299                 off = skip + len - plen - blocklen;
300                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, off, blocklen,
301                     NULL, false);
302                 m_copydata(inout, off, blocklen + plen, (void*) &last2);
303
304                 for (i = 0; i < plen; i++) {
305                         t = last2.cn[i];
306                         last2.cn[i] ^= last2.cn_1[i];
307                         last2.cn_1[i] = t;
308                 }
309
310                 m_copyback(inout, off, blocklen + plen, (void*) &last2);
311                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len - plen,
312                     ivec, false);
313         }
314
315 }
316
317 static void
318 aes_checksum(const struct krb5_key_state *ks, int usage,
319     struct mbuf *inout, size_t skip, size_t inlen, size_t outlen)
320 {
321         struct aes_state *as = ks->ks_priv;
322         struct cryptop *crp;
323         int error;
324
325         crp = crypto_getreq(as->as_session_sha1, M_WAITOK);
326
327         crp->crp_payload_start = skip;
328         crp->crp_payload_length = inlen;
329         crp->crp_digest_start = skip + inlen;
330         crp->crp_flags = CRYPTO_F_CBIFSYNC;
331         crp->crp_buf_type = CRYPTO_BUF_MBUF;
332         crp->crp_mbuf = inout;
333         crp->crp_ilen = skip + inlen + 12;
334         crp->crp_opaque = as;
335         crp->crp_callback = aes_crypto_cb;
336
337         error = crypto_dispatch(crp);
338
339         if ((crypto_ses2caps(as->as_session_sha1) & CRYPTOCAP_F_SYNC) == 0) {
340                 mtx_lock(&as->as_lock);
341                 if (!error && !(crp->crp_flags & CRYPTO_F_DONE))
342                         error = msleep(crp, &as->as_lock, 0, "gssaes", 0);
343                 mtx_unlock(&as->as_lock);
344         }
345
346         crypto_freereq(crp);
347 }
348
349 struct krb5_encryption_class krb5_aes128_encryption_class = {
350         "aes128-cts-hmac-sha1-96", /* name */
351         ETYPE_AES128_CTS_HMAC_SHA1_96, /* etype */
352         EC_DERIVED_KEYS,        /* flags */
353         16,                     /* blocklen */
354         1,                      /* msgblocklen */
355         12,                     /* checksumlen */
356         128,                    /* keybits */
357         16,                     /* keylen */
358         aes_init,
359         aes_destroy,
360         aes_set_key,
361         aes_random_to_key,
362         aes_encrypt,
363         aes_decrypt,
364         aes_checksum
365 };
366
367 struct krb5_encryption_class krb5_aes256_encryption_class = {
368         "aes256-cts-hmac-sha1-96", /* name */
369         ETYPE_AES256_CTS_HMAC_SHA1_96, /* etype */
370         EC_DERIVED_KEYS,        /* flags */
371         16,                     /* blocklen */
372         1,                      /* msgblocklen */
373         12,                     /* checksumlen */
374         256,                    /* keybits */
375         32,                     /* keylen */
376         aes_init,
377         aes_destroy,
378         aes_set_key,
379         aes_random_to_key,
380         aes_encrypt,
381         aes_decrypt,
382         aes_checksum
383 };