p80211wep.c (5732B)
1// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) 2/* 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}