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

Cache object: b23d7c152857b9d2e96db77d741689b3


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