* Herbert Xu | 2010-02-23 08:32:39 [+0800]:

>If you can find a way that allows arc4 to be used by multiple
>threads at the same time while storing less than 258 bytes in
>each thread, please let me know :)
:)

>No, what you could do is structure the IV differently based on the
>flag:
>
>struct arc4_iv {
>       union {
>               struct key {
>                       u8 key[256];
>                       u16 keylen;
>               };
>               struct iv {
>                       u8 S[256];
>                       u8 x, y;
>               };
>       };
>       u8 type;
>};
>
>This relies on the fact that we never use more than 256 bytes in
>the key so limiting its length is OK.

Okay. So so are we talking about something like that below then? This is
untested and I break other users bexcept lib80211_crypt_tkip. 

the state has been moved from ctx into iv. That way encrypt()/decrypt() can
deliver the same result for a given IV. If the IV is supplied as a plain
key then it wil be converted into a different internal state.
The name is now arc4.

Signed-off-by: Sebastian Andrzej Siewior <sebast...@breakpoint.cc>
---
 crypto/Kconfig                       |    2 +-
 crypto/arc4.c                        |  131 +++++++++++++++++++++++-----------
 crypto/testmgr.h                     |    3 +-
 drivers/net/Kconfig                  |    1 -
 drivers/net/wireless/hostap/Kconfig  |    2 -
 drivers/net/wireless/ipw2x00/Kconfig |    2 -
 include/crypto/arc4.h                |   26 +++++++
 net/mac80211/Kconfig                 |    1 -
 net/wireless/lib80211_crypt_tkip.c   |   10 ++-
 9 files changed, 123 insertions(+), 55 deletions(-)
 create mode 100644 include/crypto/arc4.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 81c185a..5fab1c3 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -561,7 +561,7 @@ config CRYPTO_ANUBIS
 
 config CRYPTO_ARC4
        tristate "ARC4 cipher algorithm"
-       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
        help
          ARC4 cipher algorithm.
 
diff --git a/crypto/arc4.c b/crypto/arc4.c
index 8be47e1..1b20463 100644
--- a/crypto/arc4.c
+++ b/crypto/arc4.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Cryptographic API
  *
  * ARC4 Cipher Algorithm
@@ -13,76 +13,122 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/arc4.h>
 
 #define ARC4_MIN_KEY_SIZE      1
 #define ARC4_MAX_KEY_SIZE      256
 #define ARC4_BLOCK_SIZE                1
 
-struct arc4_ctx {
-       u8 S[256];
-       u8 x, y;
-};
-
 static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
                        unsigned int key_len)
 {
-       struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
+       /*
+        * ARC4 is special: The user should supply an IV as struct arc4_iv and
+        * fill either the key or the iv.
+        */
+       return -EOPNOTSUPP;
+}
+
+static void arc4_key_to_iv(const u8 *in_key, u32 key_len, struct arc4_iv *iv)
+{
        int i, j = 0, k = 0;
 
-       ctx->x = 1;
-       ctx->y = 0;
+       iv->iv.x = 1;
+       iv->iv.y = 0;
 
-       for(i = 0; i < 256; i++)
-               ctx->S[i] = i;
+       for (i = 0; i < 256; i++)
+               iv->iv.S[i] = i;
 
-       for(i = 0; i < 256; i++)
+       for (i = 0; i < 256; i++)
        {
-               u8 a = ctx->S[i];
+               u8 a = iv->iv.S[i];
                j = (j + in_key[k] + a) & 0xff;
-               ctx->S[i] = ctx->S[j];
-               ctx->S[j] = a;
-               if(++k >= key_len)
+               iv->iv.S[i] = iv->iv.S[j];
+               iv->iv.S[j] = a;
+               if (++k >= key_len)
                        k = 0;
        }
-
-       return 0;
 }
 
-static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+static void arc4_ivsetup(struct arc4_iv *iv)
 {
-       struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct arc4_iv tmp_iv;
 
-       u8 *const S = ctx->S;
-       u8 x = ctx->x;
-       u8 y = ctx->y;
-       u8 a, b;
+       if (iv->type == ARC4_TYPE_IV)
+               return;
 
-       a = S[x];
-       y = (y + a) & 0xff;
-       b = S[y];
-       S[x] = b;
-       S[y] = a;
-       x = (x + 1) & 0xff;
-       *out++ = *in ^ S[(a + b) & 0xff];
+       memcpy(&tmp_iv, iv, sizeof(tmp_iv));
+       arc4_key_to_iv(tmp_iv.key.key, tmp_iv.key.key_len, iv);
+       iv->type = ARC4_TYPE_IV;
+}
+
+static int arc4_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+               struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       struct arc4_iv *aiv;
+       u8 *S;
+       u8 x;
+       u8 y;
+       u8 a, b;
+       int ret;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       ret = blkcipher_walk_virt(desc, &walk);
+       if (ret)
+               return ret;
+
+       aiv = (struct arc4_iv *)walk.iv;
+       arc4_ivsetup(aiv);
+
+       S = aiv->iv.S;
+       x = aiv->iv.x;
+       y = aiv->iv.y;
+
+       while (walk.nbytes) {
+               u8 *in = walk.src.virt.addr;
+               u8 *out = walk.dst.virt.addr;
+               u32 i;
+
+               for (i = 0; i < walk.nbytes; i++) {
+                       a = S[x];
+                       y = (y + a) & 0xff;
+                       b = S[y];
+                       S[x] = b;
+                       S[y] = a;
+                       x = (x + 1) & 0xff;
+                       *out = *in ^ S[(a + b) & 0xff];
+
+                       in++;
+                       out++;
+               }
+               ret = blkcipher_walk_done(desc, &walk, 0);
+               WARN_ON(ret < 0);
+       }
 
-       ctx->x = x;
-       ctx->y = y;
+       aiv->iv.x = x;
+       aiv->iv.y = y;
+       return ret;
 }
 
 static struct crypto_alg arc4_alg = {
        .cra_name               =       "arc4",
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
        .cra_blocksize          =       ARC4_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct arc4_ctx),
+       .cra_ctxsize            =       0,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(arc4_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       ARC4_MIN_KEY_SIZE,
-       .cia_max_keysize        =       ARC4_MAX_KEY_SIZE,
-       .cia_setkey             =       arc4_set_key,
-       .cia_encrypt            =       arc4_crypt,
-       .cia_decrypt            =       arc4_crypt } }
+       .cra_u                  =       { .blkcipher = {
+       .min_keysize            =       ARC4_MIN_KEY_SIZE,
+       .max_keysize            =       ARC4_MAX_KEY_SIZE,
+       .ivsize                 =       sizeof(struct arc4_iv),
+       .setkey                 =       arc4_set_key,
+       .encrypt                =       arc4_crypt,
+       .decrypt                =       arc4_crypt } }
 };
 
 static int __init arc4_init(void)
@@ -90,7 +136,6 @@ static int __init arc4_init(void)
        return crypto_register_alg(&arc4_alg);
 }
 
-
 static void __exit arc4_exit(void)
 {
        crypto_unregister_alg(&arc4_alg);
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index fb76517..423cf86 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -24,7 +24,8 @@
 #define MAX_TAP                        8
 
 #define MAX_KEYLEN             56
-#define MAX_IVLEN              32
+/* sizeof arc4_iv */
+#define MAX_IVLEN              260
 
 struct hash_testvec {
        /* only used with keyed hash algorithms */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c..ddce826 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3076,7 +3076,6 @@ config PPP_MPPE
        select CRYPTO
        select CRYPTO_SHA1
        select CRYPTO_ARC4
-       select CRYPTO_ECB
        ---help---
          Support for the MPPE Encryption protocol, as employed by the
         Microsoft Point-to-Point Tunneling Protocol.
diff --git a/drivers/net/wireless/hostap/Kconfig 
b/drivers/net/wireless/hostap/Kconfig
index 287d827..2548b56 100644
--- a/drivers/net/wireless/hostap/Kconfig
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -5,10 +5,8 @@ config HOSTAP
        select WEXT_PRIV
        select CRYPTO
        select CRYPTO_ARC4
-       select CRYPTO_ECB
        select CRYPTO_AES
        select CRYPTO_MICHAEL_MIC
-       select CRYPTO_ECB
        select CRC32
        select LIB80211
        select LIB80211_CRYPT_WEP
diff --git a/drivers/net/wireless/ipw2x00/Kconfig 
b/drivers/net/wireless/ipw2x00/Kconfig
index 2715b10..2f2b7d9 100644
--- a/drivers/net/wireless/ipw2x00/Kconfig
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -159,10 +159,8 @@ config LIBIPW
        select WEXT_SPY
        select CRYPTO
        select CRYPTO_ARC4
-       select CRYPTO_ECB
        select CRYPTO_AES
        select CRYPTO_MICHAEL_MIC
-       select CRYPTO_ECB
        select CRC32
        select LIB80211
        select LIB80211_CRYPT_WEP
diff --git a/include/crypto/arc4.h b/include/crypto/arc4.h
new file mode 100644
index 0000000..1423c92
--- /dev/null
+++ b/include/crypto/arc4.h
@@ -0,0 +1,26 @@
+#ifndef __CRYPTO_ARC4_H__
+#define __CRYPTO_ARC4_H__
+
+struct arc4_iv {
+       union {
+               struct arc4_key {
+                       u8 key[256];
+                       u16 key_len;
+               } key;
+               struct arc4_riv {
+                       u8 S[256];
+                       u8 x, y;
+               } iv;
+       };
+#define ARC4_TYPE_KEY   0
+#define ARC4_TYPE_IV    1
+       u8 type;
+};
+
+static inline void arc4_setup_iv(struct arc4_iv *iv, const u8 *key, u32 len)
+{
+       memcpy(iv->key.key, key, len);
+       iv->key.key_len = len;
+       iv->type = ARC4_TYPE_KEY;
+}
+#endif
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index a10d508..7925f44 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -2,7 +2,6 @@ config MAC80211
        tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
        depends on CFG80211
        select CRYPTO
-       select CRYPTO_ECB
        select CRYPTO_ARC4
        select CRYPTO_AES
        select CRC32
diff --git a/net/wireless/lib80211_crypt_tkip.c 
b/net/wireless/lib80211_crypt_tkip.c
index c362873..4c1290d 100644
--- a/net/wireless/lib80211_crypt_tkip.c
+++ b/net/wireless/lib80211_crypt_tkip.c
@@ -94,7 +94,7 @@ static void *lib80211_tkip_init(int key_idx)
 
        priv->key_idx = key_idx;
 
-       priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
+       priv->tx_tfm_arc4 = crypto_alloc_blkcipher("arc4", 0,
                                                CRYPTO_ALG_ASYNC);
        if (IS_ERR(priv->tx_tfm_arc4)) {
                printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
@@ -112,7 +112,7 @@ static void *lib80211_tkip_init(int key_idx)
                goto fail;
        }
 
-       priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
+       priv->rx_tfm_arc4 = crypto_alloc_blkcipher("arc4", 0,
                                                CRYPTO_ALG_ASYNC);
        if (IS_ERR(priv->rx_tfm_arc4)) {
                printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
@@ -360,6 +360,7 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int 
hdr_len, void *priv)
 {
        struct lib80211_tkip_data *tkey = priv;
        struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
+       struct arc4_iv *iv = crypto_blkcipher_crt(tkey->tx_tfm_arc4)->iv;
        int len;
        u8 rc4key[16], *pos, *icv;
        u32 crc;
@@ -392,7 +393,7 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int 
hdr_len, void *priv)
        icv[2] = crc >> 16;
        icv[3] = crc >> 24;
 
-       crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+       arc4_setup_iv(iv, rc4key, 16);
        sg_init_one(&sg, pos, len + 4);
        return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
 }
@@ -414,6 +415,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int 
hdr_len, void *priv)
 {
        struct lib80211_tkip_data *tkey = priv;
        struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
+       struct arc4_iv *iv = crypto_blkcipher_crt(tkey->rx_tfm_arc4)->iv;
        u8 rc4key[16];
        u8 keyidx, *pos;
        u32 iv32;
@@ -485,7 +487,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int 
hdr_len, void *priv)
 
        plen = skb->len - hdr_len - 12;
 
-       crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+       arc4_setup_iv(iv, rc4key, 16);
        sg_init_one(&sg, pos, plen + 4);
        if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
                if (net_ratelimit()) {
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to