The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kgssapi/krb5/kcrypto_aes.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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_SESS_SYNC(crp->crp_session))
  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         if (buftype == CRYPTO_BUF_MBUF)
  160                 crypto_use_mbuf(crp, buf);
  161         else
  162                 crypto_use_buf(crp, buf, skip + len);
  163         crp->crp_opaque = as;
  164         crp->crp_callback = aes_crypto_cb;
  165 
  166         error = crypto_dispatch(crp);
  167 
  168         if (!CRYPTO_SESS_SYNC(as->as_session_aes)) {
  169                 mtx_lock(&as->as_lock);
  170                 if (!error && !(crp->crp_flags & CRYPTO_F_DONE))
  171                         error = msleep(crp, &as->as_lock, 0, "gssaes", 0);
  172                 mtx_unlock(&as->as_lock);
  173         }
  174 
  175         crypto_freereq(crp);
  176 }
  177 
  178 static void
  179 aes_encrypt(const struct krb5_key_state *ks, struct mbuf *inout,
  180     size_t skip, size_t len, void *ivec, size_t ivlen)
  181 {
  182         size_t blocklen = 16, plen;
  183         struct {
  184                 uint8_t cn_1[16], cn[16];
  185         } last2;
  186         int i, off;
  187 
  188         /*
  189          * AES encryption with cyphertext stealing:
  190          *
  191          * CTSencrypt(P[0], ..., P[n], IV, K):
  192          *      len = length(P[n])
  193          *      (C[0], ..., C[n-2], E[n-1]) =
  194          *              CBCencrypt(P[0], ..., P[n-1], IV, K)
  195          *      P = pad(P[n], 0, blocksize)
  196          *      E[n] = CBCencrypt(P, E[n-1], K);
  197          *      C[n-1] = E[n]
  198          *      C[n] = E[n-1]{0..len-1}
  199          */
  200         plen = len % blocklen;
  201         if (len == blocklen) {
  202                 /*
  203                  * Note: caller will ensure len >= blocklen.
  204                  */
  205                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
  206                     true);
  207         } else if (plen == 0) {
  208                 /*
  209                  * This is equivalent to CBC mode followed by swapping
  210                  * the last two blocks. We assume that neither of the
  211                  * last two blocks cross iov boundaries.
  212                  */
  213                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
  214                     true);
  215                 off = skip + len - 2 * blocklen;
  216                 m_copydata(inout, off, 2 * blocklen, (void*) &last2);
  217                 m_copyback(inout, off, blocklen, last2.cn);
  218                 m_copyback(inout, off + blocklen, blocklen, last2.cn_1);
  219         } else {
  220                 /*
  221                  * This is the difficult case. We encrypt all but the
  222                  * last partial block first. We then create a padded
  223                  * copy of the last block and encrypt that using the
  224                  * second to last encrypted block as IV. Once we have
  225                  * the encrypted versions of the last two blocks, we
  226                  * reshuffle to create the final result.
  227                  */
  228                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len - plen,
  229                     ivec, true);
  230 
  231                 /*
  232                  * Copy out the last two blocks, pad the last block
  233                  * and encrypt it. Rearrange to get the final
  234                  * result. The cyphertext for cn_1 is in cn. The
  235                  * cyphertext for cn is the first plen bytes of what
  236                  * is in cn_1 now.
  237                  */
  238                 off = skip + len - blocklen - plen;
  239                 m_copydata(inout, off, blocklen + plen, (void*) &last2);
  240                 for (i = plen; i < blocklen; i++)
  241                         last2.cn[i] = 0;
  242                 aes_encrypt_1(ks, CRYPTO_BUF_CONTIG, last2.cn, 0, blocklen,
  243                     last2.cn_1, true);
  244                 m_copyback(inout, off, blocklen, last2.cn);
  245                 m_copyback(inout, off + blocklen, plen, last2.cn_1);
  246         }
  247 }
  248 
  249 static void
  250 aes_decrypt(const struct krb5_key_state *ks, struct mbuf *inout,
  251     size_t skip, size_t len, void *ivec, size_t ivlen)
  252 {
  253         size_t blocklen = 16, plen;
  254         struct {
  255                 uint8_t cn_1[16], cn[16];
  256         } last2;
  257         int i, off, t;
  258 
  259         /*
  260          * AES decryption with cyphertext stealing:
  261          *
  262          * CTSencrypt(C[0], ..., C[n], IV, K):
  263          *      len = length(C[n])
  264          *      E[n] = C[n-1]
  265          *      X = decrypt(E[n], K)
  266          *      P[n] = (X ^ C[n]){0..len-1}
  267          *      E[n-1] = {C[n,0],...,C[n,len-1],X[len],...,X[blocksize-1]}
  268          *      (P[0],...,P[n-1]) = CBCdecrypt(C[0],...,C[n-2],E[n-1], IV, K)
  269          */
  270         plen = len % blocklen;
  271         if (len == blocklen) {
  272                 /*
  273                  * Note: caller will ensure len >= blocklen.
  274                  */
  275                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
  276                     false);
  277         } else if (plen == 0) {
  278                 /*
  279                  * This is equivalent to CBC mode followed by swapping
  280                  * the last two blocks.
  281                  */
  282                 off = skip + len - 2 * blocklen;
  283                 m_copydata(inout, off, 2 * blocklen, (void*) &last2);
  284                 m_copyback(inout, off, blocklen, last2.cn);
  285                 m_copyback(inout, off + blocklen, blocklen, last2.cn_1);
  286                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len, ivec,
  287                     false);
  288         } else {
  289                 /*
  290                  * This is the difficult case. We first decrypt the
  291                  * second to last block with a zero IV to make X. The
  292                  * plaintext for the last block is the XOR of X and
  293                  * the last cyphertext block.
  294                  *
  295                  * We derive a new cypher text for the second to last
  296                  * block by mixing the unused bytes of X with the last
  297                  * cyphertext block. The result of that can be
  298                  * decrypted with the rest in CBC mode.
  299                  */
  300                 off = skip + len - plen - blocklen;
  301                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, off, blocklen,
  302                     NULL, false);
  303                 m_copydata(inout, off, blocklen + plen, (void*) &last2);
  304 
  305                 for (i = 0; i < plen; i++) {
  306                         t = last2.cn[i];
  307                         last2.cn[i] ^= last2.cn_1[i];
  308                         last2.cn_1[i] = t;
  309                 }
  310 
  311                 m_copyback(inout, off, blocklen + plen, (void*) &last2);
  312                 aes_encrypt_1(ks, CRYPTO_BUF_MBUF, inout, skip, len - plen,
  313                     ivec, false);
  314         }
  315 
  316 }
  317 
  318 static void
  319 aes_checksum(const struct krb5_key_state *ks, int usage,
  320     struct mbuf *inout, size_t skip, size_t inlen, size_t outlen)
  321 {
  322         struct aes_state *as = ks->ks_priv;
  323         struct cryptop *crp;
  324         int error;
  325 
  326         crp = crypto_getreq(as->as_session_sha1, M_WAITOK);
  327 
  328         crp->crp_payload_start = skip;
  329         crp->crp_payload_length = inlen;
  330         crp->crp_digest_start = skip + inlen;
  331         crp->crp_flags = CRYPTO_F_CBIFSYNC;
  332         crypto_use_mbuf(crp, inout);
  333         crp->crp_opaque = as;
  334         crp->crp_callback = aes_crypto_cb;
  335 
  336         error = crypto_dispatch(crp);
  337 
  338         if (!CRYPTO_SESS_SYNC(as->as_session_sha1)) {
  339                 mtx_lock(&as->as_lock);
  340                 if (!error && !(crp->crp_flags & CRYPTO_F_DONE))
  341                         error = msleep(crp, &as->as_lock, 0, "gssaes", 0);
  342                 mtx_unlock(&as->as_lock);
  343         }
  344 
  345         crypto_freereq(crp);
  346 }
  347 
  348 struct krb5_encryption_class krb5_aes128_encryption_class = {
  349         "aes128-cts-hmac-sha1-96", /* name */
  350         ETYPE_AES128_CTS_HMAC_SHA1_96, /* etype */
  351         EC_DERIVED_KEYS,        /* flags */
  352         16,                     /* blocklen */
  353         1,                      /* msgblocklen */
  354         12,                     /* checksumlen */
  355         128,                    /* keybits */
  356         16,                     /* keylen */
  357         aes_init,
  358         aes_destroy,
  359         aes_set_key,
  360         aes_random_to_key,
  361         aes_encrypt,
  362         aes_decrypt,
  363         aes_checksum
  364 };
  365 
  366 struct krb5_encryption_class krb5_aes256_encryption_class = {
  367         "aes256-cts-hmac-sha1-96", /* name */
  368         ETYPE_AES256_CTS_HMAC_SHA1_96, /* etype */
  369         EC_DERIVED_KEYS,        /* flags */
  370         16,                     /* blocklen */
  371         1,                      /* msgblocklen */
  372         12,                     /* checksumlen */
  373         256,                    /* keybits */
  374         32,                     /* keylen */
  375         aes_init,
  376         aes_destroy,
  377         aes_set_key,
  378         aes_random_to_key,
  379         aes_encrypt,
  380         aes_decrypt,
  381         aes_checksum
  382 };

Cache object: 14b58b04b01388ec8b7198d989013062


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.