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/* #define WEP_DEBUG    */
  57
  58#include "p80211hdr.h"
  59#include "p80211types.h"
  60#include "p80211msg.h"
  61#include "p80211conv.h"
  62#include "p80211netdev.h"
  63
  64#define WEP_KEY(x)       (((x) & 0xC0) >> 6)
  65
  66static const u32 wep_crc32_table[256] = {
  67        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  68        0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  69        0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  70        0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  71        0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  72        0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  73        0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  74        0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  75        0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  76        0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  77        0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  78        0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  79        0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  80        0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  81        0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  82        0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  83        0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  84        0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  85        0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  86        0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  87        0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  88        0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  89        0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  90        0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  91        0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  92        0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  93        0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  94        0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  95        0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  96        0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  97        0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  98        0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  99        0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
 100        0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
 101        0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
 102        0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
 103        0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
 104        0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
 105        0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
 106        0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
 107        0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
 108        0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
 109        0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
 110        0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
 111        0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
 112        0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
 113        0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
 114        0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
 115        0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
 116        0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
 117        0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
 118        0x2d02ef8dL
 119};
 120
 121/* keylen in bytes! */
 122
 123int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen)
 124{
 125        if (keylen < 0)
 126                return -1;
 127        if (keylen >= MAX_KEYLEN)
 128                return -1;
 129        if (key == NULL)
 130                return -1;
 131        if (keynum < 0)
 132                return -1;
 133        if (keynum >= NUM_WEPKEYS)
 134                return -1;
 135
 136#ifdef WEP_DEBUG
 137        printk(KERN_DEBUG "WEP key %d len %d = %*phC\n", keynum, keylen,
 138                          8, key);
 139#endif
 140
 141        wlandev->wep_keylens[keynum] = keylen;
 142        memcpy(wlandev->wep_keys[keynum], key, keylen);
 143
 144        return 0;
 145}
 146
 147/*
 148  4-byte IV at start of buffer, 4-byte ICV at end of buffer.
 149  if successful, buf start is payload begin, length -= 8;
 150 */
 151int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override,
 152                u8 *iv, u8 *icv)
 153{
 154        u32 i, j, k, crc, keylen;
 155        u8 s[256], key[64], c_crc[4];
 156        u8 keyidx;
 157
 158        /* Needs to be at least 8 bytes of payload */
 159        if (len <= 0)
 160                return -1;
 161
 162        /* initialize the first bytes of the key from the IV */
 163        key[0] = iv[0];
 164        key[1] = iv[1];
 165        key[2] = iv[2];
 166        keyidx = WEP_KEY(iv[3]);
 167
 168        if (key_override >= 0)
 169                keyidx = key_override;
 170
 171        if (keyidx >= NUM_WEPKEYS)
 172                return -2;
 173
 174        keylen = wlandev->wep_keylens[keyidx];
 175
 176        if (keylen == 0)
 177                return -3;
 178
 179        /* copy the rest of the key over from the designated key */
 180        memcpy(key + 3, wlandev->wep_keys[keyidx], keylen);
 181
 182        keylen += 3;            /* add in IV bytes */
 183
 184#ifdef WEP_DEBUG
 185        printk(KERN_DEBUG "D %d: %*ph (%d %d) %*phC\n", len, 3, key,
 186                          keyidx, keylen, 5, key + 3);
 187#endif
 188
 189        /* set up the RC4 state */
 190        for (i = 0; i < 256; i++)
 191                s[i] = i;
 192        j = 0;
 193        for (i = 0; i < 256; i++) {
 194                j = (j + s[i] + key[i % keylen]) & 0xff;
 195                swap(i, j);
 196        }
 197
 198        /* Apply the RC4 to the data, update the CRC32 */
 199        crc = ~0;
 200        i = j = 0;
 201        for (k = 0; k < len; k++) {
 202                i = (i + 1) & 0xff;
 203                j = (j + s[i]) & 0xff;
 204                swap(i, j);
 205                buf[k] ^= s[(s[i] + s[j]) & 0xff];
 206                crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
 207        }
 208        crc = ~crc;
 209
 210        /* now let's check the crc */
 211        c_crc[0] = crc;
 212        c_crc[1] = crc >> 8;
 213        c_crc[2] = crc >> 16;
 214        c_crc[3] = crc >> 24;
 215
 216        for (k = 0; k < 4; k++) {
 217                i = (i + 1) & 0xff;
 218                j = (j + s[i]) & 0xff;
 219                swap(i, j);
 220                if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
 221                        return -(4 | (k << 4)); /* ICV mismatch */
 222        }
 223
 224        return 0;
 225}
 226
 227/* encrypts in-place. */
 228int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum,
 229                u8 *iv, u8 *icv)
 230{
 231        u32 i, j, k, crc, keylen;
 232        u8 s[256], key[64];
 233
 234        /* no point in WEPping an empty frame */
 235        if (len <= 0)
 236                return -1;
 237
 238        /* we need to have a real key.. */
 239        if (keynum >= NUM_WEPKEYS)
 240                return -2;
 241        keylen = wlandev->wep_keylens[keynum];
 242        if (keylen <= 0)
 243                return -3;
 244
 245        /* use a random IV.  And skip known weak ones. */
 246        get_random_bytes(iv, 3);
 247        while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
 248                get_random_bytes(iv, 3);
 249
 250        iv[3] = (keynum & 0x03) << 6;
 251
 252        key[0] = iv[0];
 253        key[1] = iv[1];
 254        key[2] = iv[2];
 255
 256        /* copy the rest of the key over from the designated key */
 257        memcpy(key + 3, wlandev->wep_keys[keynum], keylen);
 258
 259        keylen += 3;            /* add in IV bytes */
 260
 261#ifdef WEP_DEBUG
 262        printk(KERN_DEBUG "E %d (%d/%d %d) %*ph %*phC\n", len,
 263                          iv[3], keynum, keylen, 3, key, 5, key + 3);
 264#endif
 265
 266        /* set up the RC4 state */
 267        for (i = 0; i < 256; i++)
 268                s[i] = i;
 269        j = 0;
 270        for (i = 0; i < 256; i++) {
 271                j = (j + s[i] + key[i % keylen]) & 0xff;
 272                swap(i, j);
 273        }
 274
 275        /* Update CRC32 then apply RC4 to the data */
 276        crc = ~0;
 277        i = j = 0;
 278        for (k = 0; k < len; k++) {
 279                crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
 280                i = (i + 1) & 0xff;
 281                j = (j + s[i]) & 0xff;
 282                swap(i, j);
 283                dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
 284        }
 285        crc = ~crc;
 286
 287        /* now let's encrypt the crc */
 288        icv[0] = crc;
 289        icv[1] = crc >> 8;
 290        icv[2] = crc >> 16;
 291        icv[3] = crc >> 24;
 292
 293        for (k = 0; k < 4; k++) {
 294                i = (i + 1) & 0xff;
 295                j = (j + s[i]) & 0xff;
 296                swap(i, j);
 297                icv[k] ^= s[(s[i] + s[j]) & 0xff];
 298        }
 299
 300        return 0;
 301}
 302