root/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. prism2_wep_init
  2. prism2_wep_deinit
  3. prism2_wep_encrypt
  4. prism2_wep_decrypt
  5. prism2_wep_set_key
  6. prism2_wep_get_key
  7. prism2_wep_print_stats
  8. ieee80211_crypto_wep_init
  9. ieee80211_crypto_wep_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Host AP crypt: host-based WEP encryption implementation for Host AP driver
   4  *
   5  * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/init.h>
  10 #include <linux/slab.h>
  11 #include <linux/random.h>
  12 #include <linux/skbuff.h>
  13 #include <linux/string.h>
  14 
  15 #include "ieee80211.h"
  16 
  17 #include <crypto/skcipher.h>
  18 #include <linux/scatterlist.h>
  19 #include <linux/crc32.h>
  20 
  21 MODULE_AUTHOR("Jouni Malinen");
  22 MODULE_DESCRIPTION("Host AP crypt: WEP");
  23 MODULE_LICENSE("GPL");
  24 
  25 struct prism2_wep_data {
  26         u32 iv;
  27 #define WEP_KEY_LEN 13
  28         u8 key[WEP_KEY_LEN + 1];
  29         u8 key_len;
  30         u8 key_idx;
  31         struct crypto_sync_skcipher *tx_tfm;
  32         struct crypto_sync_skcipher *rx_tfm;
  33 };
  34 
  35 
  36 static void *prism2_wep_init(int keyidx)
  37 {
  38         struct prism2_wep_data *priv;
  39 
  40         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  41         if (!priv)
  42                 return NULL;
  43         priv->key_idx = keyidx;
  44 
  45         priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
  46         if (IS_ERR(priv->tx_tfm))
  47                 goto free_priv;
  48         priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
  49         if (IS_ERR(priv->rx_tfm))
  50                 goto free_tx;
  51 
  52         /* start WEP IV from a random value */
  53         get_random_bytes(&priv->iv, 4);
  54 
  55         return priv;
  56 free_tx:
  57         crypto_free_sync_skcipher(priv->tx_tfm);
  58 free_priv:
  59         kfree(priv);
  60         return NULL;
  61 }
  62 
  63 
  64 static void prism2_wep_deinit(void *priv)
  65 {
  66         struct prism2_wep_data *_priv = priv;
  67 
  68         if (_priv) {
  69                 crypto_free_sync_skcipher(_priv->tx_tfm);
  70                 crypto_free_sync_skcipher(_priv->rx_tfm);
  71         }
  72         kfree(priv);
  73 }
  74 
  75 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
  76  * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
  77  * so the payload length increases with 8 bytes.
  78  *
  79  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  80  */
  81 static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
  82 {
  83         struct prism2_wep_data *wep = priv;
  84         u32 klen, len;
  85         u8 key[WEP_KEY_LEN + 3];
  86         u8 *pos;
  87         struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
  88         u32 crc;
  89         u8 *icv;
  90         struct scatterlist sg;
  91         int err;
  92 
  93         if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
  94             skb->len < hdr_len)
  95                 return -1;
  96 
  97         len = skb->len - hdr_len;
  98         pos = skb_push(skb, 4);
  99         memmove(pos, pos + 4, hdr_len);
 100         pos += hdr_len;
 101 
 102         klen = 3 + wep->key_len;
 103 
 104         wep->iv++;
 105 
 106         /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
 107          * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
 108          * can be used to speedup attacks, so avoid using them.
 109          */
 110         if ((wep->iv & 0xff00) == 0xff00) {
 111                 u8 B = (wep->iv >> 16) & 0xff;
 112 
 113                 if (B >= 3 && B < klen)
 114                         wep->iv += 0x0100;
 115         }
 116 
 117         /* Prepend 24-bit IV to RC4 key and TX frame */
 118         *pos++ = key[0] = (wep->iv >> 16) & 0xff;
 119         *pos++ = key[1] = (wep->iv >> 8) & 0xff;
 120         *pos++ = key[2] = wep->iv & 0xff;
 121         *pos++ = wep->key_idx << 6;
 122 
 123         /* Copy rest of the WEP key (the secret part) */
 124         memcpy(key + 3, wep->key, wep->key_len);
 125 
 126         if (!tcb_desc->bHwSec) {
 127                 SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
 128 
 129                 /* Append little-endian CRC32 and encrypt it to produce ICV */
 130                 crc = ~crc32_le(~0, pos, len);
 131                 icv = skb_put(skb, 4);
 132                 icv[0] = crc;
 133                 icv[1] = crc >> 8;
 134                 icv[2] = crc >> 16;
 135                 icv[3] = crc >> 24;
 136 
 137                 crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen);
 138                 sg_init_one(&sg, pos, len + 4);
 139 
 140                 skcipher_request_set_sync_tfm(req, wep->tx_tfm);
 141                 skcipher_request_set_callback(req, 0, NULL, NULL);
 142                 skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
 143 
 144                 err = crypto_skcipher_encrypt(req);
 145                 skcipher_request_zero(req);
 146                 return err;
 147         }
 148 
 149         return 0;
 150 }
 151 
 152 
 153 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
 154  * the frame: IV (4 bytes), encrypted payload (including SNAP header),
 155  * ICV (4 bytes). len includes both IV and ICV.
 156  *
 157  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
 158  * failure. If frame is OK, IV and ICV will be removed.
 159  */
 160 static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 161 {
 162         struct prism2_wep_data *wep = priv;
 163         u32  klen, plen;
 164         u8 key[WEP_KEY_LEN + 3];
 165         u8 keyidx, *pos;
 166         struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
 167         u32 crc;
 168         u8 icv[4];
 169         struct scatterlist sg;
 170         int err;
 171 
 172         if (skb->len < hdr_len + 8)
 173                 return -1;
 174 
 175         pos = skb->data + hdr_len;
 176         key[0] = *pos++;
 177         key[1] = *pos++;
 178         key[2] = *pos++;
 179         keyidx = *pos++ >> 6;
 180         if (keyidx != wep->key_idx)
 181                 return -1;
 182 
 183         klen = 3 + wep->key_len;
 184 
 185         /* Copy rest of the WEP key (the secret part) */
 186         memcpy(key + 3, wep->key, wep->key_len);
 187 
 188         /* Apply RC4 to data and compute CRC32 over decrypted data */
 189         plen = skb->len - hdr_len - 8;
 190 
 191         if (!tcb_desc->bHwSec) {
 192                 SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
 193 
 194                 crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen);
 195                 sg_init_one(&sg, pos, plen + 4);
 196 
 197                 skcipher_request_set_sync_tfm(req, wep->rx_tfm);
 198                 skcipher_request_set_callback(req, 0, NULL, NULL);
 199                 skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
 200 
 201                 err = crypto_skcipher_decrypt(req);
 202                 skcipher_request_zero(req);
 203                 if (err)
 204                         return -7;
 205 
 206                 crc = ~crc32_le(~0, pos, plen);
 207                 icv[0] = crc;
 208                 icv[1] = crc >> 8;
 209                 icv[2] = crc >> 16;
 210                 icv[3] = crc >> 24;
 211                 if (memcmp(icv, pos + plen, 4) != 0) {
 212                         /* ICV mismatch - drop frame */
 213                         return -2;
 214                 }
 215         }
 216         /* Remove IV and ICV */
 217         memmove(skb->data + 4, skb->data, hdr_len);
 218         skb_pull(skb, 4);
 219         skb_trim(skb, skb->len - 4);
 220 
 221         return 0;
 222 }
 223 
 224 
 225 static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
 226 {
 227         struct prism2_wep_data *wep = priv;
 228 
 229         if (len < 0 || len > WEP_KEY_LEN)
 230                 return -1;
 231 
 232         memcpy(wep->key, key, len);
 233         wep->key_len = len;
 234 
 235         return 0;
 236 }
 237 
 238 
 239 static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
 240 {
 241         struct prism2_wep_data *wep = priv;
 242 
 243         if (len < wep->key_len)
 244                 return -1;
 245 
 246         memcpy(key, wep->key, wep->key_len);
 247 
 248         return wep->key_len;
 249 }
 250 
 251 
 252 static char *prism2_wep_print_stats(char *p, void *priv)
 253 {
 254         struct prism2_wep_data *wep = priv;
 255 
 256         p += sprintf(p, "key[%d] alg=WEP len=%d\n",
 257                      wep->key_idx, wep->key_len);
 258         return p;
 259 }
 260 
 261 
 262 static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
 263         .name                   = "WEP",
 264         .init                   = prism2_wep_init,
 265         .deinit                 = prism2_wep_deinit,
 266         .encrypt_mpdu           = prism2_wep_encrypt,
 267         .decrypt_mpdu           = prism2_wep_decrypt,
 268         .encrypt_msdu           = NULL,
 269         .decrypt_msdu           = NULL,
 270         .set_key                = prism2_wep_set_key,
 271         .get_key                = prism2_wep_get_key,
 272         .print_stats            = prism2_wep_print_stats,
 273         .extra_prefix_len       = 4, /* IV */
 274         .extra_postfix_len      = 4, /* ICV */
 275         .owner                  = THIS_MODULE,
 276 };
 277 
 278 int __init ieee80211_crypto_wep_init(void)
 279 {
 280         return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
 281 }
 282 
 283 void __exit ieee80211_crypto_wep_exit(void)
 284 {
 285         ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
 286 }
 287 

/* [<][>][^][v][top][bottom][index][help] */