linux/drivers/staging/wlan-ng/p80211wep.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
   2/* src/p80211/p80211wep.c
   3 *
   4 * WEP encode/decode for P80211.
   5 *
   6 * Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
   7 * --------------------------------------------------------------------
   8 *
   9 * linux-wlan
  10 *
  11 *   The contents of this file are subject to the Mozilla Public
  12 *   License Version 1.1 (the "License"); you may not use this file
  13 *   except in compliance with the License. You may obtain a copy of
  14 *   the License at http://www.mozilla.org/MPL/
  15 *
  16 *   Software distributed under the License is distributed on an "AS
  17 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  18 *   implied. See the License for the specific language governing
  19 *   rights and limitations under the License.
  20 *
  21 *   Alternatively, the contents of this file may be used under the
  22 *   terms of the GNU Public License version 2 (the "GPL"), in which
  23 *   case the provisions of the GPL are applicable instead of the
  24 *   above.  If you wish to allow the use of your version of this file
  25 *   only under the terms of the GPL and not to allow others to use
  26 *   your version of this file under the MPL, indicate your decision
  27 *   by deleting the provisions above and replace them with the notice
  28 *   and other provisions required by the GPL.  If you do not delete
  29 *   the provisions above, a recipient may use your version of this
  30 *   file under either the MPL or the GPL.
  31 *
  32 * --------------------------------------------------------------------
  33 *
  34 * Inquiries regarding the linux-wlan Open Source project can be
  35 * made directly to:
  36 *
  37 * AbsoluteValue Systems Inc.
  38 * info@linux-wlan.com
  39 * http://www.linux-wlan.com
  40 *
  41 * --------------------------------------------------------------------
  42 *
  43 * Portions of the development of this software were funded by
  44 * Intersil Corporation as part of PRISM(R) chipset product development.
  45 *
  46 * --------------------------------------------------------------------
  47 */
  48
  49/*================================================================*/
  50/* System Includes */
  51
  52#include <linux/crc32.h>
  53#include <linux/netdevice.h>
  54#include <linux/wireless.h>
  55#include <linux/random.h>
  56#include <linux/kernel.h>
  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
  65/* keylen in bytes! */
  66
  67int wep_change_key(struct wlandevice *wlandev, int keynum, u8 *key, int keylen)
  68{
  69        if (keylen < 0)
  70                return -1;
  71        if (keylen >= MAX_KEYLEN)
  72                return -1;
  73        if (!key)
  74                return -1;
  75        if (keynum < 0)
  76                return -1;
  77        if (keynum >= NUM_WEPKEYS)
  78                return -1;
  79
  80        wlandev->wep_keylens[keynum] = keylen;
  81        memcpy(wlandev->wep_keys[keynum], key, keylen);
  82
  83        return 0;
  84}
  85
  86/*
  87 * 4-byte IV at start of buffer, 4-byte ICV at end of buffer.
  88 * if successful, buf start is payload begin, length -= 8;
  89 */
  90int wep_decrypt(struct wlandevice *wlandev, u8 *buf, u32 len, int key_override,
  91                u8 *iv, u8 *icv)
  92{
  93        u32 i, j, k, crc, keylen;
  94        u8 s[256], key[64], c_crc[4];
  95        u8 keyidx;
  96
  97        /* Needs to be at least 8 bytes of payload */
  98        if (len <= 0)
  99                return -1;
 100
 101        /* initialize the first bytes of the key from the IV */
 102        key[0] = iv[0];
 103        key[1] = iv[1];
 104        key[2] = iv[2];
 105        keyidx = WEP_KEY(iv[3]);
 106
 107        if (key_override >= 0)
 108                keyidx = key_override;
 109
 110        if (keyidx >= NUM_WEPKEYS)
 111                return -2;
 112
 113        keylen = wlandev->wep_keylens[keyidx];
 114
 115        if (keylen == 0)
 116                return -3;
 117
 118        /* copy the rest of the key over from the designated key */
 119        memcpy(key + 3, wlandev->wep_keys[keyidx], keylen);
 120
 121        keylen += 3;            /* add in IV bytes */
 122
 123        /* set up the RC4 state */
 124        for (i = 0; i < 256; i++)
 125                s[i] = i;
 126        j = 0;
 127        for (i = 0; i < 256; i++) {
 128                j = (j + s[i] + key[i % keylen]) & 0xff;
 129                swap(i, j);
 130        }
 131
 132        /* Apply the RC4 to the data, update the CRC32 */
 133        i = 0;
 134        j = 0;
 135        for (k = 0; k < len; k++) {
 136                i = (i + 1) & 0xff;
 137                j = (j + s[i]) & 0xff;
 138                swap(i, j);
 139                buf[k] ^= s[(s[i] + s[j]) & 0xff];
 140        }
 141        crc = ~crc32_le(~0, buf, len);
 142
 143        /* now let's check the crc */
 144        c_crc[0] = crc;
 145        c_crc[1] = crc >> 8;
 146        c_crc[2] = crc >> 16;
 147        c_crc[3] = crc >> 24;
 148
 149        for (k = 0; k < 4; k++) {
 150                i = (i + 1) & 0xff;
 151                j = (j + s[i]) & 0xff;
 152                swap(i, j);
 153                if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
 154                        return -(4 | (k << 4)); /* ICV mismatch */
 155        }
 156
 157        return 0;
 158}
 159
 160/* encrypts in-place. */
 161int wep_encrypt(struct wlandevice *wlandev, u8 *buf,
 162                u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv)
 163{
 164        u32 i, j, k, crc, keylen;
 165        u8 s[256], key[64];
 166
 167        /* no point in WEPping an empty frame */
 168        if (len <= 0)
 169                return -1;
 170
 171        /* we need to have a real key.. */
 172        if (keynum >= NUM_WEPKEYS)
 173                return -2;
 174        keylen = wlandev->wep_keylens[keynum];
 175        if (keylen <= 0)
 176                return -3;
 177
 178        /* use a random IV.  And skip known weak ones. */
 179        get_random_bytes(iv, 3);
 180        while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
 181                get_random_bytes(iv, 3);
 182
 183        iv[3] = (keynum & 0x03) << 6;
 184
 185        key[0] = iv[0];
 186        key[1] = iv[1];
 187        key[2] = iv[2];
 188
 189        /* copy the rest of the key over from the designated key */
 190        memcpy(key + 3, wlandev->wep_keys[keynum], keylen);
 191
 192        keylen += 3;            /* add in IV bytes */
 193
 194        /* set up the RC4 state */
 195        for (i = 0; i < 256; i++)
 196                s[i] = i;
 197        j = 0;
 198        for (i = 0; i < 256; i++) {
 199                j = (j + s[i] + key[i % keylen]) & 0xff;
 200                swap(i, j);
 201        }
 202
 203        /* Update CRC32 then apply RC4 to the data */
 204        i = 0;
 205        j = 0;
 206        for (k = 0; k < len; k++) {
 207                i = (i + 1) & 0xff;
 208                j = (j + s[i]) & 0xff;
 209                swap(i, j);
 210                dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
 211        }
 212        crc = ~crc32_le(~0, buf, len);
 213
 214        /* now let's encrypt the crc */
 215        icv[0] = crc;
 216        icv[1] = crc >> 8;
 217        icv[2] = crc >> 16;
 218        icv[3] = crc >> 24;
 219
 220        for (k = 0; k < 4; k++) {
 221                i = (i + 1) & 0xff;
 222                j = (j + s[i]) & 0xff;
 223                swap(i, j);
 224                icv[k] ^= s[(s[i] + s[j]) & 0xff];
 225        }
 226
 227        return 0;
 228}
 229