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