[COMMON] crypto: support diskcipher
authorBoojin Kim <boojin.kim@samsung.com>
Wed, 24 Jan 2018 08:00:12 +0000 (17:00 +0900)
committerJaeHun Jung <jh0801.jung@samsung.com>
Tue, 8 May 2018 08:20:58 +0000 (17:20 +0900)
Change-Id: I7b01a64020d6be4ec0c4344d71e6629db08fe2c6
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
crypto/Kconfig
crypto/Makefile
crypto/diskcipher.c [new file with mode: 0644]
crypto/testmgr.c
include/crypto/diskcipher.h [new file with mode: 0644]
include/linux/crypto.h

index d8b96515abe8ec7a388f8115cd7aee65c80185a3..ad583228e0cdfa405b2c0465bc27785676a483af 100644 (file)
@@ -1627,6 +1627,13 @@ config CRYPTO_TWOFISH_AVX_X86_64
          See also:
          <http://www.schneier.com/twofish.html>
 
+config CRYPTO_DISKCIPHER
+       bool "Diskcipher support"
+       default n
+       help
+        Diskcipher support the crypt operation of the block host device
+        that has inline crypto engine.
+
 comment "Compression"
 
 config CRYPTO_DEFLATE
index d953cc1d57c4d50e7ab1ef48e15eb66c41a7b3e7..62b9758d00bb9d4068b9121229c1e2f3fcf4241f 100644 (file)
@@ -135,6 +135,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
 obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
 obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
+obj-$(CONFIG_CRYPTO_DISKCIPHER) += diskcipher.o
 
 ecdh_generic-y := ecc.o
 ecdh_generic-y += ecdh.o
diff --git a/crypto/diskcipher.c b/crypto/diskcipher.c
new file mode 100644 (file)
index 0000000..78f1f03
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/diskcipher.h>
+
+#include "internal.h"
+
+#ifdef EANBLE_DISKCIPHER_DEBUG
+#include <crypto/fmp.h>
+#include <linux/mm_types.h>
+
+#define DUMP_MAX 20
+
+enum diskcipher_api {
+       DISKC_API_ALLOC, DISKC_API_FREE, DISKC_API_SET,
+       DISKC_API_GET, DISKC_API_CRYPT, DISKC_API_CLEAR, DISKC_API_MAX,
+};
+
+struct dump_err {
+       struct page *page;
+       struct bio bio;
+       struct fmp_crypto_info ci;
+       enum diskcipher_api api;
+};
+
+struct diskc_debug_info {
+       struct dump_err dump[DUMP_MAX];
+       int err;
+       u32 cnt[DISKC_API_MAX][2];
+};
+
+static struct diskc_debug_info diskc_dbg;
+
+static void print_err(void)
+{
+       int i, j;
+       struct bio_vec *bv;     /* bio page list */
+       struct bio *bio;
+       struct fmp_crypto_info *ci;
+       struct diskc_debug_info *dbg = &diskc_dbg;
+
+       for (j = 0; j < dbg->err; j++) {
+               bio = &dbg->dump[j].bio;
+               ci = &dbg->dump[j].ci;
+
+               if (bio) {
+                       pr_info
+                           ("%s(%d/%d): bio:%p ci:%p page:%p flag:%x, opf:%x, crypt:%p\n",
+                            __func__, j, dbg->err, bio, ci, &dbg->dump[j].page,
+                            bio->bi_flags, bio->bi_opf, bio->bi_aux_private);
+                       print_hex_dump(KERN_CONT, "bio:", DUMP_PREFIX_OFFSET,
+                               16, 1, bio, sizeof(struct bio), false);
+                       for (i = 0; i < bio->bi_max_vecs; i++) {
+                               bv = &bio->bi_io_vec[i];
+                               pr_info("bv[%d] page:%p len:%d offset:%d\n",
+                                       i, bv->bv_page, bv->bv_len, bv->bv_offset);
+                       }
+               }
+
+               if (ci) {
+                       pr_info("[ci] key_size:%d algo_mode:%d\n",
+                               ci->key_size, ci->algo_mode);
+                       print_hex_dump(KERN_CONT, "key:", DUMP_PREFIX_OFFSET,
+                                      16, 1, ci->key, sizeof(ci->key), false);
+               }
+       }
+}
+
+static void dump_err(struct crypto_diskcipher *ci, enum diskcipher_api api,
+             struct bio *bio, struct page *page)
+{
+       struct diskc_debug_info *dbg = &diskc_dbg;
+
+       if ((dbg->err < DUMP_MAX) && ci) {
+               struct crypto_tfm *tfm = crypto_diskcipher_tfm(ci);
+
+               dbg->dump[dbg->err].api = api;
+               memcpy(&dbg->dump[dbg->err].ci, crypto_tfm_ctx(tfm),
+                      sizeof(struct fmp_crypto_info));
+
+               if (page)
+                       dbg->dump[dbg->err].page = page;
+               if (bio)
+                       memcpy(&dbg->dump[dbg->err].bio, bio,
+                               sizeof(struct bio));
+       }
+       dbg->err++;
+}
+
+static inline void disckipher_log(enum diskcipher_api api, int ret,
+                              struct crypto_diskcipher *ci)
+{
+       struct diskc_debug_info *dbg = &diskc_dbg;
+
+       dbg->cnt[api][0]++;
+       if (ret) {
+               dbg->cnt[api][1]++;
+               if (ci)
+                       dump_err(ci, api, NULL, NULL);
+       }
+}
+
+static void disckipher_log_show(struct seq_file *m)
+{
+       int i;
+       char name[DISKC_API_MAX][8]
+           = {"alloc", "free", "set", "get", "crypt", "clear"};
+       struct diskc_debug_info *dbg = &diskc_dbg;
+
+       for (i = 0; i < DISKC_API_MAX; i++)
+               seq_printf(m, "%s\t: %6u(err:%u)\n",
+                       name[i], dbg->cnt[i][0], dbg->cnt[i][1]);
+
+       if (dbg->err)
+               print_err();
+}
+
+/* check diskcipher for FBE */
+void crypto_diskcipher_check(struct bio *bio, struct page *page)
+{
+#ifdef FBE_DEBUG
+       int ret = 0;
+       struct crypto_diskcipher *ci = NULL;
+
+       if (page && !PageAnon(page) && bio)
+               if (page->mapping)
+                       if (page->mapping->host)
+                               if (page->mapping->host->i_crypt_info) {
+                                       ci = page->mapping->host->i_crypt_info->ci_dtfm;
+                                       if (ci && (bio->bi_aux_private != ci)
+                                           && (!(bio->bi_flags & REQ_OP_DISCARD))) {
+                                               dump_err(ci, DISKC_API_GET, bio, page);
+                                               ret = 1;
+                                       }
+                               }
+       disckipher_log(DISKC_API_GET, ret, ci);
+#endif
+}
+#else
+enum diskcipher_api {
+       DISKC_API_ALLOC, DISKC_API_FREE, DISKC_API_SET,
+       DISKC_API_GET, DISKC_API_CRYPT, DISKC_API_CLEAR, DISKC_API_MAX,
+};
+
+#define disckipher_log_show(a) do { } while (0)
+#define disckipher_log(a, b, c) do { } while (0)
+#endif
+
+#define DISKC_NAME "-disk"
+#define DISKC_NAME_SIZE (5)
+
+struct crypto_diskcipher *crypto_diskcipher_get(struct bio *bio)
+{
+       if (!bio || !virt_addr_valid(bio)) {
+               pr_err("%s: Invalid bio:%p\n", __func__, bio);
+               return NULL;
+       }
+       if (bio->bi_opf & REQ_CRYPT)
+               return bio->bi_aux_private;
+       else
+               return NULL;
+}
+
+void crypto_diskcipher_set(struct bio *bio,
+                          struct crypto_diskcipher *diskcipher)
+{
+       if (bio && diskcipher) {
+               bio->bi_opf |= (REQ_CRYPT | REQ_AUX_PRIV);
+               bio->bi_aux_private = diskcipher;
+       }
+       disckipher_log(DISKC_API_SET, 0, NULL);
+}
+
+int crypto_diskcipher_setkey(struct crypto_diskcipher *tfm, const char *in_key,
+                            unsigned int key_len, bool persistent)
+{
+       struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+       struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
+
+       if (!cra) {
+               pr_err("%s: doesn't exist cra", __func__);
+               return -EINVAL;
+       }
+       return cra->setkey(base, in_key, key_len, persistent);
+}
+
+int crypto_diskcipher_clearkey(struct crypto_diskcipher *tfm)
+{
+       struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+       struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
+
+       if (!cra) {
+               pr_err("%s: doesn't exist cra", __func__);
+               return -EINVAL;
+       }
+       return cra->clearkey(base);
+}
+
+int crypto_diskcipher_set_crypt(struct crypto_diskcipher *tfm, void *req)
+{
+       int ret = 0;
+       struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+       struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
+
+       if (!cra) {
+               pr_err("%s: doesn't exist cra", __func__);
+               ret = EINVAL;
+               goto out;
+       }
+
+       ret = cra->crypt(base, req);
+out:
+       if (ret)
+               pr_err("%s fails ret:%d, cra:%p\n", __func__, ret, cra);
+       pr_debug("%s done\n", __func__);
+       disckipher_log(DISKC_API_CRYPT, ret, tfm);
+       return ret;
+}
+
+int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void *req)
+{
+       int ret = 0;
+       struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+       struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
+
+       if (!cra) {
+               pr_err("%s: doesn't exist cra", __func__);
+               ret = EINVAL;
+               goto out;
+       }
+
+       ret = cra->clear(base, req);
+       if (ret)
+               pr_err("%s fails", __func__);
+
+out:
+       pr_debug("%s done\n", __func__);
+       disckipher_log(DISKC_API_CLEAR, ret, tfm);
+       return ret;
+}
+
+#ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
+int diskcipher_do_crypt(struct crypto_diskcipher *tfm,
+                       struct diskcipher_test_request *req)
+{
+       int ret;
+       struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+       struct diskcipher_alg *cra = crypto_diskcipher_alg(base->__crt_alg);
+
+       if (!cra) {
+               pr_err("%s: doesn't exist cra", __func__);
+               ret = EINVAL;
+               goto out;
+       }
+
+       if (cra->do_crypt)
+               ret = cra->do_crypt(base, req);
+       else
+               ret = -EINVAL;
+       if (ret)
+               pr_err("%s fails ret:%d", __func__, ret);
+
+out:
+       pr_debug("%s done\n", __func__);
+       return ret;
+}
+#endif
+
+static int crypto_diskcipher_init_tfm(struct crypto_tfm *tfm)
+{
+       return 0;
+}
+
+unsigned int crypto_diskcipher_extsize(struct crypto_alg *alg)
+{
+       return alg->cra_ctxsize +
+           (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
+}
+
+static void crypto_diskcipher_show(struct seq_file *m, struct crypto_alg *alg)
+{
+       seq_printf(m, "type         : diskcipher\n");
+       disckipher_log_show(m);
+}
+
+static const struct crypto_type crypto_diskcipher_type = {
+       .extsize = crypto_diskcipher_extsize,
+       .init_tfm = crypto_diskcipher_init_tfm,
+#ifdef CONFIG_PROC_FS
+       .show = crypto_diskcipher_show,
+#endif
+       .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+       .maskset = CRYPTO_ALG_TYPE_MASK,
+       .type = CRYPTO_ALG_TYPE_DISKCIPHER,
+       .tfmsize = offsetof(struct crypto_diskcipher, base),
+};
+
+struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name,
+                       u32 type, u32 mask, bool force)
+{
+       disckipher_log(DISKC_API_ALLOC, 0, NULL);
+       if (force) {
+               if (strlen(alg_name) + DISKC_NAME_SIZE < CRYPTO_MAX_ALG_NAME) {
+                       char diskc_name[CRYPTO_MAX_ALG_NAME];
+
+                       strcpy(diskc_name, alg_name);
+                       strcat(diskc_name, DISKC_NAME);
+                       return crypto_alloc_tfm(diskc_name,
+                               &crypto_diskcipher_type, type, mask);
+               }
+       } else {
+               return crypto_alloc_tfm(alg_name, &crypto_diskcipher_type, type, mask);
+       }
+
+       return NULL;
+}
+
+void crypto_free_diskcipher(struct crypto_diskcipher *tfm)
+{
+       disckipher_log(DISKC_API_FREE, 0, NULL);
+       crypto_destroy_tfm(tfm, crypto_diskcipher_tfm(tfm));
+}
+
+int crypto_register_diskcipher(struct diskcipher_alg *alg)
+{
+       struct crypto_alg *base = &alg->base;
+
+       base->cra_type = &crypto_diskcipher_type;
+       base->cra_flags = CRYPTO_ALG_TYPE_DISKCIPHER;
+       return crypto_register_alg(base);
+}
+
+void crypto_unregister_diskcipher(struct diskcipher_alg *alg)
+{
+       crypto_unregister_alg(&alg->base);
+}
+
+int crypto_register_diskciphers(struct diskcipher_alg *algs, int count)
+{
+       int i, ret;
+
+       for (i = 0; i < count; i++) {
+               ret = crypto_register_diskcipher(algs + i);
+               if (ret)
+                       goto err;
+       }
+       return 0;
+
+err:
+       for (--i; i >= 0; --i)
+               crypto_unregister_diskcipher(algs + i);
+       return ret;
+}
+
+void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count)
+{
+       int i;
+
+       for (i = count - 1; i >= 0; --i)
+               crypto_unregister_diskcipher(algs + i);
+}
index b5bb45a89ff889f9af75b2aceda713044a3cf18e..68a1cfadd3fcfdf12d2fc7de399fbf1deb870b5e 100644 (file)
@@ -32,6 +32,7 @@
 #include <crypto/rng.h>
 #include <crypto/drbg.h>
 #include <crypto/akcipher.h>
+#include <crypto/diskcipher.h>
 #include <crypto/kpp.h>
 #include <crypto/acompress.h>
 
@@ -1682,6 +1683,150 @@ out:
        return err;
 }
 
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+static int __test_diskcipher(struct crypto_diskcipher *tfm, int enc,
+                          const struct cipher_testvec *template, unsigned int tcount,
+                          const int align_offset)
+{
+       const char *algo =
+               crypto_tfm_alg_driver_name(crypto_diskcipher_tfm(tfm));
+       unsigned int i, j;
+       char *q;
+       struct scatterlist sg[8];
+       struct scatterlist sgout[8];
+       const char *e = (enc == ENCRYPT) ? "encryption" : "decryption";
+       struct tcrypt_result result;
+       void *data;
+       char iv[MAX_IVLEN];
+       char *xbuf[XBUFSIZE];
+       char *xoutbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+       unsigned int ivsize = crypto_diskcipher_ivsize(tfm);
+       struct diskcipher_test_request req;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
+
+       if (testmgr_alloc_buf(xoutbuf))
+               goto out_nooutbuf;
+
+       init_completion(&result.completion);
+
+       j = 0;
+       for (i = 0; i < tcount; i++) {
+               if (template[i].np && !template[i].also_non_np)
+                       continue;
+
+               if (template[i].fips_skip)
+                       continue;
+
+               if (template[i].iv)
+                       memcpy(iv, template[i].iv, ivsize);
+               else
+                       memset(iv, 0, MAX_IVLEN);
+
+               j++;
+               ret = -EINVAL;
+               if (WARN_ON(align_offset + template[i].ilen > PAGE_SIZE))
+                       goto out;
+
+               ret = crypto_diskcipher_setkey(tfm, template[i].key,
+                                            template[i].klen, 0);
+               if (ret == -ENOKEY) {
+                       pr_err("alg: diskcipher: no support %d keylen for %s. skip it\n",
+                              template[i].klen, algo);
+                       continue;
+               } else if (ret) {
+                       pr_err("alg: diskcipher: setkey failed on test %d for %s\n",
+                                  j, algo);
+                       goto out;
+               }
+
+               data = xbuf[0];
+               data += align_offset;
+               memcpy(data, template[i].input, template[i].ilen);
+               sg_init_one(&sg[0], data, template[i].ilen);
+
+               data = xoutbuf[0];
+               data += align_offset;
+               sg_init_one(&sgout[0], data, template[i].ilen);
+
+               diskcipher_request_set_crypt(&req, sg, sgout,
+                               template[i].ilen, iv, enc ? 1 : 0);
+               ret = diskcipher_do_crypt(tfm, &req);
+               if (ret) {
+                       pr_err("alg: diskcipher: %s failed on test %d for %s: ret=%d\n",
+                                  e, j, algo, -ret);
+                       goto out;
+               }
+
+               q = data;
+               if (memcmp(q, template[i].result, template[i].rlen)) {
+                       pr_err("alg: diskcipher: Test %d failed (invalid result) on %s for %s\n",
+                              j, e, algo);
+                       hexdump(q, template[i].rlen);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+       ret = 0;
+
+out:
+       testmgr_free_buf(xoutbuf);
+out_nooutbuf:
+       testmgr_free_buf(xbuf);
+out_nobuf:
+       return ret;
+}
+
+static int test_diskcipher(struct crypto_diskcipher *tfm, int enc,
+                        const struct cipher_testvec *template,
+                        unsigned int tcount)
+{
+       int ret;
+
+       ret = __test_diskcipher(tfm, enc, template, tcount, 0);
+       if (ret)
+               return ret;
+
+       /* test unaligned buffers, check with one byte offset */
+       ret = __test_diskcipher(tfm, enc, template, tcount, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int alg_test_diskcipher(const struct alg_test_desc *desc,
+                            const char *driver, u32 type, u32 mask)
+{
+       struct crypto_diskcipher *tfm;
+       int err = 0;
+
+       tfm = crypto_alloc_diskcipher(driver, type | CRYPTO_ALG_INTERNAL, mask, 0);
+       if (!tfm || IS_ERR(tfm)) {
+               pr_err("alg: diskcipher: Failed to load transform for %s: %ld\n",
+                       driver, PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+
+       if (desc->suite.cipher.enc.vecs) {
+               err = test_diskcipher(tfm, ENCRYPT, desc->suite.cipher.enc.vecs,
+                                   desc->suite.cipher.enc.count);
+               if (err)
+                       goto out;
+       }
+
+       if (desc->suite.cipher.dec.vecs)
+               err = test_diskcipher(tfm, DECRYPT, desc->suite.cipher.dec.vecs,
+                                   desc->suite.cipher.dec.count);
+
+out:
+       crypto_free_diskcipher(tfm);
+       return err;
+}
+#endif
+
 static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
                         u32 type, u32 mask)
 {
@@ -2526,6 +2671,17 @@ static const struct alg_test_desc alg_test_descs[] = {
                                .dec = __VECS(aes_cbc_dec_tv_template)
                        }
                }
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+       }, {
+               .alg = "cbc(aes)-disk",
+               .test = alg_test_diskcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = __VECS(aes_cbc_enc_tv_template),
+                               .dec = __VECS(aes_cbc_dec_tv_template)
+                       }
+               }
+#endif
        }, {
                .alg = "cbc(anubis)",
                .test = alg_test_skcipher,
@@ -3575,6 +3731,17 @@ static const struct alg_test_desc alg_test_descs[] = {
                                .dec = __VECS(aes_xts_dec_tv_template)
                        }
                }
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+       }, {
+               .alg = "xts(aes)-disk",
+               .test = alg_test_diskcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = __VECS(aes_xts_enc_tv_template),
+                               .dec = __VECS(aes_xts_dec_tv_template)
+                       }
+               }
+#endif
        }, {
                .alg = "xts(camellia)",
                .test = alg_test_skcipher,
diff --git a/include/crypto/diskcipher.h b/include/crypto/diskcipher.h
new file mode 100644 (file)
index 0000000..2369b8b
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _DISKCIPHER_H_
+#define _DISKCIPHER_H_
+
+#include <linux/crypto.h>
+#include <linux/blk_types.h>
+
+struct diskcipher_alg;
+
+struct crypto_diskcipher {
+       u32 algo;
+       unsigned int ivsize;
+       struct crypto_tfm base;
+};
+
+struct diskcipher_test_request {
+       unsigned int cryptlen;
+       const u8 *iv;
+       struct scatterlist *src;
+       struct scatterlist *dst;
+       bool enc;
+};
+
+/**
+ * struct diskcipher_alg - symmetric key cipher definition
+ * for inline crypto engine on disk host device
+ *
+ * @setkey
+ * @clearkey
+ * @crypt
+ * @clear
+ * @do_crypt
+ * @base:      Common crypto API algorithm data structure.
+ *
+ * Diskcipher supports APIs to set crypto information for dm-crypt and fscrypt
+ * And pass the crypto information to disk host device via bio.
+ * Crypt operation executes on inline crypto on disk host device.
+ */
+struct diskcipher_alg {
+       int (*setkey)(struct crypto_tfm *tfm, const char *key, u32 keylen,
+                      bool persistent);
+       int (*clearkey)(struct crypto_tfm *tfm);
+       int (*crypt)(struct crypto_tfm *tfm, void *req);
+       int (*clear)(struct crypto_tfm *tfm, void *req);
+#ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
+       int (*do_crypt)(struct crypto_tfm *tfm,
+               struct diskcipher_test_request *req);
+#endif
+       struct crypto_alg base;
+};
+
+static inline unsigned int crypto_diskcipher_ivsize(struct crypto_diskcipher *tfm)
+{
+       return tfm->ivsize;
+}
+
+static inline struct crypto_tfm *crypto_diskcipher_tfm(struct crypto_diskcipher
+                                                      *tfm)
+{
+       return &tfm->base;
+}
+
+static inline struct diskcipher_alg *crypto_diskcipher_alg(struct crypto_alg
+                                                          *alg)
+{
+       return container_of(alg, struct diskcipher_alg, base);
+}
+
+static inline struct crypto_diskcipher *__crypto_diskcipher_cast(
+       struct crypto_tfm *tfm)
+{
+       return container_of(tfm, struct crypto_diskcipher, base);
+}
+
+int crypto_register_diskcipher(struct diskcipher_alg *alg);
+void crypto_unregister_diskcipher(struct diskcipher_alg *alg);
+int crypto_register_diskciphers(struct diskcipher_alg *algs, int count);
+void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count);
+
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+/**
+ * crypto_alloc_diskcipher() - allocate symmetric cipher running on disk device
+ * @alg_name: is the cra_name / name or cra_driver_name / driver name of the
+ *           skcipher cipher
+ * @type: specifies the type of the cipher
+ * @mask: specifies the mask for the cipher
+ * @force: add diskcipher postfix '-disk' on algo_name
+ *
+ * Allocate a cipher handle for an diskcipher. The returned struct
+ * crypto_diskcipher is the cipher handle that is required for any subsequent
+ * API invocation for that diskcipher.
+ *
+ * Return: allocated cipher handle in case of success; IS_ERR() is true in case
+ *        of an error, PTR_ERR() returns the error code.
+ */
+struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name,
+                         u32 type, u32 mask, bool force);
+
+/**
+ * crypto_free_diskcipher() - zeroize and free cipher handle
+ * @tfm: cipher handle to be freed
+ */
+void crypto_free_diskcipher(struct crypto_diskcipher *tfm);
+
+/**
+ * crypto_diskcipher_get() - get diskcipher from bio
+ * @bio: bio structure
+ */
+struct crypto_diskcipher *crypto_diskcipher_get(struct bio *bio);
+
+/**
+ * crypto_diskcipher_set() - set diskcipher to bio
+ * @bio: bio structure to contain diskcipher
+ * @tfm: cipher handle
+ *
+ * This functions set thm to bio->bi_aux_private to pass it to host driver.
+ *
+ */
+void crypto_diskcipher_set(struct bio *bio, struct crypto_diskcipher *tfm);
+
+/**
+ * crypto_diskcipher_setkey() - set key for cipher
+ * @tfm: cipher handle
+ * @key: buffer holding the key
+ * @keylen: length of the key in bytes
+ * @persistent: option of key storage option
+ *
+ * The caller provided key is set for the skcipher referenced by the cipher
+ * handle.
+ *
+ * Return: 0 if the setting of the key was successful; < 0 if an error occurred
+ */
+int crypto_diskcipher_setkey(struct crypto_diskcipher *tfm, const char *key,
+                            u32 keylen, bool persistent);
+
+/**
+ * crypto_diskcipher_clearkey() - clear key
+ * @tfm: cipher handle
+ */
+int crypto_diskcipher_clearkey(struct crypto_diskcipher *tfm);
+
+/**
+ * crypto_diskcipher_set_crypt() - set crypto info for inline crypto engine
+ * @tfm: cipher handle
+ * @req: request handle. it's specific structure for inline crypt hardware
+ *
+ * Return: 0 if the setting of the key was successful; < 0 if an error occurred
+ */
+int crypto_diskcipher_set_crypt(struct crypto_diskcipher *tfm, void *req);
+
+/**
+ * crypto_diskcipher_clear_crypt() - clear crypto info on inline crypt hardware
+ * @tfm: cipher handle
+ * @req: request handle. it's specific structure for inline crypt hardware
+ *
+ * Return: 0 if the setting of the key was successful; < 0 if an error occurred
+ */
+int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void *req);
+
+#ifndef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
+/**
+ * diskcipher_do_crypt() - execute crypto for test
+ * @tfm: cipher handle
+ * @req: diskcipher_test_request handle
+ *
+ * The caller uses this function to request crypto
+ * Diskcipher_algo allocates the block area for test and then request block I/O
+ *
+ */
+int diskcipher_do_crypt(struct crypto_diskcipher *tfm,
+                               struct diskcipher_test_request *req);
+
+/**
+ * diskcipher_request_set_crypt() - fill diskcipher_test_requeust
+ * @req: request handle
+ * @src: source scatter / gather list
+ * @dst: destination scatter / gather list
+ * @cryptlen: number of bytes to process from @src
+ * @iv: IV for the cipher operation which must comply with the IV size defined
+ *      by crypto_skcipher_ivsize
+ * @enc: encrypt(1) / decrypt(0)
+ *
+ * This function allows setting of the source data and destination data
+ * scatter / gather lists.
+ *
+ * For encryption, the source is treated as the plaintext and the
+ * destination is the ciphertext. For a decryption operation, the use is
+ * reversed - the source is the ciphertext and the destination is the plaintext.
+ */
+static inline void diskcipher_request_set_crypt(
+       struct diskcipher_test_request *req,
+       struct scatterlist *src, struct scatterlist *dst,
+       unsigned int cryptlen, void *iv, bool enc)
+{
+       req->src = src;
+       req->dst = dst;
+       req->cryptlen = cryptlen;
+       req->iv = iv;
+       req->enc = enc;
+}
+#endif
+#define EANBLE_DISKCIPHER_DEBUG
+#ifdef EANBLE_DISKCIPHER_DEBUG
+void crypto_diskcipher_check(struct bio *bio, struct page *page);
+#endif
+#else
+#define crypto_alloc_diskcipher(a, b, c, d) ((void *)NULL)
+#define crypto_free_diskcipher(a) ((void)0)
+#define crypto_diskcipher_get(a) ((void *)NULL)
+#define crypto_diskcipher_set(a, b) ((void)0)
+#define crypto_diskcipher_clearkey(a) ((void)0)
+#define crypto_diskcipher_setkey(a, b, c, d) (-1)
+#endif
+#endif /* _DISKCIPHER_H_ */
index 29c4257f9c5b14c3c66e2e57eef573f9a2ff7a10..dd76928b9eada1e68dc2c8d8ceafca0ee54e9234 100644 (file)
@@ -50,6 +50,7 @@
 #define CRYPTO_ALG_TYPE_ABLKCIPHER     0x00000005
 #define CRYPTO_ALG_TYPE_SKCIPHER       0x00000005
 #define CRYPTO_ALG_TYPE_GIVCIPHER      0x00000006
+#define CRYPTO_ALG_TYPE_DISKCIPHER      0x00000007
 #define CRYPTO_ALG_TYPE_KPP            0x00000008
 #define CRYPTO_ALG_TYPE_ACOMPRESS      0x0000000a
 #define CRYPTO_ALG_TYPE_SCOMPRESS      0x0000000b