-#include "scatterwalk.h"
-
-struct cipher_desc {
- struct crypto_tfm *tfm;
- void (*crfn)(void *ctx, u8 *dst, const u8 *src);
- unsigned int (*prfn)(const struct cipher_desc *desc, u8 *dst,
- const u8 *src, unsigned int nbytes);
- void *info;
-};
-
-static inline void xor_64(u8 *a, const u8 *b)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static inline void xor_128(u8 *a, const u8 *b)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
- ((u32 *)a)[2] ^= ((u32 *)b)[2];
- ((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
-static unsigned int crypt_slow(const struct cipher_desc *desc,
- struct scatter_walk *in,
- struct scatter_walk *out, unsigned int bsize)
-{
- u8 src[bsize];
- u8 dst[bsize];
- unsigned int n;
-
- n = scatterwalk_copychunks(src, in, bsize, 0);
- scatterwalk_advance(in, n);
-
- desc->prfn(desc, dst, src, bsize);
-
- n = scatterwalk_copychunks(dst, out, bsize, 1);
- scatterwalk_advance(out, n);
-
- return bsize;
-}
-
-static inline unsigned int crypt_fast(const struct cipher_desc *desc,
- struct scatter_walk *in,
- struct scatter_walk *out,
- unsigned int nbytes)
-{
- u8 *src, *dst;
-
- src = in->data;
- dst = scatterwalk_samebuf(in, out) ? src : out->data;
-
- nbytes = desc->prfn(desc, dst, src, nbytes);
-
- scatterwalk_advance(in, nbytes);
- scatterwalk_advance(out, nbytes);
-
- return nbytes;
-}
-
-/*
- * Generic encrypt/decrypt wrapper for ciphers, handles operations across
- * multiple page boundaries by using temporary blocks. In user context,
- * the kernel is given a chance to schedule us once per page.
- */
-static int crypt(const struct cipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- struct scatter_walk walk_in, walk_out;
- struct crypto_tfm *tfm = desc->tfm;
- const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
-
- if (!nbytes)
- return 0;
-
- if (nbytes % bsize) {
- tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
- return -EINVAL;
- }
-
- scatterwalk_start(&walk_in, src);
- scatterwalk_start(&walk_out, dst);
-
- for(;;) {
- unsigned int n;
-
- scatterwalk_map(&walk_in, 0);
- scatterwalk_map(&walk_out, 1);
-
- n = scatterwalk_clamp(&walk_in, nbytes);
- n = scatterwalk_clamp(&walk_out, n);
-
- if (likely(n >= bsize))
- n = crypt_fast(desc, &walk_in, &walk_out, n);
- else
- n = crypt_slow(desc, &walk_in, &walk_out, bsize);
-
- nbytes -= n;
-
- scatterwalk_done(&walk_in, 0, nbytes);
- scatterwalk_done(&walk_out, 1, nbytes);
-
- if (!nbytes)
- return 0;
-
- crypto_yield(tfm);
- }
-}
-
-static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
- u8 *dst, const u8 *src,
- unsigned int nbytes)
-{
- 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);
-
- void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
- u8 *iv = desc->info;
- unsigned int done = 0;
-
- do {
- xor(iv, src);
- fn(crypto_tfm_ctx(tfm), dst, iv);
- memcpy(iv, dst, bsize);
-
- src += bsize;
- dst += bsize;
- } while ((done += bsize) < nbytes);
-
- return done;
-}