Main Page | Data Structures | Directories | File List | Data Fields | Globals

hostap_crypt_wep.c

Go to the documentation of this file.
00001 /*
00002  * Host AP crypt: host-based WEP encryption implementation for Host AP driver
00003  *
00004  * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License version 2 as
00008  * published by the Free Software Foundation. See README and COPYING for
00009  * more details.
00010  */
00011 
00012 #include <linux/config.h>
00013 #include <linux/version.h>
00014 #include <linux/module.h>
00015 #include <linux/init.h>
00016 #include <linux/slab.h>
00017 #include <linux/random.h>
00018 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44))
00019 #include <linux/tqueue.h>
00020 #else
00021 #include <linux/workqueue.h>
00022 #endif
00023 #include <asm/string.h>
00024 
00025 #include "hostap_crypt.h"
00026 #include "hostap_compat.h"
00027 
00028 MODULE_AUTHOR("Jouni Malinen");
00029 MODULE_DESCRIPTION("Host AP crypt: WEP");
00030 MODULE_LICENSE("GPL");
00031 
00032 
00033 struct prism2_wep_data {
00034         u32 iv;
00035 #define WEP_KEYS 4
00036 #define WEP_KEY_LEN 13
00037         u8 keys[WEP_KEYS][WEP_KEY_LEN + 1];
00038         u8 key_lens[WEP_KEYS];
00039         int tx_key;
00040 };
00041 
00042 static const __u32 crc32_table[256] = {
00043         0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
00044         0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
00045         0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
00046         0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
00047         0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
00048         0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
00049         0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
00050         0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
00051         0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
00052         0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
00053         0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
00054         0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
00055         0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
00056         0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
00057         0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
00058         0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
00059         0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
00060         0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
00061         0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
00062         0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
00063         0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
00064         0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
00065         0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
00066         0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
00067         0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
00068         0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
00069         0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
00070         0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
00071         0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
00072         0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
00073         0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
00074         0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
00075         0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
00076         0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
00077         0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
00078         0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
00079         0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
00080         0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
00081         0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
00082         0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
00083         0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
00084         0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
00085         0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
00086         0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
00087         0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
00088         0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
00089         0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
00090         0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
00091         0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
00092         0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
00093         0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
00094         0x2d02ef8dL
00095 };
00096 
00097 
00098 static void * prism2_wep_init(void)
00099 {
00100         struct prism2_wep_data *priv;
00101 
00102 #ifdef NEW_MODULE_CODE
00103         if (!try_module_get(THIS_MODULE))
00104                 return NULL;
00105 #else
00106         MOD_INC_USE_COUNT;
00107 #endif
00108 
00109         priv = (struct prism2_wep_data *) kmalloc(sizeof(*priv), GFP_ATOMIC);
00110         if (priv == NULL) {
00111 #ifdef NEW_MODULE_CODE
00112                 module_put(THIS_MODULE);
00113 #else
00114                 MOD_DEC_USE_COUNT;
00115 #endif
00116                 return NULL;
00117         }
00118         memset(priv, 0, sizeof(*priv));
00119 
00120         /* start WEP IV from a random value */
00121         get_random_bytes(&priv->iv, 4);
00122 
00123         return priv;
00124 }
00125 
00126 
00127 static void prism2_wep_deinit(void *priv)
00128 {
00129         kfree(priv);
00130 #ifdef NEW_MODULE_CODE
00131         module_put(THIS_MODULE);
00132 #else
00133         MOD_DEC_USE_COUNT;
00134 #endif
00135 }
00136 
00137 
00138 /* Perform WEP encryption on given buffer. Buffer needs to has 4 bytes of
00139  * extra space (IV) in the beginning, then len bytes of data, and finally
00140  * 4 bytes of extra space (ICV). Both IV and ICV will be transmitted, so the
00141  * payload length increases with 8 bytes.
00142  *
00143  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
00144  */
00145 static int prism2_wep_encrypt(u8 *buf, int len, void *priv)
00146 {
00147         struct prism2_wep_data *wep = priv;
00148         u32 i, j, k, crc, klen;
00149         u8 S[256], key[WEP_KEY_LEN + 3];
00150         u8 kpos, *pos;
00151 #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
00152 
00153         klen = 3 + wep->key_lens[wep->tx_key];
00154 
00155         wep->iv++;
00156 
00157         /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
00158          * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
00159          * can be used to speedup attacks, so avoid using them. */
00160         if ((wep->iv & 0xff00) == 0xff00) {
00161                 u8 B = (wep->iv >> 16) & 0xff;
00162                 if (B >= 3 && B < klen)
00163                         wep->iv += 0x0100;
00164         }
00165 
00166         /* Prepend 24-bit IV to RC4 key and TX frame */
00167         pos = buf;
00168         *pos++ = key[0] = (wep->iv >> 16) & 0xff;
00169         *pos++ = key[1] = (wep->iv >> 8) & 0xff;
00170         *pos++ = key[2] = wep->iv & 0xff;
00171         *pos++ = wep->tx_key << 6;
00172 
00173         /* Copy rest of the WEP key (the secret part) */
00174         memcpy(key + 3, wep->keys[wep->tx_key],
00175                wep->key_lens[wep->tx_key]);
00176 
00177         /* Setup RC4 state */
00178         for (i = 0; i < 256; i++)
00179                 S[i] = i;
00180         j = 0;
00181         kpos = 0;
00182         for (i = 0; i < 256; i++) {
00183                 j = (j + S[i] + key[kpos]) & 0xff;
00184                 kpos++;
00185                 if (kpos >= klen)
00186                         kpos = 0;
00187                 S_SWAP(i, j);
00188         }
00189 
00190         /* Compute CRC32 over unencrypted data and apply RC4 to data */
00191         crc = ~0;
00192         i = j = 0;
00193         for (k = 0; k < len; k++) {
00194                 crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
00195                 i = (i + 1) & 0xff;
00196                 j = (j + S[i]) & 0xff;
00197                 S_SWAP(i, j);
00198                 *pos++ ^= S[(S[i] + S[j]) & 0xff];
00199         }
00200         crc = ~crc;
00201 
00202         /* Append little-endian CRC32 and encrypt it to produce ICV */
00203         pos[0] = crc;
00204         pos[1] = crc >> 8;
00205         pos[2] = crc >> 16;
00206         pos[3] = crc >> 24;
00207         for (k = 0; k < 4; k++) {
00208                 i = (i + 1) & 0xff;
00209                 j = (j + S[i]) & 0xff;
00210                 S_SWAP(i, j);
00211                 *pos++ ^= S[(S[i] + S[j]) & 0xff];
00212         }
00213 
00214         return len + 8;
00215 }
00216 
00217 
00218 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
00219  * the frame: IV (4 bytes), encrypted payload (including SNAP header),
00220  * ICV (4 bytes). len includes both IV and ICV.
00221  *
00222  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
00223  * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
00224  * is moved to beginning of buf and last 8 bytes of buf should be ignored.
00225  */
00226 static int prism2_wep_decrypt(u8 *buf, int len, void *priv)
00227 {
00228         struct prism2_wep_data *wep = priv;
00229         u32 i, j, k, crc, klen;
00230         u8 S[256], key[WEP_KEY_LEN + 3];
00231         u8 keyidx, kpos, *dpos, *cpos;
00232 
00233         if (len < 8)
00234                 return -1;
00235 
00236         key[0] = buf[0];
00237         key[1] = buf[1];
00238         key[2] = buf[2];
00239         keyidx = buf[3] >> 6;
00240 
00241         klen = 3 + wep->key_lens[keyidx];
00242 
00243         /* Copy rest of the WEP key (the secret part) */
00244         memcpy(key + 3, wep->keys[keyidx], wep->key_lens[keyidx]);
00245 
00246         /* Setup RC4 state */
00247         for (i = 0; i < 256; i++)
00248                 S[i] = i;
00249         j = 0;
00250         kpos = 0;
00251         for (i = 0; i < 256; i++) {
00252                 j = (j + S[i] + key[kpos]) & 0xff;
00253                 kpos++;
00254                 if (kpos >= klen)
00255                         kpos = 0;
00256                 S_SWAP(i, j);
00257         }
00258 
00259         /* Apply RC4 to data and compute CRC32 over decrypted data */
00260         dpos = buf;
00261         cpos = buf + 4;
00262         crc = ~0;
00263         i = j = 0;
00264         for (k = 0; k < len - 8; k++) {
00265                 i = (i + 1) & 0xff;
00266                 j = (j + S[i]) & 0xff;
00267                 S_SWAP(i, j);
00268                 *dpos = *cpos++ ^ S[(S[i] + S[j]) & 0xff];
00269                 crc = crc32_table[(crc ^ *dpos++) & 0xff] ^ (crc >> 8);
00270         }
00271         crc = ~crc;
00272 
00273         /* Encrypt little-endian CRC32 and verify that it matches with the
00274          * received ICV */
00275         dpos[0] = crc;
00276         dpos[1] = crc >> 8;
00277         dpos[2] = crc >> 16;
00278         dpos[3] = crc >> 24;
00279         for (k = 0; k < 4; k++) {
00280                 i = (i + 1) & 0xff;
00281                 j = (j + S[i]) & 0xff;
00282                 S_SWAP(i, j);
00283                 if ((*dpos++ ^ S[(S[i] + S[j]) & 0xff]) != *cpos++) {
00284                         /* ICV mismatch - drop frame */
00285                         return -1;
00286                 }
00287         }
00288 
00289         return len - 8;
00290 }
00291 
00292 
00293 static int prism2_wep_set_key(int idx, void *key, int len, void *priv)
00294 {
00295         struct prism2_wep_data *wep = priv;
00296 
00297         if (idx < 0 || idx >= WEP_KEYS || len < 0 || len > WEP_KEY_LEN)
00298                 return -1;
00299 
00300         memcpy(wep->keys[idx], key, len);
00301         wep->key_lens[idx] = len;
00302 
00303         return 0;
00304 }
00305 
00306 
00307 static int prism2_wep_get_key(int idx, void *key, int len, void *priv)
00308 {
00309         struct prism2_wep_data *wep = priv;
00310 
00311         if (idx < 0 || idx >= WEP_KEYS || len < wep->key_lens[idx])
00312                 return -1;
00313 
00314         memcpy(key, wep->keys[idx], wep->key_lens[idx]);
00315 
00316         return wep->key_lens[idx];
00317 }
00318 
00319 
00320 static int prism2_wep_set_key_idx(int idx, void *priv)
00321 {
00322         struct prism2_wep_data *wep = priv;
00323 
00324         if (idx < 0 || idx >= WEP_KEYS || wep->key_lens[idx] == 0)
00325                 return -1;
00326 
00327         wep->tx_key = idx;
00328 
00329         return 0;
00330 }
00331 
00332 
00333 static int prism2_wep_get_key_idx(void *priv)
00334 {
00335         struct prism2_wep_data *wep = priv;
00336         return wep->tx_key;
00337 }
00338 
00339 
00340 static struct hostap_crypto_ops hostap_crypt_wep = {
00341         .name                   = "WEP",
00342         .init                   = prism2_wep_init,
00343         .deinit                 = prism2_wep_deinit,
00344         .encrypt                = prism2_wep_encrypt,
00345         .decrypt                = prism2_wep_decrypt,
00346         .set_key                = prism2_wep_set_key,
00347         .get_key                = prism2_wep_get_key,
00348         .set_key_idx            = prism2_wep_set_key_idx,
00349         .get_key_idx            = prism2_wep_get_key_idx,
00350         .extra_prefix_len       = 4 /* IV */,
00351         .extra_postfix_len      = 4 /* ICV */
00352 };
00353 
00354 
00355 static int __init hostap_crypto_wep_init(void)
00356 {
00357         if (hostap_register_crypto_ops(&hostap_crypt_wep) < 0)
00358                 return -1;
00359 
00360         return 0;
00361 }
00362 
00363 
00364 static void __exit hostap_crypto_wep_exit(void)
00365 {
00366         hostap_unregister_crypto_ops(&hostap_crypt_wep);
00367 }
00368 
00369 
00370 module_init(hostap_crypto_wep_init);
00371 module_exit(hostap_crypto_wep_exit);

Generated on Mon Nov 21 15:58:09 2005 for openwifi by  doxygen 1.4.1