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/net80211/ieee80211_crypto_wep.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 /*      $OpenBSD: ieee80211_crypto_wep.c,v 1.17 2018/11/09 14:14:31 claudio Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 /*
   20  * This code implements Wired Equivalent Privacy (WEP) defined in
   21  * IEEE Std 802.11-2007 section 8.2.1.
   22  */
   23 
   24 #include <sys/param.h>
   25 #include <sys/systm.h>
   26 #include <sys/mbuf.h>
   27 #include <sys/malloc.h>
   28 #include <sys/kernel.h>
   29 #include <sys/socket.h>
   30 #include <sys/endian.h>
   31 
   32 #include <net/if.h>
   33 #include <net/if_dl.h>
   34 #include <net/if_media.h>
   35 
   36 #include <netinet/in.h>
   37 #include <netinet/if_ether.h>
   38 
   39 #include <net80211/ieee80211_var.h>
   40 #include <net80211/ieee80211_crypto.h>
   41 
   42 #include <crypto/arc4.h>
   43 
   44 /* WEP software crypto context */
   45 struct ieee80211_wep_ctx {
   46         struct rc4_ctx  rc4;
   47         u_int32_t       iv;
   48 };
   49 
   50 /*
   51  * Initialize software crypto context.  This function can be overridden
   52  * by drivers doing hardware crypto.
   53  */
   54 int
   55 ieee80211_wep_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
   56 {
   57         struct ieee80211_wep_ctx *ctx;
   58 
   59         ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
   60         if (ctx == NULL)
   61                 return ENOMEM;
   62         k->k_priv = ctx;
   63         return 0;
   64 }
   65 
   66 void
   67 ieee80211_wep_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
   68 {
   69         if (k->k_priv != NULL) {
   70                 explicit_bzero(k->k_priv, sizeof(struct ieee80211_wep_ctx));
   71                 free(k->k_priv, M_DEVBUF, sizeof(struct ieee80211_wep_ctx));
   72         }
   73         k->k_priv = NULL;
   74 }
   75 
   76 /* shortcut */
   77 #define IEEE80211_WEP_HDRLEN    \
   78         (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
   79 
   80 struct mbuf *
   81 ieee80211_wep_encrypt(struct ieee80211com *ic, struct mbuf *m0,
   82     struct ieee80211_key *k)
   83 {
   84         struct ieee80211_wep_ctx *ctx = k->k_priv;
   85         u_int8_t wepseed[16];
   86         const struct ieee80211_frame *wh;
   87         struct mbuf *n0, *m, *n;
   88         u_int8_t *ivp, *icvp;
   89         u_int32_t iv, crc;
   90         int left, moff, noff, len, hdrlen;
   91 
   92         MGET(n0, M_DONTWAIT, m0->m_type);
   93         if (n0 == NULL)
   94                 goto nospace;
   95         if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
   96                 goto nospace;
   97         n0->m_pkthdr.len += IEEE80211_WEP_HDRLEN;
   98         n0->m_len = MHLEN;
   99         if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
  100                 MCLGET(n0, M_DONTWAIT);
  101                 if (n0->m_flags & M_EXT)
  102                         n0->m_len = n0->m_ext.ext_size;
  103         }
  104         if (n0->m_len > n0->m_pkthdr.len)
  105                 n0->m_len = n0->m_pkthdr.len;
  106 
  107         /* copy 802.11 header */
  108         wh = mtod(m0, struct ieee80211_frame *);
  109         hdrlen = ieee80211_get_hdrlen(wh);
  110         memcpy(mtod(n0, caddr_t), wh, hdrlen);
  111 
  112         /* select a new IV for every MPDU */
  113         iv = (ctx->iv != 0) ? ctx->iv : arc4random();
  114         /* skip weak IVs from Fluhrer/Mantin/Shamir */
  115         if (iv >= 0x03ff00 && (iv & 0xf8ff00) == 0x00ff00)
  116                 iv += 0x000100;
  117         ctx->iv = iv + 1;
  118         ivp = mtod(n0, u_int8_t *) + hdrlen;
  119         ivp[0] = iv;
  120         ivp[1] = iv >> 8;
  121         ivp[2] = iv >> 16;
  122         ivp[3] = k->k_id << 6;
  123 
  124         /* compute WEP seed: concatenate IV and WEP Key */
  125         memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
  126         memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
  127         rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
  128         explicit_bzero(wepseed, sizeof(wepseed));
  129 
  130         /* encrypt frame body and compute WEP ICV */
  131         m = m0;
  132         n = n0;
  133         moff = hdrlen;
  134         noff = hdrlen + IEEE80211_WEP_HDRLEN;
  135         left = m0->m_pkthdr.len - moff;
  136         crc = ~0;
  137         while (left > 0) {
  138                 if (moff == m->m_len) {
  139                         /* nothing left to copy from m */
  140                         m = m->m_next;
  141                         moff = 0;
  142                 }
  143                 if (noff == n->m_len) {
  144                         /* n is full and there's more data to copy */
  145                         MGET(n->m_next, M_DONTWAIT, n->m_type);
  146                         if (n->m_next == NULL)
  147                                 goto nospace;
  148                         n = n->m_next;
  149                         n->m_len = MLEN;
  150                         if (left >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
  151                                 MCLGET(n, M_DONTWAIT);
  152                                 if (n->m_flags & M_EXT)
  153                                         n->m_len = n->m_ext.ext_size;
  154                         }
  155                         if (n->m_len > left)
  156                                 n->m_len = left;
  157                         noff = 0;
  158                 }
  159                 len = min(m->m_len - moff, n->m_len - noff);
  160 
  161                 crc = ether_crc32_le_update(crc, mtod(m, caddr_t) + moff, len);
  162                 rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
  163                     mtod(n, caddr_t) + noff, len);
  164 
  165                 moff += len;
  166                 noff += len;
  167                 left -= len;
  168         }
  169 
  170         /* reserve trailing space for WEP ICV */
  171         if (m_trailingspace(n) < IEEE80211_WEP_CRCLEN) {
  172                 MGET(n->m_next, M_DONTWAIT, n->m_type);
  173                 if (n->m_next == NULL)
  174                         goto nospace;
  175                 n = n->m_next;
  176                 n->m_len = 0;
  177         }
  178 
  179         /* finalize WEP ICV */
  180         icvp = mtod(n, caddr_t) + n->m_len;
  181         crc = ~crc;
  182         icvp[0] = crc;
  183         icvp[1] = crc >> 8;
  184         icvp[2] = crc >> 16;
  185         icvp[3] = crc >> 24;
  186         rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN);
  187         n->m_len += IEEE80211_WEP_CRCLEN;
  188         n0->m_pkthdr.len += IEEE80211_WEP_CRCLEN;
  189 
  190         m_freem(m0);
  191         return n0;
  192  nospace:
  193         ic->ic_stats.is_tx_nombuf++;
  194         m_freem(m0);
  195         m_freem(n0);
  196         return NULL;
  197 }
  198 
  199 struct mbuf *
  200 ieee80211_wep_decrypt(struct ieee80211com *ic, struct mbuf *m0,
  201     struct ieee80211_key *k)
  202 {
  203         struct ieee80211_wep_ctx *ctx = k->k_priv;
  204         struct ieee80211_frame *wh;
  205         u_int8_t wepseed[16];
  206         u_int32_t crc, crc0;
  207         u_int8_t *ivp;
  208         struct mbuf *n0, *m, *n;
  209         int hdrlen, left, moff, noff, len;
  210 
  211         wh = mtod(m0, struct ieee80211_frame *);
  212         hdrlen = ieee80211_get_hdrlen(wh);
  213 
  214         if (m0->m_pkthdr.len < hdrlen + IEEE80211_WEP_TOTLEN) {
  215                 m_freem(m0);
  216                 return NULL;
  217         }
  218 
  219         /* concatenate IV and WEP Key */
  220         ivp = (u_int8_t *)wh + hdrlen;
  221         memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
  222         memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
  223         rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
  224         explicit_bzero(wepseed, sizeof(wepseed));
  225 
  226         MGET(n0, M_DONTWAIT, m0->m_type);
  227         if (n0 == NULL)
  228                 goto nospace;
  229         if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
  230                 goto nospace;
  231         n0->m_pkthdr.len -= IEEE80211_WEP_TOTLEN;
  232         n0->m_len = MHLEN;
  233         if (n0->m_pkthdr.len >= MINCLSIZE) {
  234                 MCLGET(n0, M_DONTWAIT);
  235                 if (n0->m_flags & M_EXT)
  236                         n0->m_len = n0->m_ext.ext_size;
  237         }
  238         if (n0->m_len > n0->m_pkthdr.len)
  239                 n0->m_len = n0->m_pkthdr.len;
  240 
  241         /* copy 802.11 header and clear protected bit */
  242         memcpy(mtod(n0, caddr_t), wh, hdrlen);
  243         wh = mtod(n0, struct ieee80211_frame *);
  244         wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
  245 
  246         /* decrypt frame body and compute WEP ICV */
  247         m = m0;
  248         n = n0;
  249         moff = hdrlen + IEEE80211_WEP_HDRLEN;
  250         noff = hdrlen;
  251         left = n0->m_pkthdr.len - noff;
  252         crc = ~0;
  253         while (left > 0) {
  254                 if (moff == m->m_len) {
  255                         /* nothing left to copy from m */
  256                         m = m->m_next;
  257                         moff = 0;
  258                 }
  259                 if (noff == n->m_len) {
  260                         /* n is full and there's more data to copy */
  261                         MGET(n->m_next, M_DONTWAIT, n->m_type);
  262                         if (n->m_next == NULL)
  263                                 goto nospace;
  264                         n = n->m_next;
  265                         n->m_len = MLEN;
  266                         if (left >= MINCLSIZE) {
  267                                 MCLGET(n, M_DONTWAIT);
  268                                 if (n->m_flags & M_EXT)
  269                                         n->m_len = n->m_ext.ext_size;
  270                         }
  271                         if (n->m_len > left)
  272                                 n->m_len = left;
  273                         noff = 0;
  274                 }
  275                 len = min(m->m_len - moff, n->m_len - noff);
  276 
  277                 rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
  278                     mtod(n, caddr_t) + noff, len);
  279                 crc = ether_crc32_le_update(crc, mtod(n, caddr_t) + noff, len);
  280 
  281                 moff += len;
  282                 noff += len;
  283                 left -= len;
  284         }
  285 
  286         /* decrypt ICV and compare it with calculated ICV */
  287         m_copydata(m, moff, IEEE80211_WEP_CRCLEN, (caddr_t)&crc0);
  288         rc4_crypt(&ctx->rc4, (caddr_t)&crc0, (caddr_t)&crc0,
  289             IEEE80211_WEP_CRCLEN);
  290         crc = ~crc;
  291         if (crc != letoh32(crc0)) {
  292                 ic->ic_stats.is_rx_decryptcrc++;
  293                 m_freem(m0);
  294                 m_freem(n0);
  295                 return NULL;
  296         }
  297 
  298         m_freem(m0);
  299         return n0;
  300  nospace:
  301         ic->ic_stats.is_rx_nombuf++;
  302         m_freem(m0);
  303         m_freem(n0);
  304         return NULL;
  305 }

Cache object: d25fd319878bf24d9382797d1fab3963


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