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/netinet6/esp_aesctr.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 /*      $NetBSD: esp_aesctr.c,v 1.1.2.1 2005/10/11 16:29:31 riz Exp $   */
    2 /*      $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $      */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, 1998 and 2003 WIDE Project.
    6  * All rights reserved.
    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  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: esp_aesctr.c,v 1.1.2.1 2005/10/11 16:29:31 riz Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/socket.h>
   39 #include <sys/queue.h>
   40 #include <sys/syslog.h>
   41 #include <sys/mbuf.h>
   42 
   43 #include <net/if.h>
   44 #include <net/route.h>
   45 
   46 #include <netinet/in.h>
   47 
   48 #include <netinet6/ipsec.h>
   49 #include <netinet6/esp.h>
   50 #include <netinet6/esp_aesctr.h>
   51 
   52 #include <netkey/key.h>
   53 
   54 #include <crypto/rijndael/rijndael.h>
   55 
   56 #include <net/net_osdep.h>
   57 
   58 #define AES_BLOCKSIZE   16
   59 
   60 #define NONCESIZE       4
   61 union cblock {
   62         struct {
   63                 u_int8_t nonce[4];
   64                 u_int8_t iv[8];
   65                 u_int32_t ctr;
   66         } v __attribute__((__packed__));
   67         u_int8_t cblock[16];
   68 };
   69 
   70 typedef struct {
   71         u_int32_t       r_ek[(RIJNDAEL_MAXNR+1)*4];
   72         int             r_nr; /* key-length-dependent number of rounds */
   73 } aesctr_ctx;
   74 
   75 int
   76 esp_aesctr_mature(sav)
   77         struct secasvar *sav;
   78 {
   79         int keylen;
   80         const struct esp_algorithm *algo;
   81 
   82         algo = esp_algorithm_lookup(sav->alg_enc);
   83         if (!algo) {
   84                 ipseclog((LOG_ERR,
   85                     "esp_aeesctr_mature %s: unsupported algorithm.\n",
   86                     algo->name));
   87                 return 1;
   88         }
   89 
   90         keylen = sav->key_enc->sadb_key_bits;
   91         if (keylen < algo->keymin || algo->keymax < keylen) {
   92                 ipseclog((LOG_ERR,
   93                     "esp_aesctr_mature %s: invalid key length %d.\n",
   94                     algo->name, sav->key_enc->sadb_key_bits));
   95                 return 1;
   96         }
   97 
   98         /* rijndael key + nonce */
   99         if (!(keylen == 128 + 32 || keylen == 192 + 32 || keylen == 256 + 32)) {
  100                 ipseclog((LOG_ERR,
  101                     "esp_aesctr_mature %s: invalid key length %d.\n",
  102                     algo->name, keylen));
  103                 return 1;
  104         }
  105 
  106         return 0;
  107 }
  108 
  109 size_t
  110 esp_aesctr_schedlen(algo)
  111         const struct esp_algorithm *algo;
  112 {
  113 
  114         return sizeof(aesctr_ctx);
  115 }
  116 
  117 int
  118 esp_aesctr_schedule(algo, sav)
  119         const struct esp_algorithm *algo;
  120         struct secasvar *sav;
  121 {
  122         aesctr_ctx *ctx;
  123         int keylen;
  124 
  125         /* SA key = AES key + nonce */
  126         keylen = _KEYLEN(sav->key_enc) * 8 - NONCESIZE * 8;
  127 
  128         ctx = (aesctr_ctx *)sav->sched;
  129         if ((ctx->r_nr = rijndaelKeySetupEnc(ctx->r_ek,
  130             (char *)_KEYBUF(sav->key_enc), keylen)) == 0)
  131                 return -1;
  132         return 0;
  133 }
  134 
  135 int
  136 esp_aesctr_decrypt(m, off, sav, algo, ivlen)
  137         struct mbuf *m;
  138         size_t off;
  139         struct secasvar *sav;
  140         const struct esp_algorithm *algo;
  141         int ivlen;
  142 {
  143         struct mbuf *s;
  144         struct mbuf *d, *d0 = NULL, *dp;
  145         int soff, doff; /* offset from the head of chain, to head of this mbuf */
  146         int sn, dn;     /* offset from the head of the mbuf, to meat */
  147         size_t ivoff, bodyoff;
  148         union cblock cblock;
  149         u_int8_t keystream[AES_BLOCKSIZE], *nonce;
  150         u_int32_t ctr;
  151         u_int8_t *ivp;
  152         u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
  153         struct mbuf *scut;
  154         int scutoff;
  155         int i;
  156         int blocklen;
  157         aesctr_ctx *ctx;
  158 
  159         if (ivlen != sav->ivlen) {
  160                 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
  161                     "unsupported ivlen %d\n", algo->name, ivlen));
  162                 goto fail;
  163         }
  164 
  165         /* assumes blocklen == padbound */
  166         blocklen = algo->padbound;
  167 
  168         ivoff = off + sizeof(struct newesp);
  169         bodyoff = off + sizeof(struct newesp) + ivlen;
  170 
  171         /* setup counter block */
  172         nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
  173         bcopy(nonce, cblock.v.nonce, NONCESIZE);
  174         m_copydata(m, ivoff, ivlen, cblock.v.iv);
  175         ctr = 1;
  176 
  177         if (m->m_pkthdr.len < bodyoff) {
  178                 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
  179                     algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
  180                 goto fail;
  181         }
  182         if ((m->m_pkthdr.len - bodyoff) % blocklen) {
  183                 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
  184                     "payload length must be multiple of %d\n",
  185                     algo->name, blocklen));
  186                 goto fail;
  187         }
  188 
  189         s = m;
  190         d = d0 = dp = NULL;
  191         soff = doff = sn = dn = 0;
  192         ivp = sp = NULL;
  193 
  194         /* skip bodyoff */
  195         while (soff < bodyoff) {
  196                 if (soff + s->m_len > bodyoff) {
  197                         sn = bodyoff - soff;
  198                         break;
  199                 }
  200 
  201                 soff += s->m_len;
  202                 s = s->m_next;
  203         }
  204         scut = s;
  205         scutoff = sn;
  206 
  207         /* skip over empty mbuf */
  208         while (s && s->m_len == 0)
  209                 s = s->m_next;
  210 
  211         while (soff < m->m_pkthdr.len) {
  212                 /* source */
  213                 if (sn + blocklen <= s->m_len) {
  214                         /* body is continuous */
  215                         sp = mtod(s, u_int8_t *) + sn;
  216                 } else {
  217                         /* body is non-continuous */
  218                         m_copydata(s, sn, blocklen, (caddr_t)sbuf);
  219                         sp = sbuf;
  220                 }
  221 
  222                 /* destination */
  223                 if (!d || dn + blocklen > d->m_len) {
  224                         if (d)
  225                                 dp = d;
  226                         MGET(d, M_DONTWAIT, MT_DATA);
  227                         i = m->m_pkthdr.len - (soff + sn);
  228                         if (d && i > MLEN) {
  229                                 MCLGET(d, M_DONTWAIT);
  230                                 if ((d->m_flags & M_EXT) == 0) {
  231                                         m_free(d);
  232                                         d = NULL;
  233                                 }
  234                         }
  235                         if (!d) {
  236                                 goto nomem;
  237                         }
  238                         if (!d0)
  239                                 d0 = d;
  240                         if (dp)
  241                                 dp->m_next = d;
  242                         d->m_len = 0;
  243                         d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
  244                         if (d->m_len > i)
  245                                 d->m_len = i;
  246                         dn = 0;
  247                 }
  248 
  249                 /* put counter into counter block */
  250                 cblock.v.ctr = htonl(ctr);
  251 
  252                 /* setup keystream */
  253                 ctx = (aesctr_ctx *)sav->sched;
  254                 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
  255 
  256                 bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
  257                 dst = mtod(d, u_int8_t *) + dn;
  258                 for (i = 0; i < blocklen; i++)
  259                         dst[i] ^= keystream[i];
  260 
  261                 ctr++;
  262 
  263                 sn += blocklen;
  264                 dn += blocklen;
  265 
  266                 /* find the next source block */
  267                 while (s && sn >= s->m_len) {
  268                         sn -= s->m_len;
  269                         soff += s->m_len;
  270                         s = s->m_next;
  271                 }
  272 
  273                 /* skip over empty mbuf */
  274                 while (s && s->m_len == 0)
  275                         s = s->m_next;
  276         }
  277 
  278         m_freem(scut->m_next);
  279         scut->m_len = scutoff;
  280         scut->m_next = d0;
  281 
  282         /* just in case */
  283         bzero(&cblock, sizeof(cblock));
  284         bzero(keystream, sizeof(keystream));
  285 
  286         return 0;
  287 
  288 fail:
  289         m_freem(m);
  290         if (d0)
  291                 m_freem(d0);
  292         return EINVAL;
  293 
  294 nomem:
  295         m_freem(m);
  296         if (d0)
  297                 m_freem(d0);
  298         return ENOBUFS;
  299 }
  300 
  301 int
  302 esp_aesctr_encrypt(m, off, plen, sav, algo, ivlen)
  303         struct mbuf *m;
  304         size_t off;
  305         size_t plen;
  306         struct secasvar *sav;
  307         const struct esp_algorithm *algo;
  308         int ivlen;
  309 {
  310         struct mbuf *s;
  311         struct mbuf *d, *d0, *dp;
  312         int soff, doff; /* offset from the head of chain, to head of this mbuf */
  313         int sn, dn;     /* offset from the head of the mbuf, to meat */
  314         size_t ivoff, bodyoff;
  315         union cblock cblock;
  316         u_int8_t keystream[AES_BLOCKSIZE], *nonce;
  317         u_int32_t ctr;
  318         u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
  319         struct mbuf *scut;
  320         int scutoff;
  321         int i;
  322         int blocklen;
  323         aesctr_ctx *ctx;
  324 
  325         if (ivlen != sav->ivlen) {
  326                 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
  327                     "unsupported ivlen %d\n", algo->name, ivlen));
  328                 m_freem(m);
  329                 return EINVAL;
  330         }
  331 
  332         /* assumes blocklen == padbound */
  333         blocklen = algo->padbound;
  334 
  335         ivoff = off + sizeof(struct newesp);
  336         bodyoff = off + sizeof(struct newesp) + ivlen;
  337 
  338         /* put iv into the packet. */
  339         /* maybe it is better to overwrite dest, not source */
  340         m_copyback(m, ivoff, ivlen, sav->iv);
  341 
  342         /* setup counter block */
  343         nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
  344         bcopy(nonce, cblock.v.nonce, NONCESIZE);
  345         m_copydata(m, ivoff, ivlen, cblock.v.iv);
  346         ctr = 1;
  347 
  348         if (m->m_pkthdr.len < bodyoff) {
  349                 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
  350                     algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
  351                 m_freem(m);
  352                 return EINVAL;
  353         }
  354         if ((m->m_pkthdr.len - bodyoff) % blocklen) {
  355                 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
  356                     "payload length must be multiple of %lu\n",
  357                     algo->name, (unsigned long)algo->padbound));
  358                 m_freem(m);
  359                 return EINVAL;
  360         }
  361 
  362         s = m;
  363         d = d0 = dp = NULL;
  364         soff = doff = sn = dn = 0;
  365         sp = NULL;
  366 
  367         /* skip bodyoff */
  368         while (soff < bodyoff) {
  369                 if (soff + s->m_len > bodyoff) {
  370                         sn = bodyoff - soff;
  371                         break;
  372                 }
  373 
  374                 soff += s->m_len;
  375                 s = s->m_next;
  376         }
  377         scut = s;
  378         scutoff = sn;
  379 
  380         /* skip over empty mbuf */
  381         while (s && s->m_len == 0)
  382                 s = s->m_next;
  383 
  384         while (soff < m->m_pkthdr.len) {
  385                 /* source */
  386                 if (sn + blocklen <= s->m_len) {
  387                         /* body is continuous */
  388                         sp = mtod(s, u_int8_t *) + sn;
  389                 } else {
  390                         /* body is non-continuous */
  391                         m_copydata(s, sn, blocklen, (caddr_t)sbuf);
  392                         sp = sbuf;
  393                 }
  394 
  395                 /* destination */
  396                 if (!d || dn + blocklen > d->m_len) {
  397                         if (d)
  398                                 dp = d;
  399                         MGET(d, M_DONTWAIT, MT_DATA);
  400                         i = m->m_pkthdr.len - (soff + sn);
  401                         if (d && i > MLEN) {
  402                                 MCLGET(d, M_DONTWAIT);
  403                                 if ((d->m_flags & M_EXT) == 0) {
  404                                         m_free(d);
  405                                         d = NULL;
  406                                 }
  407                         }
  408                         if (!d) {
  409                                 m_freem(m);
  410                                 if (d0)
  411                                         m_freem(d0);
  412                                 return ENOBUFS;
  413                         }
  414                         if (!d0)
  415                                 d0 = d;
  416                         if (dp)
  417                                 dp->m_next = d;
  418                         d->m_len = 0;
  419                         d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
  420                         if (d->m_len > i)
  421                                 d->m_len = i;
  422                         dn = 0;
  423                 }
  424 
  425                 /* put counter into counter block */
  426                 cblock.v.ctr = htonl(ctr);
  427 
  428                 /* setup keystream */
  429                 ctx = (aesctr_ctx *)sav->sched;
  430                 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
  431 
  432                 bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
  433                 dst = mtod(d, u_int8_t *) + dn;
  434                 for (i = 0; i < blocklen; i++)
  435                         dst[i] ^= keystream[i];
  436 
  437                 ctr++;
  438 
  439                 sn += blocklen;
  440                 dn += blocklen;
  441 
  442                 /* find the next source block */
  443                 while (s && sn >= s->m_len) {
  444                         sn -= s->m_len;
  445                         soff += s->m_len;
  446                         s = s->m_next;
  447                 }
  448 
  449                 /* skip over empty mbuf */
  450                 while (s && s->m_len == 0)
  451                         s = s->m_next;
  452         }
  453 
  454         m_freem(scut->m_next);
  455         scut->m_len = scutoff;
  456         scut->m_next = d0;
  457 
  458         /* just in case */
  459         bzero(&cblock, sizeof(cblock));
  460         bzero(keystream, sizeof(keystream));
  461 
  462         key_sa_stir_iv(sav);
  463 
  464         return 0;
  465 }

Cache object: 44177becf7fe922d66f76a34a17daf33


[ 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.