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