[Bluetooth] Make use of virtual devices tree
[pandora-kernel.git] / crypto / cipher.c
index dfd4bcf..9e03701 100644 (file)
 #include "internal.h"
 #include "scatterwalk.h"
 
+struct cipher_alg_compat {
+       unsigned int cia_min_keysize;
+       unsigned int cia_max_keysize;
+       int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
+                         unsigned int keylen);
+       void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+       void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+
+       unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
+                                       u8 *dst, const u8 *src,
+                                       unsigned int nbytes);
+       unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
+                                       u8 *dst, const u8 *src,
+                                       unsigned int nbytes);
+       unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
+                                       u8 *dst, const u8 *src,
+                                       unsigned int nbytes);
+       unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
+                                       u8 *dst, const u8 *src,
+                                       unsigned int nbytes);
+};
+
 static inline void xor_64(u8 *a, const u8 *b)
 {
        ((u32 *)a)[0] ^= ((u32 *)b)[0];
@@ -45,15 +67,10 @@ static unsigned int crypt_slow(const struct cipher_desc *desc,
        u8 buffer[bsize * 2 + alignmask];
        u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
        u8 *dst = src + bsize;
-       unsigned int n;
-
-       n = scatterwalk_copychunks(src, in, bsize, 0);
-       scatterwalk_advance(in, n);
 
+       scatterwalk_copychunks(src, in, bsize, 0);
        desc->prfn(desc, dst, src, bsize);
-
-       n = scatterwalk_copychunks(dst, out, bsize, 1);
-       scatterwalk_advance(out, n);
+       scatterwalk_copychunks(dst, out, bsize, 1);
 
        return bsize;
 }
@@ -64,12 +81,16 @@ static inline unsigned int crypt_fast(const struct cipher_desc *desc,
                                      unsigned int nbytes, u8 *tmp)
 {
        u8 *src, *dst;
+       u8 *real_src, *real_dst;
+
+       real_src = scatterwalk_map(in, 0);
+       real_dst = scatterwalk_map(out, 1);
 
-       src = in->data;
-       dst = scatterwalk_samebuf(in, out) ? src : out->data;
+       src = real_src;
+       dst = scatterwalk_samebuf(in, out) ? src : real_dst;
 
        if (tmp) {
-               memcpy(tmp, in->data, nbytes);
+               memcpy(tmp, src, nbytes);
                src = tmp;
                dst = tmp;
        }
@@ -77,7 +98,10 @@ static inline unsigned int crypt_fast(const struct cipher_desc *desc,
        nbytes = desc->prfn(desc, dst, src, nbytes);
 
        if (tmp)
-               memcpy(out->data, tmp, nbytes);
+               memcpy(real_dst, tmp, nbytes);
+
+       scatterwalk_unmap(real_src, 0);
+       scatterwalk_unmap(real_dst, 1);
 
        scatterwalk_advance(in, nbytes);
        scatterwalk_advance(out, nbytes);
@@ -126,9 +150,6 @@ static int crypt(const struct cipher_desc *desc,
                        tmp = (u8 *)buffer;
                }
 
-               scatterwalk_map(&walk_in, 0);
-               scatterwalk_map(&walk_out, 1);
-
                n = scatterwalk_clamp(&walk_in, n);
                n = scatterwalk_clamp(&walk_out, n);
 
@@ -145,7 +166,7 @@ static int crypt(const struct cipher_desc *desc,
                if (!nbytes)
                        break;
 
-               crypto_yield(tfm);
+               crypto_yield(tfm->crt_flags);
        }
 
        if (buffer)
@@ -187,7 +208,7 @@ static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
        void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
        int bsize = crypto_tfm_alg_blocksize(tfm);
 
-       void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
        u8 *iv = desc->info;
        unsigned int done = 0;
 
@@ -195,7 +216,7 @@ static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
 
        do {
                xor(iv, src);
-               fn(crypto_tfm_ctx(tfm), dst, iv);
+               fn(tfm, dst, iv);
                memcpy(iv, dst, bsize);
 
                src += bsize;
@@ -212,12 +233,13 @@ static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
        struct crypto_tfm *tfm = desc->tfm;
        void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
        int bsize = crypto_tfm_alg_blocksize(tfm);
+       unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm);
 
-       u8 stack[src == dst ? bsize : 0];
-       u8 *buf = stack;
+       u8 stack[src == dst ? bsize + alignmask : 0];
+       u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
        u8 **dst_p = src == dst ? &buf : &dst;
 
-       void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
        u8 *iv = desc->info;
        unsigned int done = 0;
 
@@ -226,7 +248,7 @@ static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
        do {
                u8 *tmp_dst = *dst_p;
 
-               fn(crypto_tfm_ctx(tfm), tmp_dst, src);
+               fn(tfm, tmp_dst, src);
                xor(tmp_dst, iv);
                memcpy(iv, src, bsize);
                if (tmp_dst != dst)
@@ -244,13 +266,13 @@ static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst,
 {
        struct crypto_tfm *tfm = desc->tfm;
        int bsize = crypto_tfm_alg_blocksize(tfm);
-       void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
        unsigned int done = 0;
 
        nbytes -= bsize;
 
        do {
-               fn(crypto_tfm_ctx(tfm), dst, src);
+               fn(tfm, dst, src);
 
                src += bsize;
                dst += bsize;
@@ -263,12 +285,12 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
 {
        struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
        
+       tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
        if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
                tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
                return -EINVAL;
        } else
-               return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen,
-                                      &tfm->crt_flags);
+               return cia->cia_setkey(tfm, key, keylen);
 }
 
 static int ecb_encrypt(struct crypto_tfm *tfm,
@@ -276,7 +298,7 @@ static int ecb_encrypt(struct crypto_tfm *tfm,
                        struct scatterlist *src, unsigned int nbytes)
 {
        struct cipher_desc desc;
-       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+       struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
 
        desc.tfm = tfm;
        desc.crfn = cipher->cia_encrypt;
@@ -291,7 +313,7 @@ static int ecb_decrypt(struct crypto_tfm *tfm,
                       unsigned int nbytes)
 {
        struct cipher_desc desc;
-       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+       struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
 
        desc.tfm = tfm;
        desc.crfn = cipher->cia_decrypt;
@@ -306,7 +328,7 @@ static int cbc_encrypt(struct crypto_tfm *tfm,
                       unsigned int nbytes)
 {
        struct cipher_desc desc;
-       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+       struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
 
        desc.tfm = tfm;
        desc.crfn = cipher->cia_encrypt;
@@ -322,7 +344,7 @@ static int cbc_encrypt_iv(struct crypto_tfm *tfm,
                           unsigned int nbytes, u8 *iv)
 {
        struct cipher_desc desc;
-       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+       struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
 
        desc.tfm = tfm;
        desc.crfn = cipher->cia_encrypt;
@@ -338,7 +360,7 @@ static int cbc_decrypt(struct crypto_tfm *tfm,
                       unsigned int nbytes)
 {
        struct cipher_desc desc;
-       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+       struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
 
        desc.tfm = tfm;
        desc.crfn = cipher->cia_decrypt;
@@ -354,7 +376,7 @@ static int cbc_decrypt_iv(struct crypto_tfm *tfm,
                           unsigned int nbytes, u8 *iv)
 {
        struct cipher_desc desc;
-       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+       struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher;
 
        desc.tfm = tfm;
        desc.crfn = cipher->cia_decrypt;
@@ -387,17 +409,67 @@ int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
        return 0;
 }
 
+static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
+                                             const u8 *),
+                                  struct crypto_tfm *tfm,
+                                  u8 *dst, const u8 *src)
+{
+       unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+       unsigned int size = crypto_tfm_alg_blocksize(tfm);
+       u8 buffer[size + alignmask];
+       u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+
+       memcpy(tmp, src, size);
+       fn(tfm, tmp, tmp);
+       memcpy(dst, tmp, size);
+}
+
+static void cipher_encrypt_unaligned(struct crypto_tfm *tfm,
+                                    u8 *dst, const u8 *src)
+{
+       unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+       if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
+               cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src);
+               return;
+       }
+
+       cipher->cia_encrypt(tfm, dst, src);
+}
+
+static void cipher_decrypt_unaligned(struct crypto_tfm *tfm,
+                                    u8 *dst, const u8 *src)
+{
+       unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+       if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
+               cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src);
+               return;
+       }
+
+       cipher->cia_decrypt(tfm, dst, src);
+}
+
 int crypto_init_cipher_ops(struct crypto_tfm *tfm)
 {
        int ret = 0;
        struct cipher_tfm *ops = &tfm->crt_cipher;
+       struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
 
        ops->cit_setkey = setkey;
+       ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ?
+               cipher_encrypt_unaligned : cipher->cia_encrypt;
+       ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
+               cipher_decrypt_unaligned : cipher->cia_decrypt;
 
        switch (tfm->crt_cipher.cit_mode) {
        case CRYPTO_TFM_MODE_ECB:
                ops->cit_encrypt = ecb_encrypt;
                ops->cit_decrypt = ecb_decrypt;
+               ops->cit_encrypt_iv = nocrypt_iv;
+               ops->cit_decrypt_iv = nocrypt_iv;
                break;
                
        case CRYPTO_TFM_MODE_CBC: