[ 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  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  cheribsd  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD8-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: esp_aesctr.c,v 1.13 2010/08/14 18:28:59 jym 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.13 2010/08/14 18:28:59 jym 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 __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(struct secasvar *sav)
   77 {
   78         int keylen;
   79         const struct esp_algorithm *algo;
   80 
   81         algo = esp_algorithm_lookup(sav->alg_enc);
   82         if (algo == NULL) {
   83                 ipseclog((LOG_ERR,
   84                     "esp_aesctr_mature: unsupported encryption algorithm %d\n",
   85                     sav->alg_enc));
   86                 return 1;
   87         }
   88 
   89         keylen = sav->key_enc->sadb_key_bits;
   90         if (keylen < algo->keymin || algo->keymax < keylen) {
   91                 ipseclog((LOG_ERR,
   92                     "esp_aesctr_mature %s: invalid key length %d.\n",
   93                     algo->name, sav->key_enc->sadb_key_bits));
   94                 return 1;
   95         }
   96 
   97         /* rijndael key + nonce */
   98         if (!(keylen == 128 + 32 || keylen == 192 + 32 || keylen == 256 + 32)) {
   99                 ipseclog((LOG_ERR,
  100                     "esp_aesctr_mature %s: invalid key length %d.\n",
  101                     algo->name, keylen));
  102                 return 1;
  103         }
  104 
  105         return 0;
  106 }
  107 
  108 size_t
  109 esp_aesctr_schedlen(const struct esp_algorithm *algo)
  110 {
  111 
  112         return sizeof(aesctr_ctx);
  113 }
  114 
  115 int
  116 esp_aesctr_schedule(const struct esp_algorithm *algo,
  117     struct secasvar *sav)
  118 {
  119         aesctr_ctx *ctx;
  120         int keylen;
  121 
  122         /* SA key = AES key + nonce */
  123         keylen = _KEYLEN(sav->key_enc) * 8 - NONCESIZE * 8;
  124 
  125         ctx = (aesctr_ctx *)sav->sched;
  126         if ((ctx->r_nr = rijndaelKeySetupEnc(ctx->r_ek,
  127             (char *)_KEYBUF(sav->key_enc), keylen)) == 0)
  128                 return -1;
  129         return 0;
  130 }
  131 
  132 int
  133 esp_aesctr_decrypt(struct mbuf *m, size_t off, struct secasvar *sav, 
  134         const struct esp_algorithm *algo, int ivlen)
  135 {
  136         struct mbuf *s;
  137         struct mbuf *d, *d0 = NULL, *dp;
  138         int soff, doff; /* offset from the head of chain, to head of this mbuf */
  139         int sn, dn;     /* offset from the head of the mbuf, to meat */
  140         size_t ivoff, bodyoff;
  141         union cblock cblock;
  142         u_int8_t keystream[AES_BLOCKSIZE], *nonce;
  143         u_int32_t ctr;
  144         u_int8_t *ivp;
  145         u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
  146         struct mbuf *scut;
  147         int scutoff;
  148         int i;
  149         int blocklen;
  150         aesctr_ctx *ctx;
  151 
  152         if (ivlen != sav->ivlen) {
  153                 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
  154                     "unsupported ivlen %d\n", algo->name, ivlen));
  155                 goto fail;
  156         }
  157 
  158         /* assumes blocklen == padbound */
  159         blocklen = algo->padbound;
  160 
  161         ivoff = off + sizeof(struct newesp);
  162         bodyoff = off + sizeof(struct newesp) + ivlen;
  163 
  164         /* setup counter block */
  165         nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
  166         memcpy(cblock.v.nonce, nonce, NONCESIZE);
  167         m_copydata(m, ivoff, ivlen, cblock.v.iv);
  168         ctr = 1;
  169 
  170         if (m->m_pkthdr.len < bodyoff) {
  171                 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
  172                     algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
  173                 goto fail;
  174         }
  175         if ((m->m_pkthdr.len - bodyoff) % blocklen) {
  176                 ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
  177                     "payload length must be multiple of %d\n",
  178                     algo->name, blocklen));
  179                 goto fail;
  180         }
  181 
  182         s = m;
  183         d = d0 = dp = NULL;
  184         soff = doff = sn = dn = 0;
  185         ivp = sp = NULL;
  186 
  187         /* skip bodyoff */
  188         while (soff < bodyoff) {
  189                 if (soff + s->m_len > bodyoff) {
  190                         sn = bodyoff - soff;
  191                         break;
  192                 }
  193 
  194                 soff += s->m_len;
  195                 s = s->m_next;
  196         }
  197         scut = s;
  198         scutoff = sn;
  199 
  200         /* skip over empty mbuf */
  201         while (s && s->m_len == 0)
  202                 s = s->m_next;
  203 
  204         while (soff < m->m_pkthdr.len) {
  205                 /* source */
  206                 if (sn + blocklen <= s->m_len) {
  207                         /* body is continuous */
  208                         sp = mtod(s, u_int8_t *) + sn;
  209                 } else {
  210                         /* body is non-continuous */
  211                         m_copydata(s, sn, blocklen, (void *)sbuf);
  212                         sp = sbuf;
  213                 }
  214 
  215                 /* destination */
  216                 if (!d || dn + blocklen > d->m_len) {
  217                         if (d)
  218                                 dp = d;
  219                         MGET(d, M_DONTWAIT, MT_DATA);
  220                         i = m->m_pkthdr.len - (soff + sn);
  221                         if (d && i > MLEN) {
  222                                 MCLGET(d, M_DONTWAIT);
  223                                 if ((d->m_flags & M_EXT) == 0) {
  224                                         m_free(d);
  225                                         d = NULL;
  226                                 }
  227                         }
  228                         if (!d) {
  229                                 goto nomem;
  230                         }
  231                         if (!d0)
  232                                 d0 = d;
  233                         if (dp)
  234                                 dp->m_next = d;
  235                         d->m_len = 0;
  236                         d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
  237                         if (d->m_len > i)
  238                                 d->m_len = i;
  239                         dn = 0;
  240                 }
  241 
  242                 /* put counter into counter block */
  243                 cblock.v.ctr = htonl(ctr);
  244 
  245                 /* setup keystream */
  246                 ctx = (aesctr_ctx *)sav->sched;
  247                 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
  248 
  249                 memcpy(mtod(d, u_int8_t *) + dn, sp, blocklen);
  250                 dst = mtod(d, u_int8_t *) + dn;
  251                 for (i = 0; i < blocklen; i++)
  252                         dst[i] ^= keystream[i];
  253 
  254                 ctr++;
  255 
  256                 sn += blocklen;
  257                 dn += blocklen;
  258 
  259                 /* find the next source block */
  260                 while (s && sn >= s->m_len) {
  261                         sn -= s->m_len;
  262                         soff += s->m_len;
  263                         s = s->m_next;
  264                 }
  265 
  266                 /* skip over empty mbuf */
  267                 while (s && s->m_len == 0)
  268                         s = s->m_next;
  269         }
  270 
  271         m_freem(scut->m_next);
  272         scut->m_len = scutoff;
  273         scut->m_next = d0;
  274 
  275         /* just in case */
  276         memset(&cblock, 0, sizeof(cblock));
  277         memset(keystream, 0, sizeof(keystream));
  278 
  279         return 0;
  280 
  281 fail:
  282         m_freem(m);
  283         if (d0)
  284                 m_freem(d0);
  285         return EINVAL;
  286 
  287 nomem:
  288         m_freem(m);
  289         if (d0)
  290                 m_freem(d0);
  291         return ENOBUFS;
  292 }
  293 
  294 int
  295 esp_aesctr_encrypt(
  296     struct mbuf *m,
  297     size_t off,
  298     size_t plen,
  299     struct secasvar *sav,
  300     const struct esp_algorithm *algo,
  301     int ivlen
  302 )
  303 {
  304         struct mbuf *s;
  305         struct mbuf *d, *d0, *dp;
  306         int soff, doff; /* offset from the head of chain, to head of this mbuf */
  307         int sn, dn;     /* offset from the head of the mbuf, to meat */
  308         size_t ivoff, bodyoff;
  309         union cblock cblock;
  310         u_int8_t keystream[AES_BLOCKSIZE], *nonce;
  311         u_int32_t ctr;
  312         u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
  313         struct mbuf *scut;
  314         int scutoff;
  315         int i;
  316         int blocklen;
  317         aesctr_ctx *ctx;
  318 
  319         if (ivlen != sav->ivlen) {
  320                 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
  321                     "unsupported ivlen %d\n", algo->name, ivlen));
  322                 m_freem(m);
  323                 return EINVAL;
  324         }
  325 
  326         /* assumes blocklen == padbound */
  327         blocklen = algo->padbound;
  328 
  329         ivoff = off + sizeof(struct newesp);
  330         bodyoff = off + sizeof(struct newesp) + ivlen;
  331 
  332         /* put iv into the packet. */
  333         /* maybe it is better to overwrite dest, not source */
  334         m_copyback(m, ivoff, ivlen, sav->iv);
  335 
  336         /* setup counter block */
  337         nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
  338         memcpy(cblock.v.nonce, nonce, NONCESIZE);
  339         m_copydata(m, ivoff, ivlen, cblock.v.iv);
  340         ctr = 1;
  341 
  342         if (m->m_pkthdr.len < bodyoff) {
  343                 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
  344                     algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
  345                 m_freem(m);
  346                 return EINVAL;
  347         }
  348         if ((m->m_pkthdr.len - bodyoff) % blocklen) {
  349                 ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
  350                     "payload length must be multiple of %lu\n",
  351                     algo->name, (unsigned long)algo->padbound));
  352                 m_freem(m);
  353                 return EINVAL;
  354         }
  355 
  356         s = m;
  357         d = d0 = dp = NULL;
  358         soff = doff = sn = dn = 0;
  359         sp = NULL;
  360 
  361         /* skip bodyoff */
  362         while (soff < bodyoff) {
  363                 if (soff + s->m_len > bodyoff) {
  364                         sn = bodyoff - soff;
  365                         break;
  366                 }
  367 
  368                 soff += s->m_len;
  369                 s = s->m_next;
  370         }
  371         scut = s;
  372         scutoff = sn;
  373 
  374         /* skip over empty mbuf */
  375         while (s && s->m_len == 0)
  376                 s = s->m_next;
  377 
  378         while (soff < m->m_pkthdr.len) {
  379                 /* source */
  380                 if (sn + blocklen <= s->m_len) {
  381                         /* body is continuous */
  382                         sp = mtod(s, u_int8_t *) + sn;
  383                 } else {
  384                         /* body is non-continuous */
  385                         m_copydata(s, sn, blocklen, (void *)sbuf);
  386                         sp = sbuf;
  387                 }
  388 
  389                 /* destination */
  390                 if (!d || dn + blocklen > d->m_len) {
  391                         if (d)
  392                                 dp = d;
  393                         MGET(d, M_DONTWAIT, MT_DATA);
  394                         i = m->m_pkthdr.len - (soff + sn);
  395                         if (d && i > MLEN) {
  396                                 MCLGET(d, M_DONTWAIT);
  397                                 if ((d->m_flags & M_EXT) == 0) {
  398                                         m_free(d);
  399                                         d = NULL;
  400                                 }
  401                         }
  402                         if (!d) {
  403                                 m_freem(m);
  404                                 if (d0)
  405                                         m_freem(d0);
  406                                 return ENOBUFS;
  407                         }
  408                         if (!d0)
  409                                 d0 = d;
  410                         if (dp)
  411                                 dp->m_next = d;
  412                         d->m_len = 0;
  413                         d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
  414                         if (d->m_len > i)
  415                                 d->m_len = i;
  416                         dn = 0;
  417                 }
  418 
  419                 /* put counter into counter block */
  420                 cblock.v.ctr = htonl(ctr);
  421 
  422                 /* setup keystream */
  423                 ctx = (aesctr_ctx *)sav->sched;
  424                 rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
  425 
  426                 memcpy(mtod(d, u_int8_t *) + dn, sp, blocklen);
  427                 dst = mtod(d, u_int8_t *) + dn;
  428                 for (i = 0; i < blocklen; i++)
  429                         dst[i] ^= keystream[i];
  430 
  431                 ctr++;
  432 
  433                 sn += blocklen;
  434                 dn += blocklen;
  435 
  436                 /* find the next source block */
  437                 while (s && sn >= s->m_len) {
  438                         sn -= s->m_len;
  439                         soff += s->m_len;
  440                         s = s->m_next;
  441                 }
  442 
  443                 /* skip over empty mbuf */
  444                 while (s && s->m_len == 0)
  445                         s = s->m_next;
  446         }
  447 
  448         m_freem(scut->m_next);
  449         scut->m_len = scutoff;
  450         scut->m_next = d0;
  451 
  452         /* just in case */
  453         memset(&cblock, 0, sizeof(cblock));
  454         memset(keystream, 0, sizeof(keystream));
  455 
  456         key_sa_stir_iv(sav);
  457 
  458         return 0;
  459 }

Cache object: 231f2e51faa7729d0bfb60bde7df1ded


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