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 = 0;
 192        j = 0;
 193        for (k = 0; k < len; k++) {
 194                i = (i + 1) & 0xff;
 195                j = (j + s[i]) & 0xff;
 196                swap(i, j);
 197                buf[k] ^= s[(s[i] + s[j]) & 0xff];
 198                crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
 199        }
 200        crc = ~crc;
 201
 202        /* now let's check the crc */
 203        c_crc[0] = crc;
 204        c_crc[1] = crc >> 8;
 205        c_crc[2] = crc >> 16;
 206        c_crc[3] = crc >> 24;
 207
 208        for (k = 0; k < 4; k++) {
 209                i = (i + 1) & 0xff;
 210                j = (j + s[i]) & 0xff;
 211                swap(i, j);
 212                if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
 213                        return -(4 | (k << 4)); /* ICV mismatch */
 214        }
 215
 216        return 0;
 217}
 218
 219/* encrypts in-place. */
 220int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum,
 221                u8 *iv, u8 *icv)
 222{
 223        u32 i, j, k, crc, keylen;
 224        u8 s[256], key[64];
 225
 226        /* no point in WEPping an empty frame */
 227        if (len <= 0)
 228                return -1;
 229
 230        /* we need to have a real key.. */
 231        if (keynum >= NUM_WEPKEYS)
 232                return -2;
 233        keylen = wlandev->wep_keylens[keynum];
 234        if (keylen <= 0)
 235                return -3;
 236
 237        /* use a random IV.  And skip known weak ones. */
 238        get_random_bytes(iv, 3);
 239        while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
 240                get_random_bytes(iv, 3);
 241
 242        iv[3] = (keynum & 0x03) << 6;
 243
 244        key[0] = iv[0];
 245        key[1] = iv[1];
 246        key[2] = iv[2];
 247
 248        /* copy the rest of the key over from the designated key */
 249        memcpy(key + 3, wlandev->wep_keys[keynum], keylen);
 250
 251        keylen += 3;            /* add in IV bytes */
 252
 253        /* set up the RC4 state */
 254        for (i = 0; i < 256; i++)
 255                s[i] = i;
 256        j = 0;
 257        for (i = 0; i < 256; i++) {
 258                j = (j + s[i] + key[i % keylen]) & 0xff;
 259                swap(i, j);
 260        }
 261
 262        /* Update CRC32 then apply RC4 to the data */
 263        crc = ~0;
 264        i = 0;
 265        j = 0;
 266        for (k = 0; k < len; k++) {
 267                crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
 268                i = (i + 1) & 0xff;
 269                j = (j + s[i]) & 0xff;
 270                swap(i, j);
 271                dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
 272        }
 273        crc = ~crc;
 274
 275        /* now let's encrypt the crc */
 276        icv[0] = crc;
 277        icv[1] = crc >> 8;
 278        icv[2] = crc >> 16;
 279        icv[3] = crc >> 24;
 280
 281        for (k = 0; k < 4; k++) {
 282                i = (i + 1) & 0xff;
 283                j = (j + s[i]) & 0xff;
 284                swap(i, j);
 285                icv[k] ^= s[(s[i] + s[j]) & 0xff];
 286        }
 287
 288        return 0;
 289}
 290