linux/drivers/staging/wlan-ng/p80211wep.c
<<
>>
Prefs
   1/* src/p80211/p80211wep.c
   2*
   3* WEP encode/decode for P80211.
   4*
   5* Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
   6* --------------------------------------------------------------------
   7*
   8* linux-wlan
   9*
  10*   The contents of this file are subject to the Mozilla Public
  11*   License Version 1.1 (the "License"); you may not use this file
  12*   except in compliance with the License. You may obtain a copy of
  13*   the License at http://www.mozilla.org/MPL/
  14*
  15*   Software distributed under the License is distributed on an "AS
  16*   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  17*   implied. See the License for the specific language governing
  18*   rights and limitations under the License.
  19*
  20*   Alternatively, the contents of this file may be used under the
  21*   terms of the GNU Public License version 2 (the "GPL"), in which
  22*   case the provisions of the GPL are applicable instead of the
  23*   above.  If you wish to allow the use of your version of this file
  24*   only under the terms of the GPL and not to allow others to use
  25*   your version of this file under the MPL, indicate your decision
  26*   by deleting the provisions above and replace them with the notice
  27*   and other provisions required by the GPL.  If you do not delete
  28*   the provisions above, a recipient may use your version of this
  29*   file under either the MPL or the GPL.
  30*
  31* --------------------------------------------------------------------
  32*
  33* Inquiries regarding the linux-wlan Open Source project can be
  34* made directly to:
  35*
  36* AbsoluteValue Systems Inc.
  37* info@linux-wlan.com
  38* http://www.linux-wlan.com
  39*
  40* --------------------------------------------------------------------
  41*
  42* Portions of the development of this software were funded by
  43* Intersil Corporation as part of PRISM(R) chipset product development.
  44*
  45* --------------------------------------------------------------------
  46*/
  47
  48/*================================================================*/
  49/* System Includes */
  50
  51#include <linux/netdevice.h>
  52#include <linux/wireless.h>
  53#include <linux/random.h>
  54#include <linux/kernel.h>
  55
  56
  57#include "p80211hdr.h"
  58#include "p80211types.h"
  59#include "p80211msg.h"
  60#include "p80211conv.h"
  61#include "p80211netdev.h"
  62
  63#define WEP_KEY(x)       (((x) & 0xC0) >> 6)
  64
  65static const u32 wep_crc32_table[256] = {
  66        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  67        0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  68        0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  69        0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  70        0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  71        0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  72        0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  73        0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  74        0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  75        0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  76        0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  77        0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  78        0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  79        0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  80        0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  81        0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  82        0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  83        0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  84        0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  85        0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  86        0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  87        0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  88        0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  89        0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  90        0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  91        0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  92        0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  93        0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  94        0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  95        0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  96        0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  97        0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  98        0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
  99        0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
 100        0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
 101        0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
 102        0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
 103        0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
 104        0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
 105        0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
 106        0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
 107        0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
 108        0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
 109        0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
 110        0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
 111        0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
 112        0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
 113        0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
 114        0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
 115        0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
 116        0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
 117        0x2d02ef8dL
 118};
 119
 120/* keylen in bytes! */
 121
 122int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen)
 123{
 124        if (keylen < 0)
 125                return -1;
 126        if (keylen >= MAX_KEYLEN)
 127                return -1;
 128        if (key == NULL)
 129                return -1;
 130        if (keynum < 0)
 131                return -1;
 132        if (keynum >= NUM_WEPKEYS)
 133                return -1;
 134
 135
 136        wlandev->wep_keylens[keynum] = keylen;
 137        memcpy(wlandev->wep_keys[keynum], key, keylen);
 138
 139        return 0;
 140}
 141
 142/*
 143  4-byte IV at start of buffer, 4-byte ICV at end of buffer.
 144  if successful, buf start is payload begin, length -= 8;
 145 */
 146int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override,
 147                u8 *iv, u8 *icv)
 148{
 149        u32 i, j, k, crc, keylen;
 150        u8 s[256], key[64], c_crc[4];
 151        u8 keyidx;
 152
 153        /* Needs to be at least 8 bytes of payload */
 154        if (len <= 0)
 155                return -1;
 156
 157        /* initialize the first bytes of the key from the IV */
 158        key[0] = iv[0];
 159        key[1] = iv[1];
 160        key[2] = iv[2];
 161        keyidx = WEP_KEY(iv[3]);
 162
 163        if (key_override >= 0)
 164                keyidx = key_override;
 165
 166        if (keyidx >= NUM_WEPKEYS)
 167                return -2;
 168
 169        keylen = wlandev->wep_keylens[keyidx];
 170
 171        if (keylen == 0)
 172                return -3;
 173
 174        /* copy the rest of the key over from the designated key */
 175        memcpy(key + 3, wlandev->wep_keys[keyidx], keylen);
 176
 177        keylen += 3;            /* add in IV bytes */
 178
 179
 180        /* set up the RC4 state */
 181        for (i = 0; i < 256; i++)
 182                s[i] = i;
 183        j = 0;
 184        for (i = 0; i < 256; i++) {
 185                j = (j + s[i] + key[i % keylen]) & 0xff;
 186                swap(i, j);
 187        }
 188
 189        /* Apply the RC4 to the data, update the CRC32 */
 190        crc = ~0;
 191        i = j = 0;
 192        for (k = 0; k < len; k++) {
 193                i = (i + 1) & 0xff;
 194                j = (j + s[i]) & 0xff;
 195                swap(i, j);
 196                buf[k] ^= s[(s[i] + s[j]) & 0xff];
 197                crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
 198        }
 199        crc = ~crc;
 200
 201        /* now let's check the crc */
 202        c_crc[0] = crc;
 203        c_crc[1] = crc >> 8;
 204        c_crc[2] = crc >> 16;
 205        c_crc[3] = crc >> 24;
 206
 207        for (k = 0; k < 4; k++) {
 208                i = (i + 1) & 0xff;
 209                j = (j + s[i]) & 0xff;
 210                swap(i, j);
 211                if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
 212                        return -(4 | (k << 4)); /* ICV mismatch */
 213        }
 214
 215        return 0;
 216}
 217
 218/* encrypts in-place. */
 219int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum,
 220                u8 *iv, u8 *icv)
 221{
 222        u32 i, j, k, crc, keylen;
 223        u8 s[256], key[64];
 224
 225        /* no point in WEPping an empty frame */
 226        if (len <= 0)
 227                return -1;
 228
 229        /* we need to have a real key.. */
 230        if (keynum >= NUM_WEPKEYS)
 231                return -2;
 232        keylen = wlandev->wep_keylens[keynum];
 233        if (keylen <= 0)
 234                return -3;
 235
 236        /* use a random IV.  And skip known weak ones. */
 237        get_random_bytes(iv, 3);
 238        while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
 239                get_random_bytes(iv, 3);
 240
 241        iv[3] = (keynum & 0x03) << 6;
 242
 243        key[0] = iv[0];
 244        key[1] = iv[1];
 245        key[2] = iv[2];
 246
 247        /* copy the rest of the key over from the designated key */
 248        memcpy(key + 3, wlandev->wep_keys[keynum], keylen);
 249
 250        keylen += 3;            /* add in IV bytes */
 251
 252        /* set up the RC4 state */
 253        for (i = 0; i < 256; i++)
 254                s[i] = i;
 255        j = 0;
 256        for (i = 0; i < 256; i++) {
 257                j = (j + s[i] + key[i % keylen]) & 0xff;
 258                swap(i, j);
 259        }
 260
 261        /* Update CRC32 then apply RC4 to the data */
 262        crc = ~0;
 263        i = j = 0;
 264        for (k = 0; k < len; k++) {
 265                crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
 266                i = (i + 1) & 0xff;
 267                j = (j + s[i]) & 0xff;
 268                swap(i, j);
 269                dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
 270        }
 271        crc = ~crc;
 272
 273        /* now let's encrypt the crc */
 274        icv[0] = crc;
 275        icv[1] = crc >> 8;
 276        icv[2] = crc >> 16;
 277        icv[3] = crc >> 24;
 278
 279        for (k = 0; k < 4; k++) {
 280                i = (i + 1) & 0xff;
 281                j = (j + s[i]) & 0xff;
 282                swap(i, j);
 283                icv[k] ^= s[(s[i] + s[j]) & 0xff];
 284        }
 285
 286        return 0;
 287}
 288