Linux cryptographic layer development
 help / color / mirror / Atom feed
* [PATCH 2/8] crypto: mediatek - fix incorrect data transfer result
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: linux-mediatek, linux-kernel, linux-crypto, linux-arm-kernel,
	Ryder Lee
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee@mediatek.com>

This patch fixes mtk_aes_xmit() data transfer bug.

The original function uses the same loop and ring->pos
to handle both command and result descriptors. But this
produces incomplete results when src.sg_len != dst.sg_len.

To solve the problem, we splits the descriptors into different
loops and uses cmd_pos and res_pos to record them respectively.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/crypto/mediatek/mtk-aes.c      | 44 ++++++++++++++++++++--------------
 drivers/crypto/mediatek/mtk-platform.h |  6 +++--
 drivers/crypto/mediatek/mtk-sha.c      | 29 ++++++++++++----------
 3 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index 126b93c..b658cb9 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -225,29 +225,25 @@ static int mtk_aes_info_map(struct mtk_cryp *cryp,
 	return 0;
 }
 
+/*
+ * Write descriptors for processing. This will configure the engine, load
+ * the transform information and then start the packet processing.
+ */
 static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 {
 	struct mtk_ring *ring = cryp->ring[aes->id];
 	struct mtk_desc *cmd = NULL, *res = NULL;
-	struct scatterlist *ssg, *dsg;
-	u32 len = aes->src.sg_len;
+	struct scatterlist *ssg = aes->src.sg, *dsg = aes->dst.sg;
+	u32 slen = aes->src.sg_len, dlen = aes->dst.sg_len;
 	int nents;
 
-	/* Fill in the command/result descriptors */
-	for (nents = 0; nents < len; ++nents) {
-		ssg = &aes->src.sg[nents];
-		dsg = &aes->dst.sg[nents];
-
-		cmd = ring->cmd_base + ring->pos;
+	/* Write command descriptors */
+	for (nents = 0; nents < slen; ++nents, ssg = sg_next(ssg)) {
+		cmd = ring->cmd_base + ring->cmd_pos;
 		cmd->hdr = MTK_DESC_BUF_LEN(ssg->length);
 		cmd->buf = cpu_to_le32(sg_dma_address(ssg));
 
-		res = ring->res_base + ring->pos;
-		res->hdr = MTK_DESC_BUF_LEN(dsg->length);
-		res->buf = cpu_to_le32(sg_dma_address(dsg));
-
 		if (nents == 0) {
-			res->hdr |= MTK_DESC_FIRST;
 			cmd->hdr |= MTK_DESC_FIRST |
 				    MTK_DESC_CT_LEN(aes->ctx->ct_size);
 			cmd->ct = cpu_to_le32(aes->ctx->ct_dma);
@@ -255,11 +251,23 @@ static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 			cmd->tfm = cpu_to_le32(aes->ctx->tfm_dma);
 		}
 
-		if (++ring->pos == MTK_DESC_NUM)
-			ring->pos = 0;
+		if (++ring->cmd_pos == MTK_DESC_NUM)
+			ring->cmd_pos = 0;
 	}
-
 	cmd->hdr |= MTK_DESC_LAST;
+
+	/* Prepare result descriptors */
+	for (nents = 0; nents < dlen; ++nents, dsg = sg_next(dsg)) {
+		res = ring->res_base + ring->res_pos;
+		res->hdr = MTK_DESC_BUF_LEN(dsg->length);
+		res->buf = cpu_to_le32(sg_dma_address(dsg));
+
+		if (nents == 0)
+			res->hdr |= MTK_DESC_FIRST;
+
+		if (++ring->res_pos == MTK_DESC_NUM)
+			ring->res_pos = 0;
+	}
 	res->hdr |= MTK_DESC_LAST;
 
 	/*
@@ -268,8 +276,8 @@ static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 	 */
 	wmb();
 	/* Start DMA transfer */
-	mtk_aes_write(cryp, RDR_PREP_COUNT(aes->id), MTK_DESC_CNT(len));
-	mtk_aes_write(cryp, CDR_PREP_COUNT(aes->id), MTK_DESC_CNT(len));
+	mtk_aes_write(cryp, RDR_PREP_COUNT(aes->id), MTK_DESC_CNT(dlen));
+	mtk_aes_write(cryp, CDR_PREP_COUNT(aes->id), MTK_DESC_CNT(slen));
 
 	return -EINPROGRESS;
 }
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
index 1516786..8c50b74 100644
--- a/drivers/crypto/mediatek/mtk-platform.h
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -83,9 +83,10 @@ struct mtk_desc {
  * struct mtk_ring - Descriptor ring
  * @cmd_base:	pointer to command descriptor ring base
  * @cmd_dma:	DMA address of command descriptor ring
+ * @cmd_pos:	current position in the command descriptor ring
  * @res_base:	pointer to result descriptor ring base
  * @res_dma:	DMA address of result descriptor ring
- * @pos:	current position in the ring
+ * @res_pos:	current position in the result descriptor ring
  *
  * A descriptor ring is a circular buffer that is used to manage
  * one or more descriptors. There are two type of descriptor rings;
@@ -94,9 +95,10 @@ struct mtk_desc {
 struct mtk_ring {
 	struct mtk_desc *cmd_base;
 	dma_addr_t cmd_dma;
+	u32 cmd_pos;
 	struct mtk_desc *res_base;
 	dma_addr_t res_dma;
-	u32 pos;
+	u32 res_pos;
 };
 
 /**
diff --git a/drivers/crypto/mediatek/mtk-sha.c b/drivers/crypto/mediatek/mtk-sha.c
index 8cbff21..2536ebc 100644
--- a/drivers/crypto/mediatek/mtk-sha.c
+++ b/drivers/crypto/mediatek/mtk-sha.c
@@ -426,8 +426,8 @@ static int mtk_sha_xmit(struct mtk_cryp *cryp, struct mtk_sha_rec *sha,
 {
 	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
 	struct mtk_ring *ring = cryp->ring[sha->id];
-	struct mtk_desc *cmd = ring->cmd_base + ring->pos;
-	struct mtk_desc *res = ring->res_base + ring->pos;
+	struct mtk_desc *cmd = ring->cmd_base + ring->cmd_pos;
+	struct mtk_desc *res = ring->res_base + ring->res_pos;
 	int err;
 
 	err = mtk_sha_info_map(cryp, sha, len);
@@ -451,9 +451,10 @@ static int mtk_sha_xmit(struct mtk_cryp *cryp, struct mtk_sha_rec *sha,
 	cmd->ct_hdr = ctx->ct_hdr;
 	cmd->tfm = cpu_to_le32(ctx->tfm_dma);
 
-	if (++ring->pos == MTK_DESC_NUM)
-		ring->pos = 0;
+	if (++ring->cmd_pos == MTK_DESC_NUM)
+		ring->cmd_pos = 0;
 
+	ring->res_pos = ring->cmd_pos;
 	/*
 	 * Make sure that all changes to the DMA ring are done before we
 	 * start engine.
@@ -472,8 +473,8 @@ static int mtk_sha_xmit2(struct mtk_cryp *cryp,
 			 size_t len1, size_t len2)
 {
 	struct mtk_ring *ring = cryp->ring[sha->id];
-	struct mtk_desc *cmd = ring->cmd_base + ring->pos;
-	struct mtk_desc *res = ring->res_base + ring->pos;
+	struct mtk_desc *cmd = ring->cmd_base + ring->cmd_pos;
+	struct mtk_desc *res = ring->res_base + ring->res_pos;
 	int err;
 
 	err = mtk_sha_info_map(cryp, sha, len1 + len2);
@@ -492,11 +493,13 @@ static int mtk_sha_xmit2(struct mtk_cryp *cryp,
 	cmd->ct_hdr = ctx->ct_hdr;
 	cmd->tfm = cpu_to_le32(ctx->tfm_dma);
 
-	if (++ring->pos == MTK_DESC_NUM)
-		ring->pos = 0;
+	if (++ring->cmd_pos == MTK_DESC_NUM)
+		ring->cmd_pos = 0;
 
-	cmd = ring->cmd_base + ring->pos;
-	res = ring->res_base + ring->pos;
+	ring->res_pos = ring->cmd_pos;
+
+	cmd = ring->cmd_base + ring->cmd_pos;
+	res = ring->res_base + ring->res_pos;
 
 	res->hdr = MTK_DESC_BUF_LEN(len2) | MTK_DESC_LAST;
 	res->buf = cpu_to_le32(cryp->tmp_dma);
@@ -504,8 +507,10 @@ static int mtk_sha_xmit2(struct mtk_cryp *cryp,
 	cmd->hdr = MTK_DESC_BUF_LEN(len2) | MTK_DESC_LAST;
 	cmd->buf = cpu_to_le32(ctx->dma_addr);
 
-	if (++ring->pos == MTK_DESC_NUM)
-		ring->pos = 0;
+	if (++ring->cmd_pos == MTK_DESC_NUM)
+		ring->cmd_pos = 0;
+
+	ring->res_pos = ring->cmd_pos;
 
 	/*
 	 * Make sure that all changes to the DMA ring are done before we
-- 
1.9.1

^ permalink raw reply related

* [PATCH 3/8] crypto: mediatek - make crypto request queue management more generic
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: linux-mediatek, linux-kernel, linux-crypto, linux-arm-kernel,
	Ryder Lee
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee@mediatek.com>

This patch changes mtk_aes_handle_queue() to make it more generic.
The function argument is now a pointer to struct crypto_async_request,
which is the common base of struct ablkcipher_request and
struct aead_request.

Also this patch introduces struct mtk_aes_base_ctx which will be the
common base of all the transformation contexts.

Hence the very same queue will be used to manage both block cipher and
AEAD requests (such as gcm and authenc implemented in further patches).

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/crypto/mediatek/mtk-aes.c      | 75 ++++++++++++++++++++--------------
 drivers/crypto/mediatek/mtk-platform.h | 14 ++++---
 2 files changed, 53 insertions(+), 36 deletions(-)

diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index b658cb9..7e5a8e0 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -73,9 +73,10 @@ struct mtk_aes_reqctx {
 	u64 mode;
 };
 
-struct mtk_aes_ctx {
+struct mtk_aes_base_ctx {
 	struct mtk_cryp *cryp;
 	u32 keylen;
+	mtk_aes_fn start;
 
 	struct mtk_aes_ct ct;
 	dma_addr_t ct_dma;
@@ -86,6 +87,10 @@ struct mtk_aes_ctx {
 	u32 ct_size;
 };
 
+struct mtk_aes_ctx {
+	struct mtk_aes_base_ctx	base;
+};
+
 struct mtk_aes_drv {
 	struct list_head dev_list;
 	/* Device list lock */
@@ -108,7 +113,7 @@ static inline void mtk_aes_write(struct mtk_cryp *cryp,
 	writel_relaxed(value, cryp->base + offset);
 }
 
-static struct mtk_cryp *mtk_aes_find_dev(struct mtk_aes_ctx *ctx)
+static struct mtk_cryp *mtk_aes_find_dev(struct mtk_aes_base_ctx *ctx)
 {
 	struct mtk_cryp *cryp = NULL;
 	struct mtk_cryp *tmp;
@@ -170,7 +175,8 @@ static int mtk_aes_info_map(struct mtk_cryp *cryp,
 			    struct mtk_aes_rec *aes,
 			    size_t len)
 {
-	struct mtk_aes_ctx *ctx = aes->ctx;
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
 
 	ctx->ct_hdr = AES_CT_CTRL_HDR | cpu_to_le32(len);
 	ctx->ct.cmd[0] = AES_CMD0 | cpu_to_le32(len);
@@ -189,7 +195,7 @@ static int mtk_aes_info_map(struct mtk_cryp *cryp,
 		ctx->tfm.ctrl[0] |= AES_TFM_192BITS;
 
 	if (aes->flags & AES_FLAGS_CBC) {
-		const u32 *iv = (const u32 *)aes->req->info;
+		const u32 *iv = (const u32 *)req->info;
 		u32 *iv_state = ctx->tfm.state + ctx->keylen;
 		int i;
 
@@ -299,11 +305,10 @@ static inline void mtk_aes_restore_sg(const struct mtk_aes_dma *dma)
 	sg->length += dma->remainder;
 }
 
-static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+		       struct scatterlist *src, struct scatterlist *dst,
+		       size_t len)
 {
-	struct scatterlist *src = aes->req->src;
-	struct scatterlist *dst = aes->req->dst;
-	size_t len = aes->req->nbytes;
 	size_t padlen = 0;
 	bool src_aligned, dst_aligned;
 
@@ -366,18 +371,17 @@ static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 }
 
 static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
-				struct ablkcipher_request *req)
+				struct crypto_async_request *new_areq)
 {
 	struct mtk_aes_rec *aes = cryp->aes[id];
 	struct crypto_async_request *areq, *backlog;
-	struct mtk_aes_reqctx *rctx;
-	struct mtk_aes_ctx *ctx;
+	struct mtk_aes_base_ctx *ctx;
 	unsigned long flags;
-	int err, ret = 0;
+	int ret = 0;
 
 	spin_lock_irqsave(&aes->lock, flags);
-	if (req)
-		ret = ablkcipher_enqueue_request(&aes->queue, req);
+	if (new_areq)
+		ret = crypto_enqueue_request(&aes->queue, new_areq);
 	if (aes->flags & AES_FLAGS_BUSY) {
 		spin_unlock_irqrestore(&aes->lock, flags);
 		return ret;
@@ -394,16 +398,25 @@ static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
 	if (backlog)
 		backlog->complete(backlog, -EINPROGRESS);
 
-	req = ablkcipher_request_cast(areq);
-	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+	ctx = crypto_tfm_ctx(areq->tfm);
+
+	aes->areq = areq;
+	aes->ctx = ctx;
+
+	return ctx->start(cryp, aes);
+}
+
+static int mtk_aes_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+	int err;
+
 	rctx = ablkcipher_request_ctx(req);
 	rctx->mode &= AES_FLAGS_MODE_MSK;
-	/* Assign new request to device */
-	aes->req = req;
-	aes->ctx = ctx;
 	aes->flags = (aes->flags & ~AES_FLAGS_MODE_MSK) | rctx->mode;
 
-	err = mtk_aes_map(cryp, aes);
+	err = mtk_aes_map(cryp, aes, req->src, req->dst, req->nbytes);
 	if (err)
 		return err;
 
@@ -412,7 +425,7 @@ static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
 
 static void mtk_aes_unmap(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 {
-	struct mtk_aes_ctx *ctx = aes->ctx;
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
 
 	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(ctx->ct),
 			 DMA_TO_DEVICE);
@@ -449,8 +462,7 @@ static inline void mtk_aes_complete(struct mtk_cryp *cryp,
 				    struct mtk_aes_rec *aes)
 {
 	aes->flags &= ~AES_FLAGS_BUSY;
-
-	aes->req->base.complete(&aes->req->base, 0);
+	aes->areq->complete(aes->areq, 0);
 
 	/* Handle new request */
 	mtk_aes_handle_queue(cryp, aes->id, NULL);
@@ -460,7 +472,7 @@ static inline void mtk_aes_complete(struct mtk_cryp *cryp,
 static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
 			  const u8 *key, u32 keylen)
 {
-	struct mtk_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct mtk_aes_base_ctx *ctx = crypto_ablkcipher_ctx(tfm);
 	const u32 *key_tmp = (const u32 *)key;
 	u32 *key_state = ctx->tfm.state;
 	int i;
@@ -482,14 +494,15 @@ static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
 
 static int mtk_aes_crypt(struct ablkcipher_request *req, u64 mode)
 {
-	struct mtk_aes_ctx *ctx = crypto_ablkcipher_ctx(
-			crypto_ablkcipher_reqtfm(req));
-	struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct mtk_aes_base_ctx *ctx;
+	struct mtk_aes_reqctx *rctx;
 
+	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+	rctx = ablkcipher_request_ctx(req);
 	rctx->mode = mode;
 
 	return mtk_aes_handle_queue(ctx->cryp,
-			!(mode & AES_FLAGS_ENCRYPT), req);
+			!(mode & AES_FLAGS_ENCRYPT), &req->base);
 }
 
 static int mtk_ecb_encrypt(struct ablkcipher_request *req)
@@ -517,14 +530,14 @@ static int mtk_aes_cra_init(struct crypto_tfm *tfm)
 	struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct mtk_cryp *cryp = NULL;
 
-	tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx);
-
-	cryp = mtk_aes_find_dev(ctx);
+	cryp = mtk_aes_find_dev(&ctx->base);
 	if (!cryp) {
 		pr_err("can't find crypto device\n");
 		return -ENODEV;
 	}
 
+	tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx);
+	ctx->base.start = mtk_aes_start;
 	return 0;
 }
 
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
index 8c50b74..9f5210c 100644
--- a/drivers/crypto/mediatek/mtk-platform.h
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -115,12 +115,16 @@ struct mtk_aes_dma {
 	u32 sg_len;
 };
 
-struct mtk_aes_ctx;
+struct mtk_aes_base_ctx;
+struct mtk_aes_rec;
+struct mtk_cryp;
+
+typedef int (*mtk_aes_fn)(struct mtk_cryp *cryp, struct mtk_aes_rec *aes);
 
 /**
  * struct mtk_aes_rec - AES operation record
  * @queue:	crypto request queue
- * @req:	pointer to ablkcipher request
+ * @req:	pointer to async request
  * @task:	the tasklet is use in AES interrupt
  * @ctx:	pointer to current context
  * @src:	the structure that holds source sg list info
@@ -131,15 +135,15 @@ struct mtk_aes_dma {
  * @buf:	pointer to page buffer
  * @id:		record identification
  * @flags:	it's describing AES operation state
- * @lock:	the ablkcipher queue lock
+ * @lock:	the async queue lock
  *
  * Structure used to record AES execution state.
  */
 struct mtk_aes_rec {
 	struct crypto_queue queue;
-	struct ablkcipher_request *req;
+	struct crypto_async_request *areq;
 	struct tasklet_struct task;
-	struct mtk_aes_ctx *ctx;
+	struct mtk_aes_base_ctx *ctx;
 	struct mtk_aes_dma src;
 	struct mtk_aes_dma dst;
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH 4/8] crypto: mediatek - rework crypto request completion
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: Ryder Lee, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-crypto-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>

This patch introduces a new callback 'resume' in the struct mtk_aes_rec.
This callback is run to resume/complete the processing of the crypto
request when woken up by AES interrupts when DMA completion.

This callback will help implementing the GCM mode support in further
patches.

Signed-off-by: Ryder Lee <ryder.lee-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
 drivers/crypto/mediatek/mtk-aes.c      | 25 +++++++++++++------------
 drivers/crypto/mediatek/mtk-platform.h |  3 +++
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index 7e5a8e0..9c4e468 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -406,6 +406,15 @@ static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
 	return ctx->start(cryp, aes);
 }
 
+static int mtk_aes_complete(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	aes->flags &= ~AES_FLAGS_BUSY;
+	aes->areq->complete(aes->areq, 0);
+
+	/* Handle new request */
+	return mtk_aes_handle_queue(cryp, aes->id, NULL);
+}
+
 static int mtk_aes_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 {
 	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
@@ -416,6 +425,8 @@ static int mtk_aes_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 	rctx->mode &= AES_FLAGS_MODE_MSK;
 	aes->flags = (aes->flags & ~AES_FLAGS_MODE_MSK) | rctx->mode;
 
+	aes->resume = mtk_aes_complete;
+
 	err = mtk_aes_map(cryp, aes, req->src, req->dst, req->nbytes);
 	if (err)
 		return err;
@@ -458,16 +469,6 @@ static void mtk_aes_unmap(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 				    aes->buf, aes->total);
 }
 
-static inline void mtk_aes_complete(struct mtk_cryp *cryp,
-				    struct mtk_aes_rec *aes)
-{
-	aes->flags &= ~AES_FLAGS_BUSY;
-	aes->areq->complete(aes->areq, 0);
-
-	/* Handle new request */
-	mtk_aes_handle_queue(cryp, aes->id, NULL);
-}
-
 /* Check and set the AES key to transform state buffer */
 static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
 			  const u8 *key, u32 keylen)
@@ -591,7 +592,7 @@ static void mtk_aes_enc_task(unsigned long data)
 	struct mtk_aes_rec *aes = cryp->aes[0];
 
 	mtk_aes_unmap(cryp, aes);
-	mtk_aes_complete(cryp, aes);
+	aes->resume(cryp, aes);
 }
 
 static void mtk_aes_dec_task(unsigned long data)
@@ -600,7 +601,7 @@ static void mtk_aes_dec_task(unsigned long data)
 	struct mtk_aes_rec *aes = cryp->aes[1];
 
 	mtk_aes_unmap(cryp, aes);
-	mtk_aes_complete(cryp, aes);
+	aes->resume(cryp, aes);
 }
 
 static irqreturn_t mtk_aes_enc_irq(int irq, void *dev_id)
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
index 9f5210c..36d166b 100644
--- a/drivers/crypto/mediatek/mtk-platform.h
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -131,6 +131,7 @@ struct mtk_aes_dma {
  * @dst:	the structure that holds destination sg list info
  * @aligned_sg:	the scatter list is use to alignment
  * @real_dst:	pointer to the destination sg list
+ * @resume:	pointer to resume function
  * @total:	request buffer length
  * @buf:	pointer to page buffer
  * @id:		record identification
@@ -150,6 +151,8 @@ struct mtk_aes_rec {
 	struct scatterlist aligned_sg;
 	struct scatterlist *real_dst;
 
+	mtk_aes_fn resume;
+
 	size_t total;
 	void *buf;
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH 6/8] crypto: mediatek - fix typo and indentation
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: linux-mediatek, linux-kernel, linux-crypto, linux-arm-kernel,
	Ryder Lee
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee@mediatek.com>

Dummy patch to fix typo and indentation.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/crypto/mediatek/mtk-aes.c      | 90 +++++++++++++++++-----------------
 drivers/crypto/mediatek/mtk-platform.h |  2 +-
 drivers/crypto/mediatek/mtk-sha.c      | 40 +++++++--------
 3 files changed, 63 insertions(+), 69 deletions(-)

diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index b5946e9..5e7c3ce 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -314,8 +314,8 @@ static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 		aes->dst.sg_len = dma_map_sg(cryp->dev, aes->dst.sg,
 					     aes->dst.nents, DMA_FROM_DEVICE);
 		if (unlikely(!aes->dst.sg_len)) {
-			dma_unmap_sg(cryp->dev, aes->src.sg,
-				     aes->src.nents, DMA_TO_DEVICE);
+			dma_unmap_sg(cryp->dev, aes->src.sg, aes->src.nents,
+				     DMA_TO_DEVICE);
 			goto sg_map_err;
 		}
 	}
@@ -484,7 +484,7 @@ static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
 			  const u8 *key, u32 keylen)
 {
 	struct mtk_aes_base_ctx *ctx = crypto_ablkcipher_ctx(tfm);
-	const u32 *key_tmp = (const u32 *)key;
+	const u32 *aes_key = (const u32 *)key;
 	u32 *key_state = ctx->tfm.state;
 	int i;
 
@@ -498,7 +498,7 @@ static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
 	ctx->keylen = SIZE_IN_WORDS(keylen);
 
 	for (i = 0; i < ctx->keylen; i++)
-		key_state[i] = cpu_to_le32(key_tmp[i]);
+		key_state[i] = cpu_to_le32(aes_key[i]);
 
 	return 0;
 }
@@ -512,26 +512,26 @@ static int mtk_aes_crypt(struct ablkcipher_request *req, u64 mode)
 	rctx = ablkcipher_request_ctx(req);
 	rctx->mode = mode;
 
-	return mtk_aes_handle_queue(ctx->cryp,
-			!(mode & AES_FLAGS_ENCRYPT), &req->base);
+	return mtk_aes_handle_queue(ctx->cryp, !(mode & AES_FLAGS_ENCRYPT),
+				    &req->base);
 }
 
-static int mtk_ecb_encrypt(struct ablkcipher_request *req)
+static int mtk_aes_ecb_encrypt(struct ablkcipher_request *req)
 {
 	return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_ECB);
 }
 
-static int mtk_ecb_decrypt(struct ablkcipher_request *req)
+static int mtk_aes_ecb_decrypt(struct ablkcipher_request *req)
 {
 	return mtk_aes_crypt(req, AES_FLAGS_ECB);
 }
 
-static int mtk_cbc_encrypt(struct ablkcipher_request *req)
+static int mtk_aes_cbc_encrypt(struct ablkcipher_request *req)
 {
 	return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_CBC);
 }
 
-static int mtk_cbc_decrypt(struct ablkcipher_request *req)
+static int mtk_aes_cbc_decrypt(struct ablkcipher_request *req)
 {
 	return mtk_aes_crypt(req, AES_FLAGS_CBC);
 }
@@ -554,44 +554,44 @@ static int mtk_aes_cra_init(struct crypto_tfm *tfm)
 
 static struct crypto_alg aes_algs[] = {
 {
-	.cra_name		=	"cbc(aes)",
-	.cra_driver_name	=	"cbc-aes-mtk",
-	.cra_priority		=	400,
-	.cra_flags		=	CRYPTO_ALG_TYPE_ABLKCIPHER |
-						CRYPTO_ALG_ASYNC,
-	.cra_init		=	mtk_aes_cra_init,
-	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct mtk_aes_ctx),
-	.cra_alignmask		=	15,
-	.cra_type		=	&crypto_ablkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_u.ablkcipher	=	{
-		.min_keysize	=	AES_MIN_KEY_SIZE,
-		.max_keysize	=	AES_MAX_KEY_SIZE,
-		.setkey		=	mtk_aes_setkey,
-		.encrypt	=	mtk_cbc_encrypt,
-		.decrypt	=	mtk_cbc_decrypt,
-		.ivsize		=	AES_BLOCK_SIZE,
+	.cra_name		= "cbc(aes)",
+	.cra_driver_name	= "cbc-aes-mtk",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_ASYNC,
+	.cra_init		= mtk_aes_cra_init,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct mtk_aes_ctx),
+	.cra_alignmask		= 0xf,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= mtk_aes_setkey,
+		.encrypt	= mtk_aes_cbc_encrypt,
+		.decrypt	= mtk_aes_cbc_decrypt,
+		.ivsize		= AES_BLOCK_SIZE,
 	}
 },
 {
-	.cra_name		=	"ecb(aes)",
-	.cra_driver_name	=	"ecb-aes-mtk",
-	.cra_priority		=	400,
-	.cra_flags		=	CRYPTO_ALG_TYPE_ABLKCIPHER |
-						CRYPTO_ALG_ASYNC,
-	.cra_init		=	mtk_aes_cra_init,
-	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct mtk_aes_ctx),
-	.cra_alignmask		=	15,
-	.cra_type		=	&crypto_ablkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_u.ablkcipher	=	{
-		.min_keysize	=	AES_MIN_KEY_SIZE,
-		.max_keysize	=	AES_MAX_KEY_SIZE,
-		.setkey		=	mtk_aes_setkey,
-		.encrypt	=	mtk_ecb_encrypt,
-		.decrypt	=	mtk_ecb_decrypt,
+	.cra_name		= "ecb(aes)",
+	.cra_driver_name	= "ecb-aes-mtk",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_ASYNC,
+	.cra_init		= mtk_aes_cra_init,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct mtk_aes_ctx),
+	.cra_alignmask		= 0xf,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= mtk_aes_setkey,
+		.encrypt	= mtk_aes_ecb_encrypt,
+		.decrypt	= mtk_aes_ecb_decrypt,
 	}
 },
 };
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
index 36d166b..7cd5f98 100644
--- a/drivers/crypto/mediatek/mtk-platform.h
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -124,7 +124,7 @@ struct mtk_aes_dma {
 /**
  * struct mtk_aes_rec - AES operation record
  * @queue:	crypto request queue
- * @req:	pointer to async request
+ * @areq:	pointer to async request
  * @task:	the tasklet is use in AES interrupt
  * @ctx:	pointer to current context
  * @src:	the structure that holds source sg list info
diff --git a/drivers/crypto/mediatek/mtk-sha.c b/drivers/crypto/mediatek/mtk-sha.c
index 2536ebc..55e3805 100644
--- a/drivers/crypto/mediatek/mtk-sha.c
+++ b/drivers/crypto/mediatek/mtk-sha.c
@@ -317,9 +317,9 @@ static void mtk_sha_info_init(struct mtk_sha_reqctx *ctx)
  * Update input data length field of transform information and
  * map it to DMA region.
  */
-static int mtk_sha_info_map(struct mtk_cryp *cryp,
-			    struct mtk_sha_rec *sha,
-			    size_t len)
+static int mtk_sha_info_update(struct mtk_cryp *cryp,
+			       struct mtk_sha_rec *sha,
+			       size_t len)
 {
 	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
 	struct mtk_sha_info *info = &ctx->info;
@@ -338,7 +338,7 @@ static int mtk_sha_info_map(struct mtk_cryp *cryp,
 	ctx->digcnt += len;
 
 	ctx->ct_dma = dma_map_single(cryp->dev, info, sizeof(*info),
-				      DMA_BIDIRECTIONAL);
+				     DMA_BIDIRECTIONAL);
 	if (unlikely(dma_mapping_error(cryp->dev, ctx->ct_dma))) {
 		dev_err(cryp->dev, "dma %zu bytes error\n", sizeof(*info));
 		return -EINVAL;
@@ -430,20 +430,15 @@ static int mtk_sha_xmit(struct mtk_cryp *cryp, struct mtk_sha_rec *sha,
 	struct mtk_desc *res = ring->res_base + ring->res_pos;
 	int err;
 
-	err = mtk_sha_info_map(cryp, sha, len);
+	err = mtk_sha_info_update(cryp, sha, len);
 	if (err)
 		return err;
 
 	/* Fill in the command/result descriptors */
-	res->hdr = MTK_DESC_FIRST |
-		   MTK_DESC_LAST |
-		   MTK_DESC_BUF_LEN(len);
-
+	res->hdr = MTK_DESC_FIRST | MTK_DESC_LAST | MTK_DESC_BUF_LEN(len);
 	res->buf = cpu_to_le32(cryp->tmp_dma);
 
-	cmd->hdr = MTK_DESC_FIRST |
-		   MTK_DESC_LAST |
-		   MTK_DESC_BUF_LEN(len) |
+	cmd->hdr = MTK_DESC_FIRST | MTK_DESC_LAST | MTK_DESC_BUF_LEN(len) |
 		   MTK_DESC_CT_LEN(ctx->ct_size);
 
 	cmd->buf = cpu_to_le32(addr);
@@ -477,7 +472,7 @@ static int mtk_sha_xmit2(struct mtk_cryp *cryp,
 	struct mtk_desc *res = ring->res_base + ring->res_pos;
 	int err;
 
-	err = mtk_sha_info_map(cryp, sha, len1 + len2);
+	err = mtk_sha_info_update(cryp, sha, len1 + len2);
 	if (err)
 		return err;
 
@@ -485,8 +480,7 @@ static int mtk_sha_xmit2(struct mtk_cryp *cryp,
 	res->hdr = MTK_DESC_BUF_LEN(len1) | MTK_DESC_FIRST;
 	res->buf = cpu_to_le32(cryp->tmp_dma);
 
-	cmd->hdr = MTK_DESC_BUF_LEN(len1) |
-		   MTK_DESC_FIRST |
+	cmd->hdr = MTK_DESC_BUF_LEN(len1) | MTK_DESC_FIRST |
 		   MTK_DESC_CT_LEN(ctx->ct_size);
 	cmd->buf = cpu_to_le32(sg_dma_address(ctx->sg));
 	cmd->ct = cpu_to_le32(ctx->ct_dma);
@@ -530,7 +524,7 @@ static int mtk_sha_dma_map(struct mtk_cryp *cryp,
 			   size_t count)
 {
 	ctx->dma_addr = dma_map_single(cryp->dev, ctx->buffer,
-				SHA_BUF_SIZE, DMA_TO_DEVICE);
+				       SHA_BUF_SIZE, DMA_TO_DEVICE);
 	if (unlikely(dma_mapping_error(cryp->dev, ctx->dma_addr))) {
 		dev_err(cryp->dev, "dma map error\n");
 		return -EINVAL;
@@ -619,7 +613,7 @@ static int mtk_sha_update_start(struct mtk_cryp *cryp,
 		mtk_sha_fill_padding(ctx, len);
 
 		ctx->dma_addr = dma_map_single(cryp->dev, ctx->buffer,
-			SHA_BUF_SIZE, DMA_TO_DEVICE);
+					       SHA_BUF_SIZE, DMA_TO_DEVICE);
 		if (unlikely(dma_mapping_error(cryp->dev, ctx->dma_addr))) {
 			dev_err(cryp->dev, "dma map bytes error\n");
 			return -EINVAL;
@@ -658,8 +652,7 @@ static int mtk_sha_update_start(struct mtk_cryp *cryp,
 static int mtk_sha_final_req(struct mtk_cryp *cryp,
 			     struct mtk_sha_rec *sha)
 {
-	struct ahash_request *req = sha->req;
-	struct mtk_sha_reqctx *ctx = ahash_request_ctx(req);
+	struct mtk_sha_reqctx *ctx = ahash_request_ctx(sha->req);
 	size_t count;
 
 	mtk_sha_fill_padding(ctx, 0);
@@ -690,7 +683,8 @@ static int mtk_sha_finish(struct ahash_request *req)
 }
 
 static void mtk_sha_finish_req(struct mtk_cryp *cryp,
-			       struct mtk_sha_rec *sha, int err)
+			       struct mtk_sha_rec *sha,
+			       int err)
 {
 	if (likely(!err && (SHA_FLAGS_FINAL & sha->flags)))
 		err = mtk_sha_finish(sha->req);
@@ -850,8 +844,8 @@ static int mtk_sha_digest(struct ahash_request *req)
 	return mtk_sha_init(req) ?: mtk_sha_finup(req);
 }
 
-static int mtk_sha_setkey(struct crypto_ahash *tfm,
-			  const unsigned char *key, u32 keylen)
+static int mtk_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
+			  u32 keylen)
 {
 	struct mtk_sha_ctx *tctx = crypto_ahash_ctx(tfm);
 	struct mtk_sha_hmac_ctx *bctx = tctx->base;
@@ -863,7 +857,7 @@ static int mtk_sha_setkey(struct crypto_ahash *tfm,
 
 	shash->tfm = bctx->shash;
 	shash->flags = crypto_shash_get_flags(bctx->shash) &
-			CRYPTO_TFM_REQ_MAY_SLEEP;
+		       CRYPTO_TFM_REQ_MAY_SLEEP;
 
 	if (keylen > bs) {
 		err = crypto_shash_digest(shash, key, keylen, bctx->ipad);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 7/8] crypto: mediatek - add support to CTR mode
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: linux-mediatek, linux-kernel, linux-crypto, linux-arm-kernel,
	Ryder Lee
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee@mediatek.com>

This patch adds support to the CTR mode.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/crypto/mediatek/mtk-aes.c | 151 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 146 insertions(+), 5 deletions(-)

diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index 5e7c3ce..bb5b4ff 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -23,8 +23,10 @@
 /* AES command token size */
 #define AES_CT_SIZE_ECB		2
 #define AES_CT_SIZE_CBC		3
+#define AES_CT_SIZE_CTR		3
 #define AES_CT_CTRL_HDR		cpu_to_le32(0x00220000)
-/* AES-CBC/ECB command token */
+
+/* AES-CBC/ECB/CTR command token */
 #define AES_CMD0		cpu_to_le32(0x05000000)
 #define AES_CMD1		cpu_to_le32(0x2d060000)
 #define AES_CMD2		cpu_to_le32(0xe4a63806)
@@ -39,13 +41,15 @@
 /* AES transform information word 1 fields */
 #define AES_TFM_ECB		cpu_to_le32(0x0 << 0)
 #define AES_TFM_CBC		cpu_to_le32(0x1 << 0)
-#define AES_TFM_FULL_IV		cpu_to_le32(0xf << 5)
+#define AES_TFM_CTR_LOAD	cpu_to_le32(0x6 << 0)	/* load/reuse counter */
+#define AES_TFM_FULL_IV		cpu_to_le32(0xf << 5)	/* using IV 0-3 */
 
 /* AES flags */
 #define AES_FLAGS_ECB		BIT(0)
 #define AES_FLAGS_CBC		BIT(1)
-#define AES_FLAGS_ENCRYPT	BIT(2)
-#define AES_FLAGS_BUSY		BIT(3)
+#define AES_FLAGS_CTR		BIT(2)
+#define AES_FLAGS_ENCRYPT	BIT(3)
+#define AES_FLAGS_BUSY		BIT(4)
 
 /**
  * Command token(CT) is a set of hardware instructions that
@@ -90,6 +94,15 @@ struct mtk_aes_ctx {
 	struct mtk_aes_base_ctx	base;
 };
 
+struct mtk_aes_ctr_ctx {
+	struct mtk_aes_base_ctx base;
+
+	u32	iv[AES_BLOCK_SIZE / sizeof(u32)];
+	size_t offset;
+	struct scatterlist src[2];
+	struct scatterlist dst[2];
+};
+
 struct mtk_aes_drv {
 	struct list_head dev_list;
 	/* Device list lock */
@@ -332,7 +345,7 @@ static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 	return -EINVAL;
 }
 
-/* Initialize transform information of CBC/ECB mode */
+/* Initialize transform information of CBC/ECB/CTR mode */
 static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
 			      size_t len)
 {
@@ -374,6 +387,13 @@ static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
 		ctx->tfm.ctrl[1] = AES_TFM_ECB;
 
 		ctx->ct_size = AES_CT_SIZE_ECB;
+	} else if (aes->flags & AES_FLAGS_CTR) {
+		ctx->tfm.ctrl[0] |= AES_TFM_SIZE(ctx->keylen +
+				    SIZE_IN_WORDS(AES_BLOCK_SIZE));
+		ctx->tfm.ctrl[1] = AES_TFM_CTR_LOAD | AES_TFM_FULL_IV;
+
+		ctx->ct.cmd[2] = AES_CMD2;
+		ctx->ct_size = AES_CT_SIZE_CTR;
 	}
 }
 
@@ -479,6 +499,80 @@ static int mtk_aes_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 	return mtk_aes_dma(cryp, aes, req->src, req->dst, req->nbytes);
 }
 
+static inline struct mtk_aes_ctr_ctx *
+mtk_aes_ctr_ctx_cast(struct mtk_aes_base_ctx *ctx)
+{
+	return container_of(ctx, struct mtk_aes_ctr_ctx, base);
+}
+
+static int mtk_aes_ctr_transfer(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+	struct mtk_aes_ctr_ctx *cctx = mtk_aes_ctr_ctx_cast(ctx);
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct scatterlist *src, *dst;
+	int i;
+	u32 start, end, ctr, blocks, *iv_state;
+	size_t datalen;
+	bool fragmented = false;
+
+	/* Check for transfer completion. */
+	cctx->offset += aes->total;
+	if (cctx->offset >= req->nbytes)
+		return mtk_aes_complete(cryp, aes);
+
+	/* Compute data length. */
+	datalen = req->nbytes - cctx->offset;
+	blocks = DIV_ROUND_UP(datalen, AES_BLOCK_SIZE);
+	ctr = be32_to_cpu(cctx->iv[3]);
+
+	/* Check 32bit counter overflow. */
+	start = ctr;
+	end = start + blocks - 1;
+	if (end < start) {
+		ctr |= 0xffffffff;
+		datalen = AES_BLOCK_SIZE * -start;
+		fragmented = true;
+	}
+
+	/* Jump to offset. */
+	src = scatterwalk_ffwd(cctx->src, req->src, cctx->offset);
+	dst = ((req->src == req->dst) ? src :
+	       scatterwalk_ffwd(cctx->dst, req->dst, cctx->offset));
+
+	/* Write IVs into transform state buffer. */
+	iv_state = ctx->tfm.state + ctx->keylen;
+	for (i = 0; i < SIZE_IN_WORDS(AES_BLOCK_SIZE); i++)
+		iv_state[i] = cpu_to_le32(cctx->iv[i]);
+
+	if (unlikely(fragmented)) {
+	/*
+	 * Increment the counter manually to cope with the hardware
+	 * counter overflow.
+	 */
+		cctx->iv[3] = cpu_to_be32(ctr);
+		crypto_inc((u8 *)cctx->iv, AES_BLOCK_SIZE);
+	}
+	aes->resume = mtk_aes_ctr_transfer;
+
+	return mtk_aes_dma(cryp, aes, src, dst, datalen);
+}
+
+static int mtk_aes_ctr_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_ctr_ctx *cctx = mtk_aes_ctr_ctx_cast(aes->ctx);
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+
+	mtk_aes_set_mode(aes, rctx);
+
+	memcpy(cctx->iv, req->info, AES_BLOCK_SIZE);
+	cctx->offset = 0;
+	aes->total = 0;
+
+	return mtk_aes_ctr_transfer(cryp, aes);
+}
+
 /* Check and set the AES key to transform state buffer */
 static int mtk_aes_setkey(struct crypto_ablkcipher *tfm,
 			  const u8 *key, u32 keylen)
@@ -536,6 +630,16 @@ static int mtk_aes_cbc_decrypt(struct ablkcipher_request *req)
 	return mtk_aes_crypt(req, AES_FLAGS_CBC);
 }
 
+static int mtk_aes_ctr_encrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_ENCRYPT | AES_FLAGS_CTR);
+}
+
+static int mtk_aes_ctr_decrypt(struct ablkcipher_request *req)
+{
+	return mtk_aes_crypt(req, AES_FLAGS_CTR);
+}
+
 static int mtk_aes_cra_init(struct crypto_tfm *tfm)
 {
 	struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -552,6 +656,22 @@ static int mtk_aes_cra_init(struct crypto_tfm *tfm)
 	return 0;
 }
 
+static int mtk_aes_ctr_cra_init(struct crypto_tfm *tfm)
+{
+	struct mtk_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct mtk_cryp *cryp = NULL;
+
+	cryp = mtk_aes_find_dev(&ctx->base);
+	if (!cryp) {
+		pr_err("can't find crypto device\n");
+		return -ENODEV;
+	}
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct mtk_aes_reqctx);
+	ctx->base.start = mtk_aes_ctr_start;
+	return 0;
+}
+
 static struct crypto_alg aes_algs[] = {
 {
 	.cra_name		= "cbc(aes)",
@@ -594,6 +714,27 @@ static int mtk_aes_cra_init(struct crypto_tfm *tfm)
 		.decrypt	= mtk_aes_ecb_decrypt,
 	}
 },
+{
+	.cra_name		= "ctr(aes)",
+	.cra_driver_name	= "ctr-aes-mtk",
+	.cra_priority		= 400,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_ASYNC,
+	.cra_init		= mtk_aes_ctr_cra_init,
+	.cra_blocksize		= 1,
+	.cra_ctxsize		= sizeof(struct mtk_aes_ctr_ctx),
+	.cra_alignmask		= 0xf,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.setkey		= mtk_aes_setkey,
+		.encrypt	= mtk_aes_ctr_encrypt,
+		.decrypt	= mtk_aes_ctr_decrypt,
+	}
+},
 };
 
 static void mtk_aes_enc_task(unsigned long data)
-- 
1.9.1

^ permalink raw reply related

* [PATCH 5/8] crypto: mediatek - regroup functions by usage
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: linux-mediatek, linux-kernel, linux-crypto, linux-arm-kernel,
	Ryder Lee
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee@mediatek.com>

This patch only regroup functions by usage.
This will help to integrate the GCM support patch later by
adjusting some shared code section, such as common code which
will be reused by GCM, AES mode setting, and DMA transfer.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/crypto/mediatek/mtk-aes.c | 272 ++++++++++++++++++++------------------
 1 file changed, 141 insertions(+), 131 deletions(-)

diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index 9c4e468..b5946e9 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -42,7 +42,6 @@
 #define AES_TFM_FULL_IV		cpu_to_le32(0xf << 5)
 
 /* AES flags */
-#define AES_FLAGS_MODE_MSK	0x7
 #define AES_FLAGS_ECB		BIT(0)
 #define AES_FLAGS_CBC		BIT(1)
 #define AES_FLAGS_ENCRYPT	BIT(2)
@@ -170,65 +169,28 @@ static bool mtk_aes_check_aligned(struct scatterlist *sg, size_t len,
 	return false;
 }
 
-/* Initialize and map transform information of AES */
-static int mtk_aes_info_map(struct mtk_cryp *cryp,
-			    struct mtk_aes_rec *aes,
-			    size_t len)
+static inline void mtk_aes_set_mode(struct mtk_aes_rec *aes,
+				    const struct mtk_aes_reqctx *rctx)
 {
-	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
-	struct mtk_aes_base_ctx *ctx = aes->ctx;
-
-	ctx->ct_hdr = AES_CT_CTRL_HDR | cpu_to_le32(len);
-	ctx->ct.cmd[0] = AES_CMD0 | cpu_to_le32(len);
-	ctx->ct.cmd[1] = AES_CMD1;
-
-	if (aes->flags & AES_FLAGS_ENCRYPT)
-		ctx->tfm.ctrl[0] = AES_TFM_BASIC_OUT;
-	else
-		ctx->tfm.ctrl[0] = AES_TFM_BASIC_IN;
-
-	if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_128))
-		ctx->tfm.ctrl[0] |= AES_TFM_128BITS;
-	else if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_256))
-		ctx->tfm.ctrl[0] |= AES_TFM_256BITS;
-	else if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_192))
-		ctx->tfm.ctrl[0] |= AES_TFM_192BITS;
-
-	if (aes->flags & AES_FLAGS_CBC) {
-		const u32 *iv = (const u32 *)req->info;
-		u32 *iv_state = ctx->tfm.state + ctx->keylen;
-		int i;
-
-		ctx->tfm.ctrl[0] |= AES_TFM_SIZE(ctx->keylen +
-				  SIZE_IN_WORDS(AES_BLOCK_SIZE));
-		ctx->tfm.ctrl[1] = AES_TFM_CBC | AES_TFM_FULL_IV;
-
-		for (i = 0; i < SIZE_IN_WORDS(AES_BLOCK_SIZE); i++)
-			iv_state[i] = cpu_to_le32(iv[i]);
+	/* Clear all but persistent flags and set request flags. */
+	aes->flags = (aes->flags & AES_FLAGS_BUSY) | rctx->mode;
+}
 
-		ctx->ct.cmd[2] = AES_CMD2;
-		ctx->ct_size  = AES_CT_SIZE_CBC;
-	} else if (aes->flags & AES_FLAGS_ECB) {
-		ctx->tfm.ctrl[0] |= AES_TFM_SIZE(ctx->keylen);
-		ctx->tfm.ctrl[1] = AES_TFM_ECB;
+static inline void mtk_aes_restore_sg(const struct mtk_aes_dma *dma)
+{
+	struct scatterlist *sg = dma->sg;
+	int nents = dma->nents;
 
-		ctx->ct_size = AES_CT_SIZE_ECB;
-	}
+	if (!dma->remainder)
+		return;
 
-	ctx->ct_dma = dma_map_single(cryp->dev, &ctx->ct, sizeof(ctx->ct),
-				     DMA_TO_DEVICE);
-	if (unlikely(dma_mapping_error(cryp->dev, ctx->ct_dma)))
-		return -EINVAL;
+	while (--nents > 0 && sg)
+		sg = sg_next(sg);
 
-	ctx->tfm_dma = dma_map_single(cryp->dev, &ctx->tfm, sizeof(ctx->tfm),
-				      DMA_TO_DEVICE);
-	if (unlikely(dma_mapping_error(cryp->dev, ctx->tfm_dma))) {
-		dma_unmap_single(cryp->dev, ctx->tfm_dma, sizeof(ctx->tfm),
-				 DMA_TO_DEVICE);
-		return -EINVAL;
-	}
+	if (!sg)
+		return;
 
-	return 0;
+	sg->length += dma->remainder;
 }
 
 /*
@@ -288,24 +250,134 @@ static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 	return -EINPROGRESS;
 }
 
-static inline void mtk_aes_restore_sg(const struct mtk_aes_dma *dma)
+static void mtk_aes_unmap(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 {
-	struct scatterlist *sg = dma->sg;
-	int nents = dma->nents;
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
 
-	if (!dma->remainder)
-		return;
+	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(ctx->ct),
+			 DMA_TO_DEVICE);
+	dma_unmap_single(cryp->dev, ctx->tfm_dma, sizeof(ctx->tfm),
+			 DMA_TO_DEVICE);
 
-	while (--nents > 0 && sg)
-		sg = sg_next(sg);
+	if (aes->src.sg == aes->dst.sg) {
+		dma_unmap_sg(cryp->dev, aes->src.sg, aes->src.nents,
+			     DMA_BIDIRECTIONAL);
 
-	if (!sg)
-		return;
+		if (aes->src.sg != &aes->aligned_sg)
+			mtk_aes_restore_sg(&aes->src);
+	} else {
+		dma_unmap_sg(cryp->dev, aes->dst.sg, aes->dst.nents,
+			     DMA_FROM_DEVICE);
 
-	sg->length += dma->remainder;
+		if (aes->dst.sg != &aes->aligned_sg)
+			mtk_aes_restore_sg(&aes->dst);
+
+		dma_unmap_sg(cryp->dev, aes->src.sg, aes->src.nents,
+			     DMA_TO_DEVICE);
+
+		if (aes->src.sg != &aes->aligned_sg)
+			mtk_aes_restore_sg(&aes->src);
+	}
+
+	if (aes->dst.sg == &aes->aligned_sg)
+		sg_copy_from_buffer(aes->real_dst, sg_nents(aes->real_dst),
+				    aes->buf, aes->total);
 }
 
-static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+
+	ctx->ct_dma = dma_map_single(cryp->dev, &ctx->ct, sizeof(ctx->ct),
+				     DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(cryp->dev, ctx->ct_dma)))
+		return -EINVAL;
+
+	ctx->tfm_dma = dma_map_single(cryp->dev, &ctx->tfm, sizeof(ctx->tfm),
+				      DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(cryp->dev, ctx->tfm_dma)))
+		goto tfm_map_err;
+
+	if (aes->src.sg == aes->dst.sg) {
+		aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
+					     aes->src.nents,
+					     DMA_BIDIRECTIONAL);
+		aes->dst.sg_len = aes->src.sg_len;
+		if (unlikely(!aes->src.sg_len))
+			goto sg_map_err;
+	} else {
+		aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
+					     aes->src.nents, DMA_TO_DEVICE);
+		if (unlikely(!aes->src.sg_len))
+			goto sg_map_err;
+
+		aes->dst.sg_len = dma_map_sg(cryp->dev, aes->dst.sg,
+					     aes->dst.nents, DMA_FROM_DEVICE);
+		if (unlikely(!aes->dst.sg_len)) {
+			dma_unmap_sg(cryp->dev, aes->src.sg,
+				     aes->src.nents, DMA_TO_DEVICE);
+			goto sg_map_err;
+		}
+	}
+
+	return mtk_aes_xmit(cryp, aes);
+
+sg_map_err:
+	dma_unmap_single(cryp->dev, ctx->tfm_dma, sizeof(ctx->tfm),
+			 DMA_TO_DEVICE);
+tfm_map_err:
+	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(ctx->ct),
+			 DMA_TO_DEVICE);
+
+	return -EINVAL;
+}
+
+/* Initialize transform information of CBC/ECB mode */
+static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+			      size_t len)
+{
+	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+
+	ctx->ct_hdr = AES_CT_CTRL_HDR | cpu_to_le32(len);
+	ctx->ct.cmd[0] = AES_CMD0 | cpu_to_le32(len);
+	ctx->ct.cmd[1] = AES_CMD1;
+
+	if (aes->flags & AES_FLAGS_ENCRYPT)
+		ctx->tfm.ctrl[0] = AES_TFM_BASIC_OUT;
+	else
+		ctx->tfm.ctrl[0] = AES_TFM_BASIC_IN;
+
+	if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_128))
+		ctx->tfm.ctrl[0] |= AES_TFM_128BITS;
+	else if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_256))
+		ctx->tfm.ctrl[0] |= AES_TFM_256BITS;
+	else
+		ctx->tfm.ctrl[0] |= AES_TFM_192BITS;
+
+	if (aes->flags & AES_FLAGS_CBC) {
+		const u32 *iv = (const u32 *)req->info;
+		u32 *iv_state = ctx->tfm.state + ctx->keylen;
+		int i;
+
+		ctx->tfm.ctrl[0] |= AES_TFM_SIZE(ctx->keylen +
+				    SIZE_IN_WORDS(AES_BLOCK_SIZE));
+		ctx->tfm.ctrl[1] = AES_TFM_CBC | AES_TFM_FULL_IV;
+
+		for (i = 0; i < SIZE_IN_WORDS(AES_BLOCK_SIZE); i++)
+			iv_state[i] = cpu_to_le32(iv[i]);
+
+		ctx->ct.cmd[2] = AES_CMD2;
+		ctx->ct_size = AES_CT_SIZE_CBC;
+	} else if (aes->flags & AES_FLAGS_ECB) {
+		ctx->tfm.ctrl[0] |= AES_TFM_SIZE(ctx->keylen);
+		ctx->tfm.ctrl[1] = AES_TFM_ECB;
+
+		ctx->ct_size = AES_CT_SIZE_ECB;
+	}
+}
+
+static int mtk_aes_dma(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
 		       struct scatterlist *src, struct scatterlist *dst,
 		       size_t len)
 {
@@ -346,28 +418,9 @@ static int mtk_aes_map(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
 		sg_set_buf(&aes->aligned_sg, aes->buf, len + padlen);
 	}
 
-	if (aes->src.sg == aes->dst.sg) {
-		aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
-				aes->src.nents, DMA_BIDIRECTIONAL);
-		aes->dst.sg_len = aes->src.sg_len;
-		if (unlikely(!aes->src.sg_len))
-			return -EFAULT;
-	} else {
-		aes->src.sg_len = dma_map_sg(cryp->dev, aes->src.sg,
-				aes->src.nents, DMA_TO_DEVICE);
-		if (unlikely(!aes->src.sg_len))
-			return -EFAULT;
-
-		aes->dst.sg_len = dma_map_sg(cryp->dev, aes->dst.sg,
-				aes->dst.nents, DMA_FROM_DEVICE);
-		if (unlikely(!aes->dst.sg_len)) {
-			dma_unmap_sg(cryp->dev, aes->src.sg,
-				     aes->src.nents, DMA_TO_DEVICE);
-			return -EFAULT;
-		}
-	}
+	mtk_aes_info_init(cryp, aes, len + padlen);
 
-	return mtk_aes_info_map(cryp, aes, len + padlen);
+	return mtk_aes_map(cryp, aes);
 }
 
 static int mtk_aes_handle_queue(struct mtk_cryp *cryp, u8 id,
@@ -419,54 +472,11 @@ static int mtk_aes_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 {
 	struct ablkcipher_request *req = ablkcipher_request_cast(aes->areq);
 	struct mtk_aes_reqctx *rctx = ablkcipher_request_ctx(req);
-	int err;
-
-	rctx = ablkcipher_request_ctx(req);
-	rctx->mode &= AES_FLAGS_MODE_MSK;
-	aes->flags = (aes->flags & ~AES_FLAGS_MODE_MSK) | rctx->mode;
 
+	mtk_aes_set_mode(aes, rctx);
 	aes->resume = mtk_aes_complete;
 
-	err = mtk_aes_map(cryp, aes, req->src, req->dst, req->nbytes);
-	if (err)
-		return err;
-
-	return mtk_aes_xmit(cryp, aes);
-}
-
-static void mtk_aes_unmap(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
-{
-	struct mtk_aes_base_ctx *ctx = aes->ctx;
-
-	dma_unmap_single(cryp->dev, ctx->ct_dma, sizeof(ctx->ct),
-			 DMA_TO_DEVICE);
-	dma_unmap_single(cryp->dev, ctx->tfm_dma, sizeof(ctx->tfm),
-			 DMA_TO_DEVICE);
-
-	if (aes->src.sg == aes->dst.sg) {
-		dma_unmap_sg(cryp->dev, aes->src.sg,
-			     aes->src.nents, DMA_BIDIRECTIONAL);
-
-		if (aes->src.sg != &aes->aligned_sg)
-			mtk_aes_restore_sg(&aes->src);
-	} else {
-		dma_unmap_sg(cryp->dev, aes->dst.sg,
-			     aes->dst.nents, DMA_FROM_DEVICE);
-
-		if (aes->dst.sg != &aes->aligned_sg)
-			mtk_aes_restore_sg(&aes->dst);
-
-		dma_unmap_sg(cryp->dev, aes->src.sg,
-			     aes->src.nents, DMA_TO_DEVICE);
-
-		if (aes->src.sg != &aes->aligned_sg)
-			mtk_aes_restore_sg(&aes->src);
-	}
-
-	if (aes->dst.sg == &aes->aligned_sg)
-		sg_copy_from_buffer(aes->real_dst,
-				    sg_nents(aes->real_dst),
-				    aes->buf, aes->total);
+	return mtk_aes_dma(cryp, aes, req->src, req->dst, req->nbytes);
 }
 
 /* Check and set the AES key to transform state buffer */
-- 
1.9.1

^ permalink raw reply related

* [PATCH 8/8] crypto: mediatek - add support to GCM mode
From: Ryder Lee @ 2017-01-20  5:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller
  Cc: linux-mediatek, linux-kernel, linux-crypto, linux-arm-kernel,
	Ryder Lee
In-Reply-To: <1484890875-57105-1-git-send-email-ryder.lee@mediatek.com>

This patch adds support to the GCM mode.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/crypto/Kconfig                 |   2 +
 drivers/crypto/mediatek/mtk-aes.c      | 369 ++++++++++++++++++++++++++++++++-
 drivers/crypto/mediatek/mtk-platform.h |   2 +
 3 files changed, 369 insertions(+), 4 deletions(-)

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ee5057a..bf7da55 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -557,7 +557,9 @@ config CRYPTO_DEV_MEDIATEK
 	tristate "MediaTek's EIP97 Cryptographic Engine driver"
 	depends on (ARM && ARCH_MEDIATEK) || COMPILE_TEST
 	select CRYPTO_AES
+	select CRYPTO_AEAD
 	select CRYPTO_BLKCIPHER
+	select CRYPTO_CTR
 	select CRYPTO_SHA1
 	select CRYPTO_SHA256
 	select CRYPTO_SHA512
diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index bb5b4ff..3a47cdb 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -24,16 +24,28 @@
 #define AES_CT_SIZE_ECB		2
 #define AES_CT_SIZE_CBC		3
 #define AES_CT_SIZE_CTR		3
+#define AES_CT_SIZE_GCM_OUT	5
+#define AES_CT_SIZE_GCM_IN	6
 #define AES_CT_CTRL_HDR		cpu_to_le32(0x00220000)
 
 /* AES-CBC/ECB/CTR command token */
 #define AES_CMD0		cpu_to_le32(0x05000000)
 #define AES_CMD1		cpu_to_le32(0x2d060000)
 #define AES_CMD2		cpu_to_le32(0xe4a63806)
+/* AES-GCM command token */
+#define AES_GCM_CMD0		cpu_to_le32(0x0b000000)
+#define AES_GCM_CMD1		cpu_to_le32(0xa0800000)
+#define AES_GCM_CMD2		cpu_to_le32(0x25000010)
+#define AES_GCM_CMD3		cpu_to_le32(0x0f020000)
+#define AES_GCM_CMD4		cpu_to_le32(0x21e60000)
+#define AES_GCM_CMD5		cpu_to_le32(0x40e60000)
+#define AES_GCM_CMD6		cpu_to_le32(0xd0070000)
 
 /* AES transform information word 0 fields */
 #define AES_TFM_BASIC_OUT	cpu_to_le32(0x4 << 0)
 #define AES_TFM_BASIC_IN	cpu_to_le32(0x5 << 0)
+#define AES_TFM_GCM_OUT		cpu_to_le32(0x6 << 0)
+#define AES_TFM_GCM_IN		cpu_to_le32(0xf << 0)
 #define AES_TFM_SIZE(x)		cpu_to_le32((x) << 8)
 #define AES_TFM_128BITS		cpu_to_le32(0xb << 16)
 #define AES_TFM_192BITS		cpu_to_le32(0xd << 16)
@@ -41,15 +53,22 @@
 /* AES transform information word 1 fields */
 #define AES_TFM_ECB		cpu_to_le32(0x0 << 0)
 #define AES_TFM_CBC		cpu_to_le32(0x1 << 0)
+#define AES_TFM_CTR_INIT	cpu_to_le32(0x2 << 0)	/* init counter to 1 */
 #define AES_TFM_CTR_LOAD	cpu_to_le32(0x6 << 0)	/* load/reuse counter */
+#define AES_TFM_3IV		cpu_to_le32(0x7 << 5)	/* using IV 0-2 */
 #define AES_TFM_FULL_IV		cpu_to_le32(0xf << 5)	/* using IV 0-3 */
+#define AES_TFM_IV_CTR_MODE	cpu_to_le32(0x1 << 10)
+#define AES_TFM_ENC_HASH	cpu_to_le32(0x1 << 17)
+#define AES_TFM_GHASH_DIG	cpu_to_le32(0x2 << 21)
+#define AES_TFM_GHASH		cpu_to_le32(0x4 << 23)
 
 /* AES flags */
 #define AES_FLAGS_ECB		BIT(0)
 #define AES_FLAGS_CBC		BIT(1)
 #define AES_FLAGS_CTR		BIT(2)
-#define AES_FLAGS_ENCRYPT	BIT(3)
-#define AES_FLAGS_BUSY		BIT(4)
+#define AES_FLAGS_GCM		BIT(3)
+#define AES_FLAGS_ENCRYPT	BIT(4)
+#define AES_FLAGS_BUSY		BIT(5)
 
 /**
  * Command token(CT) is a set of hardware instructions that
@@ -62,14 +81,23 @@
  * - Commands decoding and control of the engine's data path.
  * - Coordinating hardware data fetch and store operations.
  * - Result token construction and output.
+ *
+ * Memory map of GCM's TFM:
+ * /-----------\
+ * |  AES KEY  | 128/196/256 bits
+ * |-----------|
+ * |  HASH KEY | a string 128 zero bits encrypted using the block cipher
+ * |-----------|
+ * |    IVs    | 4 * 4 bytes
+ * \-----------/
  */
 struct mtk_aes_ct {
-	__le32 cmd[AES_CT_SIZE_CBC];
+	__le32 cmd[AES_CT_SIZE_GCM_IN];
 };
 
 struct mtk_aes_tfm {
 	__le32 ctrl[2];
-	__le32 state[SIZE_IN_WORDS(AES_KEYSIZE_256 + AES_BLOCK_SIZE)];
+	__le32 state[SIZE_IN_WORDS(AES_KEYSIZE_256 + AES_BLOCK_SIZE * 2)];
 };
 
 struct mtk_aes_reqctx {
@@ -103,6 +131,20 @@ struct mtk_aes_ctr_ctx {
 	struct scatterlist dst[2];
 };
 
+struct mtk_aes_gcm_ctx {
+	struct mtk_aes_base_ctx base;
+
+	u32 authsize;
+	size_t textlen;
+
+	struct crypto_skcipher *ctr;
+};
+
+struct mtk_aes_gcm_setkey_result {
+	int err;
+	struct completion completion;
+};
+
 struct mtk_aes_drv {
 	struct list_head dev_list;
 	/* Device list lock */
@@ -251,6 +293,10 @@ static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 	}
 	res->hdr |= MTK_DESC_LAST;
 
+	/* Prepare enough space for authenticated tag */
+	if (aes->flags & AES_FLAGS_GCM)
+		res->hdr += AES_BLOCK_SIZE;
+
 	/*
 	 * Make sure that all changes to the DMA ring are done before we
 	 * start engine.
@@ -737,6 +783,315 @@ static int mtk_aes_ctr_cra_init(struct crypto_tfm *tfm)
 },
 };
 
+static inline struct mtk_aes_gcm_ctx *
+mtk_aes_gcm_ctx_cast(struct mtk_aes_base_ctx *ctx)
+{
+	return container_of(ctx, struct mtk_aes_gcm_ctx, base);
+}
+
+/* Initialize transform information of GCM mode */
+static void mtk_aes_gcm_info_init(struct mtk_cryp *cryp,
+				  struct mtk_aes_rec *aes,
+				  size_t len)
+{
+	struct aead_request *req = aead_request_cast(aes->areq);
+	struct mtk_aes_base_ctx *ctx = aes->ctx;
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx);
+	const u32 *iv = (const u32 *)req->iv;
+	u32 *iv_state = ctx->tfm.state + ctx->keylen +
+			SIZE_IN_WORDS(AES_BLOCK_SIZE);
+	u32 ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req));
+	int i;
+
+	ctx->ct_hdr = AES_CT_CTRL_HDR | len;
+
+	ctx->ct.cmd[0] = AES_GCM_CMD0 | cpu_to_le32(req->assoclen);
+	ctx->ct.cmd[1] = AES_GCM_CMD1 | cpu_to_le32(req->assoclen);
+	ctx->ct.cmd[2] = AES_GCM_CMD2;
+	ctx->ct.cmd[3] = AES_GCM_CMD3 | cpu_to_le32(gctx->textlen);
+
+	if (aes->flags & AES_FLAGS_ENCRYPT) {
+		ctx->ct.cmd[4] = AES_GCM_CMD4 | cpu_to_le32(gctx->authsize);
+		ctx->ct_size = AES_CT_SIZE_GCM_OUT;
+		ctx->tfm.ctrl[0] = AES_TFM_GCM_OUT;
+	} else {
+		ctx->ct.cmd[4] = AES_GCM_CMD5 | cpu_to_le32(gctx->authsize);
+		ctx->ct.cmd[5] = AES_GCM_CMD6 | cpu_to_le32(gctx->authsize);
+		ctx->ct_size = AES_CT_SIZE_GCM_IN;
+		ctx->tfm.ctrl[0] = AES_TFM_GCM_IN;
+	}
+
+	if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_128))
+		ctx->tfm.ctrl[0] |= AES_TFM_128BITS;
+	else if (ctx->keylen == SIZE_IN_WORDS(AES_KEYSIZE_256))
+		ctx->tfm.ctrl[0] |= AES_TFM_256BITS;
+	else
+		ctx->tfm.ctrl[0] |= AES_TFM_192BITS;
+
+	ctx->tfm.ctrl[0] |= AES_TFM_GHASH_DIG | AES_TFM_GHASH |
+			    AES_TFM_SIZE(ctx->keylen + SIZE_IN_WORDS(
+			    AES_BLOCK_SIZE + ivsize));
+	ctx->tfm.ctrl[1] = AES_TFM_CTR_INIT | AES_TFM_IV_CTR_MODE |
+			   AES_TFM_3IV | AES_TFM_ENC_HASH;
+
+	for (i = 0; i < SIZE_IN_WORDS(ivsize); i++)
+		iv_state[i] = cpu_to_le32(iv[i]);
+}
+
+static int mtk_aes_gcm_dma(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
+			   struct scatterlist *src, struct scatterlist *dst,
+			   size_t len)
+{
+	bool src_aligned, dst_aligned;
+
+	aes->src.sg = src;
+	aes->dst.sg = dst;
+	aes->real_dst = dst;
+
+	src_aligned = mtk_aes_check_aligned(src, len, &aes->src);
+	if (src == dst)
+		dst_aligned = src_aligned;
+	else
+		dst_aligned = mtk_aes_check_aligned(dst, len, &aes->dst);
+
+	if (!src_aligned || !dst_aligned) {
+		if (aes->total > AES_BUF_SIZE)
+			return -ENOMEM;
+
+		if (!src_aligned) {
+			sg_copy_to_buffer(src, sg_nents(src), aes->buf, len);
+			aes->src.sg = &aes->aligned_sg;
+			aes->src.nents = 1;
+			aes->src.remainder = 0;
+		}
+
+		if (!dst_aligned) {
+			aes->dst.sg = &aes->aligned_sg;
+			aes->dst.nents = 1;
+			aes->dst.remainder = 0;
+		}
+
+		sg_init_table(&aes->aligned_sg, 1);
+		sg_set_buf(&aes->aligned_sg, aes->buf, aes->total);
+	}
+
+	mtk_aes_gcm_info_init(cryp, aes, len);
+
+	return mtk_aes_map(cryp, aes);
+}
+
+/* Todo: GMAC */
+static int mtk_aes_gcm_start(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
+{
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(aes->ctx);
+	struct aead_request *req = aead_request_cast(aes->areq);
+	struct mtk_aes_reqctx *rctx = aead_request_ctx(req);
+	u32 len = req->assoclen + req->cryptlen;
+
+	mtk_aes_set_mode(aes, rctx);
+
+	if (aes->flags & AES_FLAGS_ENCRYPT) {
+		u32 tag[4];
+		/* Compute total process length. */
+		aes->total = len + gctx->authsize;
+		/* Compute text length. */
+		gctx->textlen = req->cryptlen;
+		/* Hardware will append authenticated tag to output buffer */
+		scatterwalk_map_and_copy(tag, req->dst, len, gctx->authsize, 1);
+	} else {
+		aes->total = len;
+		gctx->textlen = req->cryptlen - gctx->authsize;
+	}
+	aes->resume = mtk_aes_complete;
+
+	return mtk_aes_gcm_dma(cryp, aes, req->src, req->dst, len);
+}
+
+static int mtk_aes_gcm_crypt(struct aead_request *req, u64 mode)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+	struct mtk_aes_reqctx *rctx = aead_request_ctx(req);
+
+	rctx->mode = AES_FLAGS_GCM | mode;
+
+	return mtk_aes_handle_queue(ctx->cryp, !!(mode & AES_FLAGS_ENCRYPT),
+								&req->base);
+}
+
+static void mtk_gcm_setkey_done(struct crypto_async_request *req, int err)
+{
+	struct mtk_aes_gcm_setkey_result *result = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	result->err = err;
+	complete(&result->completion);
+}
+
+/*
+ * Because of the hardware limitation, we need to pre-calculate key(H)
+ * for the GHASH operation. The result of the encryption operation
+ * need to be stored in the transform state buffer.
+ */
+static int mtk_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key,
+			      u32 keylen)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(aead);
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx);
+	struct crypto_skcipher *ctr = gctx->ctr;
+	struct {
+		u32 hash[4];
+		u8 iv[8];
+
+		struct mtk_aes_gcm_setkey_result result;
+
+		struct scatterlist sg[1];
+		struct skcipher_request req;
+	} *data;
+	const u32 *aes_key;
+	u32 *key_state, *hash_state;
+	int err, i;
+
+	if (keylen != AES_KEYSIZE_256 &&
+	    keylen != AES_KEYSIZE_192 &&
+	    keylen != AES_KEYSIZE_128) {
+		crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	key_state = ctx->tfm.state;
+	aes_key = (u32 *)key;
+	ctx->keylen = SIZE_IN_WORDS(keylen);
+
+	for (i = 0; i < ctx->keylen; i++)
+		ctx->tfm.state[i] = cpu_to_le32(aes_key[i]);
+
+	/* Same as crypto_gcm_setkey() from crypto/gcm.c */
+	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
+	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
+				  CRYPTO_TFM_REQ_MASK);
+	err = crypto_skcipher_setkey(ctr, key, keylen);
+	crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) &
+			      CRYPTO_TFM_RES_MASK);
+	if (err)
+		return err;
+
+	data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr),
+		       GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	init_completion(&data->result.completion);
+	sg_init_one(data->sg, &data->hash, AES_BLOCK_SIZE);
+	skcipher_request_set_tfm(&data->req, ctr);
+	skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
+				      CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      mtk_gcm_setkey_done, &data->result);
+	skcipher_request_set_crypt(&data->req, data->sg, data->sg,
+				   AES_BLOCK_SIZE, data->iv);
+
+	err = crypto_skcipher_encrypt(&data->req);
+	if (err == -EINPROGRESS || err == -EBUSY) {
+		err = wait_for_completion_interruptible(
+			&data->result.completion);
+		if (!err)
+			err = data->result.err;
+	}
+	if (err)
+		goto out;
+
+	hash_state = key_state + ctx->keylen;
+
+	for (i = 0; i < 4; i++)
+		hash_state[i] = cpu_to_be32(data->hash[i]);
+out:
+	kzfree(data);
+	return err;
+}
+
+static int mtk_aes_gcm_setauthsize(struct crypto_aead *aead,
+				   u32 authsize)
+{
+	struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(aead);
+	struct mtk_aes_gcm_ctx *gctx = mtk_aes_gcm_ctx_cast(ctx);
+
+	/* Same as crypto_gcm_authsize() from crypto/gcm.c */
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	gctx->authsize = authsize;
+	return 0;
+}
+
+static int mtk_aes_gcm_encrypt(struct aead_request *req)
+{
+	return mtk_aes_gcm_crypt(req, AES_FLAGS_ENCRYPT);
+}
+
+static int mtk_aes_gcm_decrypt(struct aead_request *req)
+{
+	return mtk_aes_gcm_crypt(req, 0);
+}
+
+static int mtk_aes_gcm_init(struct crypto_aead *aead)
+{
+	struct mtk_aes_gcm_ctx *ctx = crypto_aead_ctx(aead);
+	struct mtk_cryp *cryp = NULL;
+
+	cryp = mtk_aes_find_dev(&ctx->base);
+	if (!cryp) {
+		pr_err("can't find crypto device\n");
+		return -ENODEV;
+	}
+
+	ctx->ctr = crypto_alloc_skcipher("ctr(aes)", 0,
+					 CRYPTO_ALG_ASYNC);
+	if (IS_ERR(ctx->ctr)) {
+		pr_err("Error allocating ctr(aes)\n");
+		return PTR_ERR(ctx->ctr);
+	}
+
+	crypto_aead_set_reqsize(aead, sizeof(struct mtk_aes_reqctx));
+	ctx->base.start = mtk_aes_gcm_start;
+	return 0;
+}
+
+static void mtk_aes_gcm_exit(struct crypto_aead *aead)
+{
+	struct mtk_aes_gcm_ctx *ctx = crypto_aead_ctx(aead);
+
+	crypto_free_skcipher(ctx->ctr);
+}
+
+static struct aead_alg aes_gcm_alg = {
+	.setkey		= mtk_aes_gcm_setkey,
+	.setauthsize	= mtk_aes_gcm_setauthsize,
+	.encrypt	= mtk_aes_gcm_encrypt,
+	.decrypt	= mtk_aes_gcm_decrypt,
+	.init		= mtk_aes_gcm_init,
+	.exit		= mtk_aes_gcm_exit,
+	.ivsize		= 12,
+	.maxauthsize	= AES_BLOCK_SIZE,
+
+	.base = {
+		.cra_name		= "gcm(aes)",
+		.cra_driver_name	= "gcm-aes-mtk",
+		.cra_priority		= 400,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= 1,
+		.cra_ctxsize		= sizeof(struct mtk_aes_gcm_ctx),
+		.cra_alignmask		= 0xf,
+		.cra_module		= THIS_MODULE,
+	},
+};
+
 static void mtk_aes_enc_task(unsigned long data)
 {
 	struct mtk_cryp *cryp = (struct mtk_cryp *)data;
@@ -851,6 +1206,8 @@ static void mtk_aes_unregister_algs(void)
 {
 	int i;
 
+	crypto_unregister_aead(&aes_gcm_alg);
+
 	for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
 		crypto_unregister_alg(&aes_algs[i]);
 }
@@ -865,6 +1222,10 @@ static int mtk_aes_register_algs(void)
 			goto err_aes_algs;
 	}
 
+	err = crypto_register_aead(&aes_gcm_alg);
+	if (err)
+		goto err_aes_algs;
+
 	return 0;
 
 err_aes_algs:
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
index 7cd5f98..ed6d871 100644
--- a/drivers/crypto/mediatek/mtk-platform.h
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -13,8 +13,10 @@
 #define __MTK_PLATFORM_H_
 
 #include <crypto/algapi.h>
+#include <crypto/internal/aead.h>
 #include <crypto/internal/hash.h>
 #include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
 #include <linux/crypto.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
-- 
1.9.1

^ permalink raw reply related

* [PATCH] crypto: vmx -- disable preemption to enable vsx in aes_ctr.c
From: Li Zhong @ 2017-01-20  8:35 UTC (permalink / raw)
  To: linux-crypto; +Cc: leosilva, pfsmorigo, herbert

Some preemptible check warnings were reported from enable_kernel_vsx(). This
patch disables preemption in aes_ctr.c before enabling vsx, and they are now 
consistent with other files in the same directory.

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
---
 drivers/crypto/vmx/aes_ctr.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c
index 38ed10d..7cf6d31 100644
--- a/drivers/crypto/vmx/aes_ctr.c
+++ b/drivers/crypto/vmx/aes_ctr.c
@@ -80,11 +80,13 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key,
 	int ret;
 	struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
 
+	preempt_disable();
 	pagefault_disable();
 	enable_kernel_vsx();
 	ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
 	disable_kernel_vsx();
 	pagefault_enable();
+	preempt_enable();
 
 	ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
 	return ret;
@@ -99,11 +101,13 @@ static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx,
 	u8 *dst = walk->dst.virt.addr;
 	unsigned int nbytes = walk->nbytes;
 
+	preempt_disable();
 	pagefault_disable();
 	enable_kernel_vsx();
 	aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key);
 	disable_kernel_vsx();
 	pagefault_enable();
+	preempt_enable();
 
 	crypto_xor(keystream, src, nbytes);
 	memcpy(dst, keystream, nbytes);
@@ -132,6 +136,7 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
 		blkcipher_walk_init(&walk, dst, src, nbytes);
 		ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
 		while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
+			preempt_disable();
 			pagefault_disable();
 			enable_kernel_vsx();
 			aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr,
@@ -143,6 +148,7 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
 						    walk.iv);
 			disable_kernel_vsx();
 			pagefault_enable();
+			preempt_enable();
 
 			/* We need to update IV mostly for last bytes/round */
 			inc = (nbytes & AES_BLOCK_MASK) / AES_BLOCK_SIZE;

^ permalink raw reply related

* Re: [PATCH 0/2] Introduce AMD Secure Processor device
From: Greg KH @ 2017-01-20  8:45 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: thomas.lendacky, herbert, arnd, lambert.quentin, gary.hook,
	linux-kernel, Julia.Lawall, weiyongjun1, linux-crypto,
	umgwanakikbuti
In-Reply-To: <0442f536-221d-fcef-3009-4bc07403ccd8@amd.com>

On Thu, Jan 19, 2017 at 02:03:12PM -0600, Brijesh Singh wrote:
> Hi Greg,
> 
> On 01/19/2017 12:21 PM, Greg KH wrote:
> > On Thu, Jan 19, 2017 at 01:07:50PM -0500, Brijesh Singh wrote:
> > > The CCP device (drivers/crypto/ccp/ccp.ko) is part of AMD Secure Processor,
> > > which is not dedicated solely to crypto. The AMD Secure Processor includes
> > > CCP and PSP (Platform Secure Processor) devices.
> > > 
> > > This patch series moves the CCP device driver to the misc directory and
> > > creates a framework that allows functional component of the AMD Secure
> > > Processor to be initialized and handled appropriately.
> > 
> > Why the misc directory?  I don't see the justification here...
> > 
> 
> Since this driver is not solely for crypto purposes and do not fit in any of
> the standard categories hence I thought of moving it into misc directory. I
> am open to other suggestions unless Herbert is ok with leaving it into
> crypto and allowing the addition of the Secure Processor support.
> 
> The patch series allows the CCP driver to support other Secure Processor
> functions, e.g Secure Encrypted Virtualization (SEV) key management. In
> past, I tried to add SEV support into existing CCP driver [1] but we quickly
> learned that CCP driver should be moved outside the crypto directory
> otherwise will end up adding non crypto code into drivers/crypto directory.
> Once this cleanup is accepted then I can work to add SEV support inside the
> CCP driver.
> 
> [1] http://marc.info/?l=linux-kernel&m=147204118426151&w=2

Ok, what type of interface will this driver have with userspace and/or
other parts of the kernel?  Is there a misc char device burried in there
somewhere (I couldn't find it in the big diff sent out), or is this
driver just creating specific apis that other parts of the kernel will
call if available?

I think we need to see more code here, broken up into sane and
reviewable pieces, before we could either say "No don't do that!" or
"sure, let me go merge these!" :)

thanks,

greg k-h

^ permalink raw reply

* [PATCH 6/6] crypto: tcrypt: add ECDSA test modes
From: Nitin Kumbhar @ 2017-01-20 11:36 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar
In-Reply-To: <1484912161-5932-1-git-send-email-nkumbhar@nvidia.com>

Update tcrypt module to include a new ECDSA test
modes. It includes:

tcrypt.ko mode=560 for ECDSA sign/verify validation.
tcrypt.ko mode=561 for ECDSA sign/verify op perf in cycles.
tcrypt.ko mode=561 sec=<seconds> for number of ECDSA sign
  verify ops in given time.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/tcrypt.c |  250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 crypto/tcrypt.h |  122 +++++++++++++++++++++++++++
 2 files changed, 368 insertions(+), 4 deletions(-)

diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index ae22f05d5936..0e4547fe23a8 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -7,6 +7,7 @@
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * Updated RFC4106 AES-GCM testing.
  *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
@@ -25,6 +26,7 @@
 #include <crypto/aead.h>
 #include <crypto/hash.h>
 #include <crypto/skcipher.h>
+#include <crypto/akcipher.h>
 #include <linux/err.h>
 #include <linux/fips.h>
 #include <linux/init.h>
@@ -44,10 +46,12 @@
 #define TVMEMSIZE	4
 
 /*
-* Used by test_cipher_speed()
-*/
-#define ENCRYPT 1
-#define DECRYPT 0
+ * Used by test_cipher_speed()
+ */
+#define DECRYPT		0
+#define ENCRYPT		1
+#define SIGN		2
+#define VERIFY		3
 
 #define MAX_DIGEST_SIZE		64
 
@@ -994,6 +998,223 @@ static void test_cipher_speed(const char *algo, int enc, unsigned int secs,
 				   false);
 }
 
+static inline int do_one_akcipher_op(struct akcipher_request *r, int ret)
+{
+	if (ret == -EINPROGRESS || ret == -EBUSY) {
+		struct tcrypt_result *tr = r->base.data;
+
+		wait_for_completion(&tr->completion);
+		reinit_completion(&tr->completion);
+		ret = tr->err;
+	}
+	return ret;
+}
+
+static int test_akcipher_jiffies(struct akcipher_request *r, int op, int secs)
+{
+	unsigned long start, end;
+	int count, ret;
+
+	for (start = jiffies, end = start + secs * HZ, count = 0;
+	     time_before(jiffies, end); count++) {
+
+		switch (op) {
+		case SIGN:
+			ret = do_one_akcipher_op(r, crypto_akcipher_sign(r));
+			break;
+		case VERIFY:
+			ret = do_one_akcipher_op(r, crypto_akcipher_verify(r));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		if (ret)
+			return ret;
+	}
+
+	pr_info("%d operations in %d seconds\n", count, secs);
+	return 0;
+}
+
+static int test_akcipher_cycles(struct akcipher_request *r, int op)
+{
+	unsigned long cycles = 0;
+	int ret = 0;
+	int i;
+
+	/* Warm-up run. */
+	for (i = 0; i < 4; i++) {
+		switch (op) {
+		case SIGN:
+			ret = do_one_akcipher_op(r, crypto_akcipher_sign(r));
+			break;
+		case VERIFY:
+			ret = do_one_akcipher_op(r, crypto_akcipher_verify(r));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		if (ret)
+			goto out;
+	}
+
+	/* The real thing. */
+	for (i = 0; i < 8; i++) {
+		cycles_t start, end;
+
+		start = get_cycles();
+		switch (op) {
+		case SIGN:
+			ret = do_one_akcipher_op(r, crypto_akcipher_sign(r));
+			break;
+		case VERIFY:
+			ret = do_one_akcipher_op(r, crypto_akcipher_verify(r));
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		end = get_cycles();
+
+		if (ret)
+			goto out;
+
+		cycles += end - start;
+	}
+out:
+	if (ret == 0)
+		pr_info("1 operation in %lu cycles\n", (cycles + 4) / 8);
+
+	return ret;
+}
+
+static void test_akcipher_speed(const char *algo, int op, unsigned int secs,
+				struct akcipher_speed_template *template,
+				unsigned int tcount, u8 *keysize)
+{
+	unsigned int ret, i, j;
+	struct tcrypt_result tresult;
+	const char *key;
+	struct akcipher_request *req;
+	struct crypto_akcipher *tfm;
+	unsigned int m_size = 0;
+	unsigned int nbytes = 0;
+	const char *o;
+
+	if (op == SIGN)
+		o = "sign";
+	else if (op == VERIFY)
+		o = "verify";
+	else
+		return;
+
+	tfm = crypto_alloc_akcipher(algo, 0, 0);
+	if (IS_ERR(tfm)) {
+		pr_err("failed to load transform for %s: %ld\n", algo,
+		       PTR_ERR(tfm));
+		return;
+	}
+
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		pr_err("tcrypt: akcipher: Failed to allocate request for %s\n",
+		       algo);
+		goto out;
+	}
+
+	init_completion(&tresult.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &tresult);
+
+	i = 0;
+	do {
+		struct scatterlist sg[TVMEMSIZE];
+
+		memset(tvmem[0], 0xff, PAGE_SIZE);
+
+		/* set key */
+		key = tvmem[0];
+		for (j = 0; j < tcount; j++) {
+			if (template[j].key_len == *keysize) {
+				key = template[j].key;
+				break;
+			}
+		}
+
+		ret = crypto_akcipher_set_pub_key(tfm, key, *keysize);
+		if (ret) {
+			pr_err("set_pub_key() failed\n");
+			goto out_free_req;
+		}
+
+		ret = crypto_akcipher_set_priv_key(tfm, key, *keysize);
+		if (ret) {
+			pr_err("set_priv_key() failed\n");
+			goto out_free_req;
+		}
+
+		/* set up src/dst buffs */
+		sg_init_table(sg, TVMEMSIZE);
+		if (op == SIGN) {
+			m_size = template[j].m_size;
+			nbytes = template[j].c_size / 3;
+
+			memcpy(tvmem[0], template[j].m, m_size);
+
+			sg_set_buf(&sg[0], tvmem[0], m_size);
+			akcipher_request_set_crypt(req, sg, sg,
+						   m_size, PAGE_SIZE);
+		} else if (op == VERIFY) {
+			m_size = template[j].m_size;
+			nbytes = template[j].c_size / 3;
+
+			memcpy(tvmem[0], template[j].m, m_size);
+			memcpy(tvmem[1], (u8 *)(template[j].c) + nbytes,
+			       nbytes);
+			memcpy(tvmem[2], (u8 *)(template[j].c) + 2 * nbytes,
+			       nbytes);
+
+			sg_set_buf(&sg[0], tvmem[0], m_size);
+			sg_set_buf(&sg[1], tvmem[1], nbytes);
+			sg_set_buf(&sg[2], tvmem[2], nbytes);
+
+			akcipher_request_set_crypt(req, sg, sg,
+						   m_size + 2 * nbytes,
+						   PAGE_SIZE);
+		} else {
+			pr_err("invalid op\n");
+			ret = -EINVAL;
+			goto out_free_req;
+		}
+
+
+		pr_info("\ntesting speed of %s (%s) %s with keysize %d\n",
+			algo, get_driver_name(crypto_akcipher, tfm), o,
+			nbytes * 8);
+
+		if (secs)
+			ret = test_akcipher_jiffies(req, op, secs);
+		else
+			ret = test_akcipher_cycles(req, op);
+
+		if (ret) {
+			pr_err("%s() failed\n", o);
+			break;
+		}
+
+		i++;
+		keysize++;
+
+	} while (*keysize);
+
+out_free_req:
+	akcipher_request_free(req);
+out:
+	crypto_free_akcipher(tfm);
+}
+
 static void test_available(void)
 {
 	char **name = check;
@@ -2035,6 +2256,27 @@ static int do_test(const char *alg, u32 type, u32 mask, int m)
 				   speed_template_8_32);
 		break;
 
+	case 560:
+		ret += tcrypt_test("ecdsa");
+		break;
+
+	case 561:
+#ifndef CONFIG_CRYPTO_FIPS
+		test_akcipher_speed("ecdsa", SIGN, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P192);
+		test_akcipher_speed("ecdsa", VERIFY, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P192);
+#endif
+		test_akcipher_speed("ecdsa", SIGN, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P256);
+		test_akcipher_speed("ecdsa", VERIFY, sec,
+				    ecdsa_speed_template, ECDSA_SPEED_VECTORS,
+				    akc_speed_template_P256);
+		break;
+
 	case 1000:
 		test_available();
 		break;
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index f0bfee1bb293..bd6a4b1cbcbe 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -7,6 +7,7 @@
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * 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
@@ -17,6 +18,16 @@
 #ifndef _CRYPTO_TCRYPT_H
 #define _CRYPTO_TCRYPT_H
 
+struct akcipher_speed_template {
+	unsigned char *key;
+	unsigned char *m;
+	unsigned char *c;
+	unsigned int key_len;
+	unsigned int m_size;
+	unsigned int c_size;
+	bool public_key_vec;
+};
+
 struct cipher_speed_template {
 	const char *key;
 	unsigned int klen;
@@ -48,6 +59,117 @@ struct hash_speed {
 };
 
 /*
+ * ECDSA test vectors.
+ */
+#ifdef CONFIG_CRYPTO_FIPS
+#define ECDSA_SPEED_VECTORS	1
+#else
+#define ECDSA_SPEED_VECTORS	2
+#endif
+
+static struct akcipher_speed_template ecdsa_speed_template[] = {
+	{
+#ifndef CONFIG_CRYPTO_FIPS
+		/* [P-192,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\xd0\xd8\xc0\x99\xe0\xe2\xf7\xf8"
+		"\x87\xe1\x6d\x11\xe1\xcc\x20\x43"
+		"\xaf\xc0\x80\xdb\x47\x72\xfa\xe3"
+		"\x95\xe5\xd1\x34\x7d\x31\xe8\x5a",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x01"
+		/* d */
+		"\x47\x7a\xf2\x5c\x86\xef\x09\x08"
+		"\xa4\x9a\x47\x53\x06\xfc\x61\xbc"
+		"\xa5\x6f\xdd\x7d\x2f\xd2\xed\x24"
+		/* Qx */
+		"\xdc\x14\xd4\xd8\x2e\x1e\x25\x2f"
+		"\x66\x28\xaa\x80\xbc\x38\x6a\x07"
+		"\x8a\x70\xb7\x74\x71\x2d\xf1\x9b"
+		/* Qy */
+		"\x98\x34\x57\x11\xb0\xdc\x3d\xff"
+		"\xfc\xdc\xfe\xa2\x1c\x47\x9e\x4e"
+		"\x82\x08\xfc\x7d\xd0\xc8\x54\x48",
+		.key_len = 74,
+		.c =
+		/* k */
+		"\x3e\x70\xc7\x86\xaf\xaa\x71\x7c"
+		"\x68\x96\xc5\xc3\xec\xb8\x29\xa3"
+		"\xfa\xf7\xa5\x36\xa2\x17\xc8\xa5"
+		/* R */
+		"\xf8\xef\x13\xa8\x86\xe6\x73\x85"
+		"\xdf\x2e\x88\x99\x91\x9b\xc2\x90"
+		"\xea\x1f\x36\xf4\xec\xba\x4a\x35"
+		/* S */
+		"\xc1\x82\x9e\x94\xb7\x58\x2c\x63"
+		"\x8e\xd7\x15\x5a\x38\x47\x30\x9b"
+		"\x1c\x11\x86\xac\x00\x00\xf5\x80",
+		.c_size = 72,
+	}, {
+#endif
+		/* [P-256,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\x56\xec\x33\xa1\xa6\xe7\xc4\xdb"
+		"\x77\x03\x90\x1a\xfb\x2e\x1e\x4e"
+		"\x50\x09\xfe\x04\x72\x89\xc5\xc2"
+		"\x42\x13\x6c\xe3\xb7\xf6\xac\x44",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x02"
+		/* d */
+		"\x64\xb4\x72\xda\x6d\xa5\x54\xca"
+		"\xac\x3e\x4e\x0b\x13\xc8\x44\x5b"
+		"\x1a\x77\xf4\x59\xee\xa8\x4f\x1f"
+		"\x58\x8b\x5f\x71\x3d\x42\x9b\x51"
+		/* Qx */
+		"\x83\xbf\x71\xc2\x46\xff\x59\x3c"
+		"\x2f\xb1\xbf\x4b\xe9\x5d\x56\xd3"
+		"\xcc\x8f\xdb\x48\xa2\xbf\x33\xf0"
+		"\xf4\xc7\x5f\x07\x1c\xe9\xcb\x1c"
+		/* Qy */
+		"\xa9\x4c\x9a\xa8\x5c\xcd\x7c\xdc"
+		"\x78\x4e\x40\xb7\x93\xca\xb7\x6d"
+		"\xe0\x13\x61\x0e\x2c\xdb\x1f\x1a"
+		"\xa2\xf9\x11\x88\xc6\x14\x40\xce",
+		.key_len = 98,
+		.c =
+		/* k */
+		"\xde\x68\x2a\x64\x87\x07\x67\xb9"
+		"\x33\x5d\x4f\x82\x47\x62\x4a\x3b"
+		"\x7f\x3c\xe9\xf9\x45\xf2\x80\xa2"
+		"\x61\x6a\x90\x4b\xb1\xbb\xa1\x94"
+		/* R */
+		"\xac\xc2\xc8\x79\x6f\x5e\xbb\xca"
+		"\x7a\x5a\x55\x6a\x1f\x6b\xfd\x2a"
+		"\xed\x27\x95\x62\xd6\xe3\x43\x88"
+		"\x5b\x79\x14\xb5\x61\x80\xac\xf3"
+		/* S */
+		"\x03\x89\x05\xcc\x2a\xda\xcd\x3c"
+		"\x5a\x17\x6f\xe9\x18\xb2\x97\xef"
+		"\x1c\x37\xf7\x2b\x26\x76\x6c\x78"
+		"\xb2\xa6\x05\xca\x19\x78\xf7\x8b",
+		.c_size = 96,
+	},
+};
+
+/*
+ * AKCipher speed tests
+ */
+#ifndef CONFIG_CRYPTO_FIPS
+static u8 akc_speed_template_P192[] = {74, 0};
+#endif
+static u8 akc_speed_template_P256[] = {98, 0};
+
+/*
  * Cipher speed tests
  */
 static u8 speed_template_8[] = {8, 0};
-- 
1.7.6.3

^ permalink raw reply related

* [PATCH 2/6] crypto: ecc: add vli and ecc ops
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar
In-Reply-To: <1484912161-5932-1-git-send-email-nkumbhar@nvidia.com>

Add functions to copy vli from buffers, to print vli in
big endian format, for vli mod and mod multiplication ops
and ecc point addition.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/ecc.c |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 168 insertions(+), 0 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index a8c10e725138..6ad785c4c12a 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -208,6 +208,42 @@ static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
 		dest[i] = src[i];
 }
 
+/* Copy from vli to buf.
+ * For buffers smaller than vli: copy only LSB nbytes from vli.
+ * For buffers larger than vli : fill up remaining buf with zeroes.
+ */
+void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
+		     const u64 *src_vli, unsigned int ndigits)
+{
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	u8 *vli = (u8 *)src_vli;
+	int i;
+
+	for (i = 0; i < buf_len && i < nbytes; i++)
+		dst_buf[i] = vli[i];
+
+	for (; i < buf_len; i++)
+		dst_buf[i] = 0;
+}
+
+/* Copy from buffer to vli.
+ * For buffers smaller than vli: fill up remaining vli with zeroes.
+ * For buffers larger than vli : copy only LSB nbytes to vli.
+ */
+void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
+		       const u8 *src_buf, unsigned int buf_len)
+{
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	u8 *vli = (u8 *)dst_vli;
+	int i;
+
+	for (i = 0; i < buf_len && i < nbytes; i++)
+		vli[i] = src_buf[i];
+
+	for (; i < nbytes; i++)
+		vli[i] = 0;
+}
+
 /* Returns sign of left - right. */
 static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 {
@@ -440,6 +476,83 @@ static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
 		vli_add(result, result, mod, ndigits);
 }
 
+/* Computes result = input % mod.
+ * Assumes that input < mod, result != mod.
+ */
+void vli_mod(u64 *result, const u64 *input, const u64 *mod,
+	     unsigned int ndigits)
+{
+	if (vli_cmp(input, mod, ndigits) >= 0)
+		vli_sub(result, input, mod, ndigits);
+	else
+		vli_set(result, input, ndigits);
+}
+
+/* Print vli in big-endian format.
+ * The bytes are printed in hex.
+ */
+void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits)
+{
+	int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	int buf_size = 2 * ECC_MAX_DIGIT_BYTES + 1;
+	unsigned char *c, buf[buf_size];
+	int i, j;
+
+	c = (unsigned char *)vli;
+
+	for (i = nbytes - 1, j = 0; i >= 0 && j < buf_size; i--, j += 2)
+		snprintf(&buf[j], 3, "%02x", *(c + i));
+
+	buf[j] = '\0';
+
+	pr_info("%20s(BigEnd)=%s\n", vli_name, buf);
+}
+
+/* Computes result = (left * right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ * Uses:
+ *	(a * b) % m = ((a % m) * (b % m)) % m
+ *	(a * b) % m = (a + a + ... + a) % m = b modular additions of (a % m)
+ */
+void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
+		  const u64 *mod, unsigned int ndigits)
+{
+	u64 t1[ndigits], mm[ndigits];
+	u64 aa[ndigits], bb[ndigits];
+
+	vli_clear(result, ndigits);
+	vli_set(aa, left, ndigits);
+	vli_set(bb, right, ndigits);
+	vli_set(mm, mod, ndigits);
+
+	/* aa = aa % mm */
+	vli_mod(aa, aa, mm, ndigits);
+
+	/* bb = bb % mm */
+	vli_mod(bb, bb, mm, ndigits);
+
+	while (!vli_is_zero(bb, ndigits)) {
+
+		/* if bb is odd i.e. 0th bit set then add
+		 * aa i.e. result = (result + aa) % mm
+		 */
+		if (vli_test_bit(bb, 0))
+			vli_mod_add(result, result, aa, mm, ndigits);
+
+		/* bb = bb / 2 = bb >> 1 */
+		vli_rshift1(bb, ndigits);
+
+		/* aa = (aa * 2) % mm */
+		vli_sub(t1, mm, aa, ndigits);
+		if (vli_cmp(aa, t1, ndigits) == -1)
+			/* if aa < t1 then aa = aa * 2 = aa << 1*/
+			vli_lshift(aa, aa, 1, ndigits);
+		else
+			/* if aa >= t1 then aa = aa - t1 */
+			vli_sub(aa, aa, t1, ndigits);
+	}
+}
+
 /* Computes p_result = p_product % curve_p.
  * See algorithm 5 and 6 from
  * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf
@@ -878,6 +991,61 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
 	vli_set(x1, t7, ndigits);
 }
 
+/* Point addition.
+ * Add 2 distinct points on elliptic curve to get a new point.
+ *
+ * P = (x1,y1)and Q = (x2, y2) then P + Q = (x3,y3) where
+ * x3 = ((y2-y1)/(x2-x1))^2 - x1 - x2
+ * y3 = ((y2-y1)/(x2-x1))(x1-x3) - y1
+ *
+ * Q => P + Q
+ */
+void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+		   unsigned int ndigits)
+{
+	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+	u64 t5[ndigits];
+	u64 t6[ndigits];
+	u64 t7[ndigits];
+
+	/* t6 = x2 - x1 */
+	vli_mod_sub(t6, x2, x1, curve_prime, ndigits);
+	/* t6 = (x2 - x1)^2 = A */
+	vli_mod_square_fast(t6, t6, curve_prime, ndigits);
+	vli_mod_inv(t7, t6, curve_prime, ndigits);
+	/* t5 = x2 - x1 */
+	vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
+	/* t5 = (x2 - x1)^2 = A */
+	vli_mod_square_fast(t5, t5, curve_prime, ndigits);
+	/* t1 = x1*A = B = x1*(x2-x1)^2*/
+	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
+	/* t3 = x2*A = C = x2*(x2-x1)^2*/
+	vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
+	/* t4 = y2 - y1 */
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+	/* t5 = (y2 - y1)^2 = D */
+	vli_mod_square_fast(t5, y2, curve_prime, ndigits);
+
+	/* t5 = D - B = (y2 - y1)^2 - x1*(x2-x1)^2 */
+	vli_mod_sub(t5, t5, x1, curve_prime, ndigits);
+	/* t5 = D - B - C = x3 = (y2 - y1)^2 - x1*(x2-x1)^2 - x2*(x2-x1)^2*/
+	vli_mod_sub(t5, t5, x2, curve_prime, ndigits);
+
+	/* t3 = C - B = x2*(x2-x1)^2 - x1*(x2-x1)^2 */
+	vli_mod_sub(x2, x2, x1, curve_prime, ndigits);
+	/* t2 = y1*(C - B) = y1*(x2*(x2-x1)^2 - x1*(x2-x1)^2)*/
+	vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits);
+	/* t3 = B - x3 = x1*(x2-x1)^2 - x3*/
+	vli_mod_sub(x2, x1, t5, curve_prime, ndigits);
+	/* t4 = (y2 - y1)*(B - x3)  = (y2 - y1)*(x1*(x2-x1)^2 - x3)*/
+	vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits);
+	/* t4 = y3 = ((y2 - y1)*(x1*(x2-x1)^2 - x3)) - y1*/
+	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+
+	vli_mod_mult_fast(t5, t5, t7,  curve_prime, ndigits);
+	vli_set(x2, t5, ndigits);
+}
+
 static void ecc_point_mult(struct ecc_point *result,
 			   const struct ecc_point *point, const u64 *scalar,
 			   u64 *initial_z, u64 *curve_prime,
-- 
1.7.6.3

^ permalink raw reply related

* [PATCH 1/6] crypto: ecc: separate out ecc and ecdh
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar
In-Reply-To: <1484912161-5932-1-git-send-email-nkumbhar@nvidia.com>

Add ECC operations i.e. vli and ecc point ops as a separate
module under CRYPTO_ECC kconfig. This allows other ECC
algorithms like ECDSA & ECIES to reuse these ops even when ECDH
is disabled with CRYPTO_ECDH kconfig.

With these changes, ECDH specific functions are consolidated
as ECDH helper routines and ECC curves are moved to ECC specific
files.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/Kconfig          |    7 +++
 crypto/Makefile         |    5 +-
 crypto/ecc.c            |  133 ++++++++++++++--------------------------------
 crypto/ecc.h            |   45 ++--------------
 crypto/ecc_curve_defs.h |   51 ++++--------------
 crypto/ecc_ecdh.h       |   54 +++++++++++++++++++
 crypto/ecdh.c           |    4 +-
 crypto/ecdh_helper.c    |   94 +++++++++++++++++++++++++++++++++
 include/crypto/ecc.h    |   24 +++++++++
 include/crypto/ecdh.h   |   10 +---
 10 files changed, 243 insertions(+), 184 deletions(-)
 create mode 100644 crypto/ecc_ecdh.h
 create mode 100644 include/crypto/ecc.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 160f08e721cc..e240075d6f46 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -127,9 +127,16 @@ config CRYPTO_DH
 	help
 	  Generic implementation of the Diffie-Hellman algorithm.
 
+config CRYPTO_ECC
+	tristate "ECC functions"
+	help
+	  Implementation of ECC functions
+
+
 config CRYPTO_ECDH
 	tristate "ECDH algorithm"
 	select CRYTPO_KPP
+	select CRYPTO_ECC
 	help
 	  Generic implementation of the ECDH algorithm
 
diff --git a/crypto/Makefile b/crypto/Makefile
index b8f0e3eb0791..827740a47a37 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -33,8 +33,9 @@ obj-$(CONFIG_CRYPTO_KPP2) += kpp.o
 dh_generic-y := dh.o
 dh_generic-y += dh_helper.o
 obj-$(CONFIG_CRYPTO_DH) += dh_generic.o
-ecdh_generic-y := ecc.o
-ecdh_generic-y += ecdh.o
+
+obj-$(CONFIG_CRYPTO_ECC) += ecc.o
+ecdh_generic-y := ecdh.o
 ecdh_generic-y += ecdh_helper.o
 obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
 
diff --git a/crypto/ecc.c b/crypto/ecc.c
index 414c78a9c214..a8c10e725138 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2013, Kenneth MacKay
  * All rights reserved.
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -28,16 +29,54 @@
 #include <linux/slab.h>
 #include <linux/swab.h>
 #include <linux/fips.h>
-#include <crypto/ecdh.h>
 
 #include "ecc.h"
-#include "ecc_curve_defs.h"
 
 typedef struct {
 	u64 m_low;
 	u64 m_high;
 } uint128_t;
 
+/* NIST P-192 */
+static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
+				0x188DA80EB03090F6ull };
+static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull,
+				0x07192B95FFC8DA78ull };
+static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull,
+				0xFFFFFFFFFFFFFFFFull };
+static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull,
+				0xFFFFFFFFFFFFFFFFull };
+static struct ecc_curve nist_p192 = {
+	.name = "nist_192",
+	.g = {
+		.x = nist_p192_g_x,
+		.y = nist_p192_g_y,
+		.ndigits = 3,
+	},
+	.p = nist_p192_p,
+	.n = nist_p192_n
+};
+
+/* NIST P-256 */
+static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,
+				0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull };
+static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull,
+				0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull };
+static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull,
+				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
+static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,
+				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull };
+static struct ecc_curve nist_p256 = {
+	.name = "nist_256",
+	.g = {
+		.x = nist_p256_g_x,
+		.y = nist_p256_g_y,
+		.ndigits = 4,
+	},
+	.p = nist_p256_p,
+	.n = nist_p256_n
+};
+
 static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
 {
 	switch (curve_id) {
@@ -926,93 +965,3 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 
 	return 0;
 }
-
-int ecdh_make_pub_key(unsigned int curve_id, unsigned int ndigits,
-		      const u8 *private_key, unsigned int private_key_len,
-		      u8 *public_key, unsigned int public_key_len)
-{
-	int ret = 0;
-	struct ecc_point *pk;
-	u64 priv[ndigits];
-	unsigned int nbytes;
-	const struct ecc_curve *curve = ecc_get_curve(curve_id);
-
-	if (!private_key || !curve) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
-
-	pk = ecc_alloc_point(ndigits);
-	if (!pk) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
-	if (ecc_point_is_zero(pk)) {
-		ret = -EAGAIN;
-		goto err_free_point;
-	}
-
-	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
-	ecc_swap_digits(pk->x, (u64 *)public_key, ndigits);
-	ecc_swap_digits(pk->y, (u64 *)&public_key[nbytes], ndigits);
-
-err_free_point:
-	ecc_free_point(pk);
-out:
-	return ret;
-}
-
-int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
-		       const u8 *private_key, unsigned int private_key_len,
-		       const u8 *public_key, unsigned int public_key_len,
-		       u8 *secret, unsigned int secret_len)
-{
-	int ret = 0;
-	struct ecc_point *product, *pk;
-	u64 priv[ndigits];
-	u64 rand_z[ndigits];
-	unsigned int nbytes;
-	const struct ecc_curve *curve = ecc_get_curve(curve_id);
-
-	if (!private_key || !public_key || !curve) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
-
-	get_random_bytes(rand_z, nbytes);
-
-	pk = ecc_alloc_point(ndigits);
-	if (!pk) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	product = ecc_alloc_point(ndigits);
-	if (!product) {
-		ret = -ENOMEM;
-		goto err_alloc_product;
-	}
-
-	ecc_swap_digits((const u64 *)public_key, pk->x, ndigits);
-	ecc_swap_digits((const u64 *)&public_key[nbytes], pk->y, ndigits);
-	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
-
-	ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
-
-	ecc_swap_digits(product->x, (u64 *)secret, ndigits);
-
-	if (ecc_point_is_zero(product))
-		ret = -EFAULT;
-
-	ecc_free_point(product);
-err_alloc_product:
-	ecc_free_point(pk);
-out:
-	return ret;
-}
diff --git a/crypto/ecc.h b/crypto/ecc.h
index 663d598c7406..5db82223d485 100644
--- a/crypto/ecc.h
+++ b/crypto/ecc.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2013, Kenneth MacKay
  * All rights reserved.
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -26,9 +27,9 @@
 #ifndef _CRYPTO_ECC_H
 #define _CRYPTO_ECC_H
 
-#define ECC_MAX_DIGITS	4 /* 256 */
+#include <crypto/ecc.h>
 
-#define ECC_DIGITS_TO_BYTES_SHIFT 3
+#include "ecc_curve_defs.h"
 
 /**
  * ecc_is_key_valid() - Validate a given ECDH private key
@@ -42,42 +43,4 @@
  */
 int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 		     const u8 *private_key, unsigned int private_key_len);
-
-/**
- * ecdh_make_pub_key() - Compute an ECC public key
- *
- * @curve_id:		id representing the curve to use
- * @private_key:	pregenerated private key for the given curve
- * @private_key_len:	length of private_key
- * @public_key:		buffer for storing the public key generated
- * @public_key_len:	length of the public_key buffer
- *
- * Returns 0 if the public key was generated successfully, a negative value
- * if an error occurred.
- */
-int ecdh_make_pub_key(const unsigned int curve_id, unsigned int ndigits,
-		      const u8 *private_key, unsigned int private_key_len,
-		      u8 *public_key, unsigned int public_key_len);
-
-/**
- * crypto_ecdh_shared_secret() - Compute a shared secret
- *
- * @curve_id:		id representing the curve to use
- * @private_key:	private key of part A
- * @private_key_len:	length of private_key
- * @public_key:		public key of counterpart B
- * @public_key_len:	length of public_key
- * @secret:		buffer for storing the calculated shared secret
- * @secret_len:		length of the secret buffer
- *
- * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret
- * before using it for symmetric encryption or HMAC.
- *
- * Returns 0 if the shared secret was generated successfully, a negative value
- * if an error occurred.
- */
-int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
-		       const u8 *private_key, unsigned int private_key_len,
-		       const u8 *public_key, unsigned int public_key_len,
-		       u8 *secret, unsigned int secret_len);
-#endif
+#endif /* _CRYPTO_ECC_H */
diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h
index 03ae5f714028..baacf32bca16 100644
--- a/crypto/ecc_curve_defs.h
+++ b/crypto/ecc_curve_defs.h
@@ -1,3 +1,12 @@
+/*
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * 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 _CRYTO_ECC_CURVE_DEFS_H
 #define _CRYTO_ECC_CURVE_DEFS_H
 
@@ -14,44 +23,4 @@ struct ecc_curve {
 	u64 *n;
 };
 
-/* NIST P-192 */
-static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
-				0x188DA80EB03090F6ull };
-static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull,
-				0x07192B95FFC8DA78ull };
-static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull,
-				0xFFFFFFFFFFFFFFFFull };
-static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull,
-				0xFFFFFFFFFFFFFFFFull };
-static struct ecc_curve nist_p192 = {
-	.name = "nist_192",
-	.g = {
-		.x = nist_p192_g_x,
-		.y = nist_p192_g_y,
-		.ndigits = 3,
-	},
-	.p = nist_p192_p,
-	.n = nist_p192_n
-};
-
-/* NIST P-256 */
-static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,
-				0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull };
-static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull,
-				0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull };
-static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull,
-				0x0000000000000000ull, 0xFFFFFFFF00000001ull };
-static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,
-				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull };
-static struct ecc_curve nist_p256 = {
-	.name = "nist_256",
-	.g = {
-		.x = nist_p256_g_x,
-		.y = nist_p256_g_y,
-		.ndigits = 4,
-	},
-	.p = nist_p256_p,
-	.n = nist_p256_n
-};
-
-#endif
+#endif /* _CRYTO_ECC_CURVE_DEFS_H */
diff --git a/crypto/ecc_ecdh.h b/crypto/ecc_ecdh.h
new file mode 100644
index 000000000000..f77b1fe094c9
--- /dev/null
+++ b/crypto/ecc_ecdh.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, Kenneth MacKay. All rights reserved.
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * 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 _CRYPTO_ECC_ECDH_H
+#define _CRYPTO_ECC_ECDH_H
+
+#include "ecc.h"
+
+/**
+ * ecdh_make_pub_key() - Compute an ECC public key
+ *
+ * @curve_id:		id representing the curve to use
+ * @private_key:	pregenerated private key for the given curve
+ * @private_key_len:	length of private_key
+ * @public_key:		buffer for storing the public key generated
+ * @public_key_len:	length of the public_key buffer
+ *
+ * Returns 0 if the public key was generated successfully, a negative value
+ * if an error occurred.
+ */
+int ecdh_make_pub_key(const unsigned int curve_id, unsigned int ndigits,
+		      const u8 *private_key, unsigned int private_key_len,
+		      u8 *public_key, unsigned int public_key_len);
+
+/**
+ * crypto_ecdh_shared_secret() - Compute a shared secret
+ *
+ * @curve_id:		id representing the curve to use
+ * @private_key:	private key of part A
+ * @private_key_len:	length of private_key
+ * @public_key:		public key of counterpart B
+ * @public_key_len:	length of public_key
+ * @secret:		buffer for storing the calculated shared secret
+ * @secret_len:		length of the secret buffer
+ *
+ * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret
+ * before using it for symmetric encryption or HMAC.
+ *
+ * Returns 0 if the shared secret was generated successfully, a negative value
+ * if an error occurred.
+ */
+int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
+		       const u8 *private_key, unsigned int private_key_len,
+		       const u8 *public_key, unsigned int public_key_len,
+		       u8 *secret, unsigned int secret_len);
+
+#endif /* _CRYPTO_ECC_ECDH_H */
diff --git a/crypto/ecdh.c b/crypto/ecdh.c
index 3de289806d67..2b83ff3a4b9a 100644
--- a/crypto/ecdh.c
+++ b/crypto/ecdh.c
@@ -2,6 +2,7 @@
  *
  * Copyright (c) 2016, Intel Corporation
  * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public Licence
@@ -14,7 +15,8 @@
 #include <crypto/kpp.h>
 #include <crypto/ecdh.h>
 #include <linux/scatterlist.h>
-#include "ecc.h"
+
+#include "ecc_ecdh.h"
 
 struct ecdh_ctx {
 	unsigned int curve_id;
diff --git a/crypto/ecdh_helper.c b/crypto/ecdh_helper.c
index 3cd8a2414e60..b3857f3bfcee 100644
--- a/crypto/ecdh_helper.c
+++ b/crypto/ecdh_helper.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2016, Intel Corporation
  * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public Licence
@@ -11,9 +12,12 @@
 #include <linux/export.h>
 #include <linux/err.h>
 #include <linux/string.h>
+#include <linux/random.h>
 #include <crypto/ecdh.h>
 #include <crypto/kpp.h>
 
+#include "ecc_ecdh.h"
+
 #define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 2 * sizeof(short))
 
 static inline u8 *ecdh_pack_data(void *dst, const void *src, size_t sz)
@@ -28,6 +32,96 @@
 	return src + sz;
 }
 
+int ecdh_make_pub_key(unsigned int curve_id, unsigned int ndigits,
+		      const u8 *private_key, unsigned int private_key_len,
+		      u8 *public_key, unsigned int public_key_len)
+{
+	int ret = 0;
+	struct ecc_point *pk;
+	u64 priv[ndigits];
+	unsigned int nbytes;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key || !curve) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
+
+	pk = ecc_alloc_point(ndigits);
+	if (!pk) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
+	if (ecc_point_is_zero(pk)) {
+		ret = -EAGAIN;
+		goto err_free_point;
+	}
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	ecc_swap_digits(pk->x, (u64 *)public_key, ndigits);
+	ecc_swap_digits(pk->y, (u64 *)&public_key[nbytes], ndigits);
+
+err_free_point:
+	ecc_free_point(pk);
+out:
+	return ret;
+}
+
+int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
+		       const u8 *private_key, unsigned int private_key_len,
+		       const u8 *public_key, unsigned int public_key_len,
+		       u8 *secret, unsigned int secret_len)
+{
+	int ret = 0;
+	struct ecc_point *product, *pk;
+	u64 priv[ndigits];
+	u64 rand_z[ndigits];
+	unsigned int nbytes;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+
+	if (!private_key || !public_key || !curve) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	get_random_bytes(rand_z, nbytes);
+
+	pk = ecc_alloc_point(ndigits);
+	if (!pk) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	product = ecc_alloc_point(ndigits);
+	if (!product) {
+		ret = -ENOMEM;
+		goto err_alloc_product;
+	}
+
+	ecc_swap_digits((const u64 *)public_key, pk->x, ndigits);
+	ecc_swap_digits((const u64 *)&public_key[nbytes], pk->y, ndigits);
+	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
+
+	ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
+
+	ecc_swap_digits(product->x, (u64 *)secret, ndigits);
+
+	if (ecc_point_is_zero(product))
+		ret = -EFAULT;
+
+	ecc_free_point(product);
+err_alloc_product:
+	ecc_free_point(pk);
+out:
+	return ret;
+}
+
 int crypto_ecdh_key_len(const struct ecdh *params)
 {
 	return ECDH_KPP_SECRET_MIN_SIZE + params->key_size;
diff --git a/include/crypto/ecc.h b/include/crypto/ecc.h
new file mode 100644
index 000000000000..27957f805fd6
--- /dev/null
+++ b/include/crypto/ecc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * 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 _CRYPTO_ECC_
+#define _CRYPTO_ECC_
+
+/* Curves IDs */
+#define ECC_CURVE_NIST_P192	0x0001
+#define ECC_CURVE_NIST_P256	0x0002
+
+#define ECC_MAX_DIGITS	4 /* 256 */
+
+#define ECC_DIGITS_TO_BYTES_SHIFT 3
+
+#define ECC_MAX_DIGIT_BYTES (ECC_MAX_DIGITS << ECC_DIGITS_TO_BYTES_SHIFT)
+
+#endif /* _CRYPTO_ECC_ */
diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h
index 03a64f62ba7a..c8556305acad 100644
--- a/include/crypto/ecdh.h
+++ b/include/crypto/ecdh.h
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2016, Intel Corporation
  * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation.
  *
  * 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
@@ -13,24 +14,19 @@
 #ifndef _CRYPTO_ECDH_
 #define _CRYPTO_ECDH_
 
+#include <crypto/ecc.h>
+
 /**
  * DOC: ECDH Helper Functions
  *
  * To use ECDH with the KPP cipher API, the following data structure and
  * functions should be used.
  *
- * The ECC curves known to the ECDH implementation are specified in this
- * header file.
- *
  * To use ECDH with KPP, the following functions should be used to operate on
  * an ECDH private key. The packet private key that can be set with
  * the KPP API function call of crypto_kpp_set_secret.
  */
 
-/* Curves IDs */
-#define ECC_CURVE_NIST_P192	0x0001
-#define ECC_CURVE_NIST_P256	0x0002
-
 /**
  * struct ecdh - define an ECDH private key
  *
-- 
1.7.6.3

^ permalink raw reply related

* [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar
In-Reply-To: <1484912161-5932-1-git-send-email-nkumbhar@nvidia.com>

This adds support for ECDSA algorithm. This implementation supports
sign and verify functions for ECDSA algorithm using akcipher. As ECDSA
is a signing algorithm dummy functions are added for encrypt() and
decrypt().

Helper routines for parsing public and private ECC keys for ECDSA are
added as well.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/Kconfig            |    7 +
 crypto/Makefile           |    3 +
 crypto/ecdsa.c            |  331 +++++++++++++++++++++++++++++++++++++++++++++
 crypto/ecdsa_helper.c     |  116 ++++++++++++++++
 include/crypto/akcipher.h |    5 +-
 include/crypto/ecdsa.h    |   29 ++++
 6 files changed, 490 insertions(+), 1 deletions(-)
 create mode 100644 crypto/ecdsa.c
 create mode 100644 crypto/ecdsa_helper.c
 create mode 100644 include/crypto/ecdsa.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index e240075d6f46..1c5c236b3bbc 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -140,6 +140,13 @@ config CRYPTO_ECDH
 	help
 	  Generic implementation of the ECDH algorithm
 
+config CRYPTO_ECDSA
+	tristate "ECDSA algorithm"
+	select CRYPTO_AKCIPHER
+	select CRYPTO_ECC
+	help
+	  Generic implementation of the ECDSA algorithm
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
 	select CRYPTO_MANAGER2
diff --git a/crypto/Makefile b/crypto/Makefile
index 827740a47a37..9c13eb2ade6a 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -38,6 +38,9 @@ obj-$(CONFIG_CRYPTO_ECC) += ecc.o
 ecdh_generic-y := ecdh.o
 ecdh_generic-y += ecdh_helper.o
 obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
+ecdsa_generic-y := ecdsa.o
+ecdsa_generic-y += ecdsa_helper.o
+obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
 
 $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
 $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
new file mode 100644
index 000000000000..d415900af3bd
--- /dev/null
+++ b/crypto/ecdsa.c
@@ -0,0 +1,331 @@
+/*
+ * ECDSA generic algorithm
+ *
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * 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/module.h>
+#include <linux/scatterlist.h>
+#include <linux/random.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/akcipher.h>
+#include <crypto/ecdsa.h>
+
+#include "ecc.h"
+
+struct ecdsa_ctx {
+	unsigned int curve_id;
+	unsigned int ndigits;
+	u64 private_key[ECC_MAX_DIGITS];
+	u64 public_key[2 * ECC_MAX_DIGITS];
+};
+
+static inline struct ecdsa_ctx *ecdsa_get_ctx(struct crypto_akcipher *tfm)
+{
+	return akcipher_tfm_ctx(tfm);
+}
+
+static void ecdsa_parse_msg_hash(struct akcipher_request *req, u64 *msg,
+				 unsigned int ndigits)
+{
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int hash_len, hash_off;
+	unsigned char *hash, *msg_ptr;
+	int i;
+
+	/*
+	 * If hash_len == nbytes:
+	 *	copy nbytes from req
+	 * If hash_len > nbytes:
+	 *	copy left most nbytes from hash ignoring LSBs
+	 * If hash_len < nbytes:
+	 *	copy hash_len from req and zero remaining bytes
+	 *	(nbytes - hash_len)
+	 */
+	hash_len = req->src[0].length;
+	hash_off = hash_len <= nbytes ? 0 : hash_len - nbytes;
+
+	msg_ptr = (unsigned char *)msg;
+	hash = sg_virt(&req->src[0]);
+
+	for (i = hash_off; i < hash_len; i++)
+		*msg_ptr++ = hash[i];
+	for (; i < nbytes; i++)
+		*msg_ptr++ = 0;
+}
+
+int ecdsa_sign(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	unsigned int ndigits = ctx->ndigits;
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int curve_id = ctx->curve_id;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+	struct ecc_point *x1y1 = NULL;
+	u64 z[ndigits], d[ndigits];
+	u64 k[ndigits], k_inv[ndigits];
+	u64 r[ndigits], s[ndigits];
+	u64 dr[ndigits], zdr[ndigits];
+	u8 *r_ptr, *s_ptr;
+
+	if (req->dst_len < 2 * nbytes) {
+		req->dst_len = 2 * nbytes;
+		return -EINVAL;
+	}
+
+	ecdsa_parse_msg_hash(req, z, ndigits);
+
+	/* d */
+	vli_set(d, (const u64 *)ctx->private_key, ndigits);
+
+	/* k */
+#if defined(CONFIG_CRYPTO_MANAGER2)
+	if (req->info) {
+		vli_copy_from_buf(k, ndigits, req->info, nbytes);
+	} else
+#endif
+		get_random_bytes(k, nbytes);
+
+	x1y1 = ecc_alloc_point(ndigits);
+	if (!x1y1)
+		return -ENOMEM;
+
+	/* (x1, y1) = k x G */
+	ecc_point_mult(x1y1, &curve->g, k, NULL, curve->p, ndigits);
+
+	/* r = x1 mod n */
+	vli_mod(r, x1y1->x, curve->n, ndigits);
+
+	/* k^-1 */
+	vli_mod_inv(k_inv, k, curve->n, ndigits);
+
+	/* d . r mod n */
+	vli_mod_mult(dr, d, r, curve->n, ndigits);
+
+	/* z + dr mod n */
+	vli_mod_add(zdr, z, dr, curve->n, ndigits);
+
+	/* k^-1 . ( z + dr) mod n */
+	vli_mod_mult(s, k_inv, zdr, curve->n, ndigits);
+
+	/* write signature (r,s) in dst */
+	r_ptr = sg_virt(req->dst);
+	s_ptr = (u8 *)sg_virt(req->dst) + nbytes;
+
+	vli_copy_to_buf(r_ptr, nbytes, r, ndigits);
+	vli_copy_to_buf(s_ptr, nbytes, s, ndigits);
+
+	req->dst_len = 2 * nbytes;
+
+	ecc_free_point(x1y1);
+	return 0;
+}
+
+int ecdsa_verify(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	unsigned int ndigits = ctx->ndigits;
+	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+	unsigned int curve_id = ctx->curve_id;
+	const struct ecc_curve *curve = ecc_get_curve(curve_id);
+	struct ecc_point *x1y1 = NULL, *x2y2 = NULL, *Q = NULL;
+	u64 r[ndigits], s[ndigits], v[ndigits];
+	u64 z[ndigits], w[ndigits];
+	u64 u1[ndigits], u2[ndigits];
+	u64 x1[ndigits], x2[ndigits];
+	u64 y1[ndigits], y2[ndigits];
+	u64 *ctx_qx, *ctx_qy;
+	int ret;
+
+	x1y1 = ecc_alloc_point(ndigits);
+	x2y2 = ecc_alloc_point(ndigits);
+	Q = ecc_alloc_point(ndigits);
+	if (!x1y1 || !x2y2 || !Q) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ecdsa_parse_msg_hash(req, z, ndigits);
+
+	/* Signature r,s */
+	vli_copy_from_buf(r, ndigits, sg_virt(&req->src[1]), nbytes);
+	vli_copy_from_buf(s, ndigits, sg_virt(&req->src[2]), nbytes);
+
+	/* w = s^-1 mod n */
+	vli_mod_inv(w, s, curve->n, ndigits);
+
+	/* u1 = zw mod n */
+	vli_mod_mult(u1, z, w, curve->n, ndigits);
+
+	/* u2 = rw mod n */
+	vli_mod_mult(u2, r, w, curve->n, ndigits);
+
+	/* u1 . G */
+	ecc_point_mult(x1y1, &curve->g, u1, NULL, curve->p, ndigits);
+
+	/* Q=(Qx,Qy) */
+	ctx_qx = ctx->public_key;
+	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
+	vli_set(Q->x, ctx_qx, ndigits);
+	vli_set(Q->y, ctx_qy, ndigits);
+
+	/* u2 x Q */
+	ecc_point_mult(x2y2, Q, u2, NULL, curve->p, ndigits);
+
+	vli_set(x1, x1y1->x, ndigits);
+	vli_set(y1, x1y1->y, ndigits);
+	vli_set(x2, x2y2->x, ndigits);
+	vli_set(y2, x2y2->y, ndigits);
+
+	/* x1y1 + x2y2 => P + Q; P + Q in x2 y2 */
+	ecc_point_add(x1, y1, x2, y2, curve->p, ndigits);
+
+	/* v = x mod n */
+	vli_mod(v, x2, curve->n, ndigits);
+
+	/* validate signature */
+	ret = vli_cmp(v, r, ndigits) == 0 ? 0 : -EBADMSG;
+ exit:
+	ecc_free_point(x1y1);
+	ecc_free_point(x2y2);
+	ecc_free_point(Q);
+	return ret;
+}
+
+int ecdsa_dummy_enc(struct akcipher_request *req)
+{
+	return -EINVAL;
+}
+
+int ecdsa_dummy_dec(struct akcipher_request *req)
+{
+	return -EINVAL;
+}
+
+int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+		      unsigned int keylen)
+{
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	struct ecdsa params;
+	unsigned int ndigits;
+	unsigned int nbytes;
+	u8 *params_qx, *params_qy;
+	u64 *ctx_qx, *ctx_qy;
+	int ret = 0;
+
+	if (crypto_ecdsa_parse_pub_key(key, keylen, &params))
+		return -EINVAL;
+
+	ndigits = ecdsa_supported_curve(params.curve_id);
+
+	ctx->curve_id = params.curve_id;
+	ctx->ndigits = ndigits;
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	params_qx = params.key;
+	params_qy = params_qx + ECC_MAX_DIGIT_BYTES;
+
+	ctx_qx = ctx->public_key;
+	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
+
+	vli_copy_from_buf(ctx_qx, ndigits, params_qx, nbytes);
+	vli_copy_from_buf(ctx_qy, ndigits, params_qy, nbytes);
+
+	memset(&params, 0, sizeof(params));
+	return ret;
+}
+
+int ecdsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
+		       unsigned int keylen)
+{
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	struct ecdsa params;
+	unsigned int ndigits;
+	unsigned int nbytes;
+
+	if (crypto_ecdsa_parse_priv_key(key, keylen, &params))
+		return -EINVAL;
+
+	ndigits = ecdsa_supported_curve(params.curve_id);
+
+	ctx->curve_id = params.curve_id;
+	ctx->ndigits = ndigits;
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
+			     (const u8 *)params.key, params.key_size) < 0)
+		return -EINVAL;
+
+	vli_copy_from_buf(ctx->private_key, ndigits, params.key, nbytes);
+
+	memset(&params, 0, sizeof(params));
+	return 0;
+}
+
+int ecdsa_max_size(struct crypto_akcipher *tfm)
+{
+	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
+	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	/* For r,s */
+	return 2 * nbytes;
+}
+
+int ecdsa_init_tfm(struct crypto_akcipher *tfm)
+{
+	return 0;
+}
+
+void ecdsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+}
+
+static struct akcipher_alg ecdsa_alg = {
+	.sign		= ecdsa_sign,
+	.verify		= ecdsa_verify,
+	.encrypt	= ecdsa_dummy_enc,
+	.decrypt	= ecdsa_dummy_dec,
+	.set_priv_key	= ecdsa_set_priv_key,
+	.set_pub_key	= ecdsa_set_pub_key,
+	.max_size	= ecdsa_max_size,
+	.init		= ecdsa_init_tfm,
+	.exit		= ecdsa_exit_tfm,
+	.base = {
+		.cra_name	= "ecdsa",
+		.cra_driver_name = "ecdsa-generic",
+		.cra_priority	= 100,
+		.cra_module	= THIS_MODULE,
+		.cra_ctxsize	= sizeof(struct ecdsa_ctx),
+	},
+};
+
+static int ecdsa_init(void)
+{
+	int ret;
+
+	ret = crypto_register_akcipher(&ecdsa_alg);
+	if (ret)
+		pr_err("ecdsa alg register failed. err:%d\n", ret);
+	return ret;
+}
+
+static void ecdsa_exit(void)
+{
+	crypto_unregister_akcipher(&ecdsa_alg);
+}
+
+module_init(ecdsa_init);
+module_exit(ecdsa_exit);
+
+MODULE_ALIAS_CRYPTO("ecdsa");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ECDSA Generic Algorithm");
+MODULE_AUTHOR("NVIDIA Corporation");
diff --git a/crypto/ecdsa_helper.c b/crypto/ecdsa_helper.c
new file mode 100644
index 000000000000..d31eb54431a9
--- /dev/null
+++ b/crypto/ecdsa_helper.c
@@ -0,0 +1,116 @@
+/*
+ * ECDSA helper routines
+ *
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * 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/export.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <crypto/ecdsa.h>
+
+#include "ecc.h"
+
+#define ECDSA_KEY_MIN_SIZE	(1 + 1 + 24) /* ver + cid + n (P-192) */
+
+unsigned int ecdsa_supported_curve(unsigned int curve_id)
+{
+	switch (curve_id) {
+	case ECC_CURVE_NIST_P192: return 3;
+	case ECC_CURVE_NIST_P256: return 4;
+	default: return 0;
+	}
+}
+
+static inline u8 *ecdsa_pack_data(void *dst, const void *src, size_t sz)
+{
+	memcpy(dst, src, sz);
+	return dst + sz;
+}
+
+static inline const u8 *ecdsa_unpack_data(void *dst, const void *src, size_t sz)
+{
+	memcpy(dst, src, sz);
+	return src + sz;
+}
+
+int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
+			       struct ecdsa *params)
+{
+	unsigned char version;
+	unsigned int ndigits;
+	unsigned int nbytes;
+	const u8 *ptr = buf;
+	u8 *qx, *qy;
+
+	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
+	if (version != 1)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
+				sizeof(params->curve_id));
+
+	ndigits = ecdsa_supported_curve(params->curve_id);
+	if (!ndigits)
+		return -EINVAL;
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	/* skip private key */
+	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
+
+	/* copy public key */
+	qx = params->key;
+	qy = qx + ECC_MAX_DIGIT_BYTES;
+
+	ptr = ecdsa_unpack_data(qx, ptr, nbytes);
+	ptr = ecdsa_unpack_data(qy, ptr, nbytes);
+
+	params->key_size = 2 * nbytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_pub_key);
+
+int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
+				struct ecdsa *params)
+{
+	unsigned char version;
+	unsigned int ndigits;
+	unsigned int nbytes;
+	const u8 *ptr = buf;
+
+	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
+	if (version != 1)
+		return -EINVAL;
+
+	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
+				sizeof(params->curve_id));
+
+	ndigits = ecdsa_supported_curve(params->curve_id);
+	if (!ndigits)
+		return -EINVAL;
+
+	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+
+	params->key_size = nbytes;
+
+	/* copy private key */
+	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_priv_key);
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index c37cc59e9bf2..6b34e9043a6f 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2015, Intel Corporation
  * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
  *
  * 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
@@ -27,6 +28,7 @@
  *		result.
  *		In case of error where the dst sgl size was insufficient,
  *		it will be updated to the size required for the operation.
+ * @info:	Any request specific data needed to process the request.
  * @__ctx:	Start of private context data
  */
 struct akcipher_request {
@@ -35,6 +37,7 @@ struct akcipher_request {
 	struct scatterlist *dst;
 	unsigned int src_len;
 	unsigned int dst_len;
+	void *info;
 	void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
@@ -193,7 +196,7 @@ static inline void crypto_free_akcipher(struct crypto_akcipher *tfm)
 {
 	struct akcipher_request *req;
 
-	req = kmalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
+	req = kzalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
 	if (likely(req))
 		akcipher_request_set_tfm(req, tfm);
 
diff --git a/include/crypto/ecdsa.h b/include/crypto/ecdsa.h
new file mode 100644
index 000000000000..c71d21e654b9
--- /dev/null
+++ b/include/crypto/ecdsa.h
@@ -0,0 +1,29 @@
+/*
+ * ECC parameters for ECDSA
+ *
+ * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
+ *
+ * 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 _CRYPTO_ECDSA_
+#define _CRYPTO_ECDSA_
+
+#include <crypto/ecc.h>
+
+struct ecdsa {
+	unsigned char curve_id;
+	unsigned char key[2 * ECC_MAX_DIGIT_BYTES];
+	unsigned short key_size;
+};
+
+unsigned int ecdsa_supported_curve(unsigned int curve_id);
+int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
+			       struct ecdsa *params);
+int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
+				struct ecdsa *params);
+#endif /* _CRYPTO_ECDSA_ */
-- 
1.7.6.3

^ permalink raw reply related

* [PATCH 3/6] crypto: ecc: export vli and ecc ops
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar
In-Reply-To: <1484912161-5932-1-git-send-email-nkumbhar@nvidia.com>

Export vli and ECC related functions so that these can
be used by all ECC algorithm modules like ECDH, ECDSA and ECIES.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/ecc.c |  114 +++++++++++++++++++++++++++++++++++++---------------------
 crypto/ecc.h |   53 +++++++++++++++++++++++++++
 2 files changed, 126 insertions(+), 41 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index 6ad785c4c12a..c6fe1b7b998d 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -77,7 +77,7 @@
 	.n = nist_p256_n
 };
 
-static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
+const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
 {
 	switch (curve_id) {
 	/* In FIPS mode only allow P256 and higher */
@@ -89,6 +89,7 @@
 		return NULL;
 	}
 }
+EXPORT_SYMBOL_GPL(ecc_get_curve);
 
 static u64 *ecc_alloc_digits_space(unsigned int ndigits)
 {
@@ -105,7 +106,7 @@ static void ecc_free_digits_space(u64 *space)
 	kzfree(space);
 }
 
-static struct ecc_point *ecc_alloc_point(unsigned int ndigits)
+struct ecc_point *ecc_alloc_point(unsigned int ndigits)
 {
 	struct ecc_point *p = kmalloc(sizeof(*p), GFP_KERNEL);
 
@@ -130,8 +131,9 @@ static void ecc_free_digits_space(u64 *space)
 	kfree(p);
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(ecc_alloc_point);
 
-static void ecc_free_point(struct ecc_point *p)
+void ecc_free_point(struct ecc_point *p)
 {
 	if (!p)
 		return;
@@ -140,17 +142,19 @@ static void ecc_free_point(struct ecc_point *p)
 	kzfree(p->y);
 	kzfree(p);
 }
+EXPORT_SYMBOL_GPL(ecc_free_point);
 
-static void vli_clear(u64 *vli, unsigned int ndigits)
+void vli_clear(u64 *vli, unsigned int ndigits)
 {
 	int i;
 
 	for (i = 0; i < ndigits; i++)
 		vli[i] = 0;
 }
+EXPORT_SYMBOL_GPL(vli_clear);
 
 /* Returns true if vli == 0, false otherwise. */
-static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
+bool vli_is_zero(const u64 *vli, unsigned int ndigits)
 {
 	int i;
 
@@ -161,15 +165,17 @@ static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(vli_is_zero);
 
 /* Returns nonzero if bit bit of vli is set. */
-static u64 vli_test_bit(const u64 *vli, unsigned int bit)
+u64 vli_test_bit(const u64 *vli, unsigned int bit)
 {
 	return (vli[bit / 64] & ((u64)1 << (bit % 64)));
 }
+EXPORT_SYMBOL_GPL(vli_test_bit);
 
 /* Counts the number of 64-bit "digits" in vli. */
-static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
+unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
 {
 	int i;
 
@@ -181,9 +187,10 @@ static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
 
 	return (i + 1);
 }
+EXPORT_SYMBOL_GPL(vli_num_digits);
 
 /* Counts the number of bits required for vli. */
-static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
+unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
 {
 	unsigned int i, num_digits;
 	u64 digit;
@@ -198,15 +205,17 @@ static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
 
 	return ((num_digits - 1) * 64 + i);
 }
+EXPORT_SYMBOL_GPL(vli_num_bits);
 
 /* Sets dest = src. */
-static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
+void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
 {
 	int i;
 
 	for (i = 0; i < ndigits; i++)
 		dest[i] = src[i];
 }
+EXPORT_SYMBOL_GPL(vli_set);
 
 /* Copy from vli to buf.
  * For buffers smaller than vli: copy only LSB nbytes from vli.
@@ -225,6 +234,7 @@ void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
 	for (; i < buf_len; i++)
 		dst_buf[i] = 0;
 }
+EXPORT_SYMBOL_GPL(vli_copy_to_buf);
 
 /* Copy from buffer to vli.
  * For buffers smaller than vli: fill up remaining vli with zeroes.
@@ -243,9 +253,10 @@ void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
 	for (; i < nbytes; i++)
 		vli[i] = 0;
 }
+EXPORT_SYMBOL_GPL(vli_copy_from_buf);
 
 /* Returns sign of left - right. */
-static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
+int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 {
 	int i;
 
@@ -258,12 +269,13 @@ static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vli_cmp);
 
 /* Computes result = in << c, returning carry. Can modify in place
  * (if result == in). 0 < shift < 64.
  */
-static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
-		      unsigned int ndigits)
+u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
+	       unsigned int ndigits)
 {
 	u64 carry = 0;
 	int i;
@@ -277,9 +289,10 @@ static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
 
 	return carry;
 }
+EXPORT_SYMBOL_GPL(vli_lshift);
 
 /* Computes vli = vli >> 1. */
-static void vli_rshift1(u64 *vli, unsigned int ndigits)
+void vli_rshift1(u64 *vli, unsigned int ndigits)
 {
 	u64 *end = vli;
 	u64 carry = 0;
@@ -292,10 +305,11 @@ static void vli_rshift1(u64 *vli, unsigned int ndigits)
 		carry = temp << 63;
 	}
 }
+EXPORT_SYMBOL_GPL(vli_rshift1);
 
 /* Computes result = left + right, returning carry. Can modify in place. */
-static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
-		   unsigned int ndigits)
+u64 vli_add(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits)
 {
 	u64 carry = 0;
 	int i;
@@ -312,10 +326,11 @@ static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
 
 	return carry;
 }
+EXPORT_SYMBOL_GPL(vli_add);
 
 /* Computes result = left - right, returning borrow. Can modify in place. */
-static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
-		   unsigned int ndigits)
+u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits)
 {
 	u64 borrow = 0;
 	int i;
@@ -332,6 +347,7 @@ static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
 
 	return borrow;
 }
+EXPORT_SYMBOL_GPL(vli_sub);
 
 static uint128_t mul_64_64(u64 left, u64 right)
 {
@@ -368,8 +384,8 @@ static uint128_t add_128_128(uint128_t a, uint128_t b)
 	return result;
 }
 
-static void vli_mult(u64 *result, const u64 *left, const u64 *right,
-		     unsigned int ndigits)
+void vli_mult(u64 *result, const u64 *left, const u64 *right,
+	      unsigned int ndigits)
 {
 	uint128_t r01 = { 0, 0 };
 	u64 r2 = 0;
@@ -403,8 +419,9 @@ static void vli_mult(u64 *result, const u64 *left, const u64 *right,
 
 	result[ndigits * 2 - 1] = r01.m_low;
 }
+EXPORT_SYMBOL_GPL(vli_mult);
 
-static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
+void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
 {
 	uint128_t r01 = { 0, 0 };
 	u64 r2 = 0;
@@ -442,12 +459,13 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
 
 	result[ndigits * 2 - 1] = r01.m_low;
 }
+EXPORT_SYMBOL_GPL(vli_square);
 
 /* Computes result = (left + right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
  */
-static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
-			const u64 *mod, unsigned int ndigits)
+void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits)
 {
 	u64 carry;
 
@@ -459,12 +477,13 @@ static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
 	if (carry || vli_cmp(result, mod, ndigits) >= 0)
 		vli_sub(result, result, mod, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_add);
 
 /* Computes result = (left - right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
  */
-static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
-			const u64 *mod, unsigned int ndigits)
+void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits)
 {
 	u64 borrow = vli_sub(result, left, right, ndigits);
 
@@ -475,6 +494,7 @@ static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
 	if (borrow)
 		vli_add(result, result, mod, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_sub);
 
 /* Computes result = input % mod.
  * Assumes that input < mod, result != mod.
@@ -487,6 +507,7 @@ void vli_mod(u64 *result, const u64 *input, const u64 *mod,
 	else
 		vli_set(result, input, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod);
 
 /* Print vli in big-endian format.
  * The bytes are printed in hex.
@@ -507,6 +528,7 @@ void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits)
 
 	pr_info("%20s(BigEnd)=%s\n", vli_name, buf);
 }
+EXPORT_SYMBOL_GPL(vli_print);
 
 /* Computes result = (left * right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
@@ -552,6 +574,7 @@ void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
 			vli_sub(aa, aa, t1, ndigits);
 	}
 }
+EXPORT_SYMBOL_GPL(vli_mod_mult);
 
 /* Computes p_result = p_product % curve_p.
  * See algorithm 5 and 6 from
@@ -663,8 +686,8 @@ static void vli_mmod_fast_256(u64 *result, const u64 *product,
 /* Computes result = product % curve_prime
  *  from http://www.nsa.gov/ia/_files/nist-routines.pdf
 */
-static bool vli_mmod_fast(u64 *result, u64 *product,
-			  const u64 *curve_prime, unsigned int ndigits)
+bool vli_mmod_fast(u64 *result, u64 *product,
+		   const u64 *curve_prime, unsigned int ndigits)
 {
 	u64 tmp[2 * ndigits];
 
@@ -682,34 +705,37 @@ static bool vli_mmod_fast(u64 *result, u64 *product,
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(vli_mmod_fast);
 
 /* Computes result = (left * right) % curve_prime. */
-static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
-			      const u64 *curve_prime, unsigned int ndigits)
+void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+		       const u64 *curve_prime, unsigned int ndigits)
 {
 	u64 product[2 * ndigits];
 
 	vli_mult(product, left, right, ndigits);
 	vli_mmod_fast(result, product, curve_prime, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_mult_fast);
 
 /* Computes result = left^2 % curve_prime. */
-static void vli_mod_square_fast(u64 *result, const u64 *left,
-				const u64 *curve_prime, unsigned int ndigits)
+void vli_mod_square_fast(u64 *result, const u64 *left,
+			 const u64 *curve_prime, unsigned int ndigits)
 {
 	u64 product[2 * ndigits];
 
 	vli_square(product, left, ndigits);
 	vli_mmod_fast(result, product, curve_prime, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_square_fast);
 
 #define EVEN(vli) (!(vli[0] & 1))
 /* Computes result = (1 / p_input) % mod. All VLIs are the same size.
  * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
  * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
  */
-static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
-			unsigned int ndigits)
+void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+		 unsigned int ndigits)
 {
 	u64 a[ndigits], b[ndigits];
 	u64 u[ndigits], v[ndigits];
@@ -781,23 +807,25 @@ static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
 
 	vli_set(result, u, ndigits);
 }
+EXPORT_SYMBOL_GPL(vli_mod_inv);
 
 /* ------ Point operations ------ */
 
 /* Returns true if p_point is the point at infinity, false otherwise. */
-static bool ecc_point_is_zero(const struct ecc_point *point)
+bool ecc_point_is_zero(const struct ecc_point *point)
 {
 	return (vli_is_zero(point->x, point->ndigits) &&
 		vli_is_zero(point->y, point->ndigits));
 }
+EXPORT_SYMBOL_GPL(ecc_point_is_zero);
 
 /* Point multiplication algorithm using Montgomery's ladder with co-Z
  * coordinates. From http://eprint.iacr.org/2011/338.pdf
  */
 
 /* Double in place */
-static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
-				      u64 *curve_prime, unsigned int ndigits)
+void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
+			       u64 *curve_prime, unsigned int ndigits)
 {
 	/* t1 = x, t2 = y, t3 = z */
 	u64 t4[ndigits];
@@ -857,6 +885,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
 	vli_set(z1, y1, ndigits);
 	vli_set(y1, t4, ndigits);
 }
+EXPORT_SYMBOL_GPL(ecc_point_double_jacobian);
 
 /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
 static void apply_z(u64 *x1, u64 *y1, u64 *z, u64 *curve_prime,
@@ -1045,11 +1074,12 @@ void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
 	vli_mod_mult_fast(t5, t5, t7,  curve_prime, ndigits);
 	vli_set(x2, t5, ndigits);
 }
+EXPORT_SYMBOL_GPL(ecc_point_add);
 
-static void ecc_point_mult(struct ecc_point *result,
-			   const struct ecc_point *point, const u64 *scalar,
-			   u64 *initial_z, u64 *curve_prime,
-			   unsigned int ndigits)
+void ecc_point_mult(struct ecc_point *result,
+		    const struct ecc_point *point, const u64 *scalar,
+		    u64 *initial_z, u64 *curve_prime,
+		    unsigned int ndigits)
 {
 	/* R0 and R1 */
 	u64 rx[2][ndigits];
@@ -1100,15 +1130,16 @@ static void ecc_point_mult(struct ecc_point *result,
 	vli_set(result->x, rx[0], ndigits);
 	vli_set(result->y, ry[0], ndigits);
 }
+EXPORT_SYMBOL_GPL(ecc_point_mult);
 
-static inline void ecc_swap_digits(const u64 *in, u64 *out,
-				   unsigned int ndigits)
+void ecc_swap_digits(const u64 *in, u64 *out, unsigned int ndigits)
 {
 	int i;
 
 	for (i = 0; i < ndigits; i++)
 		out[i] = __swab64(in[ndigits - 1 - i]);
 }
+EXPORT_SYMBOL_GPL(ecc_swap_digits);
 
 int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 		     const u8 *private_key, unsigned int private_key_len)
@@ -1133,3 +1164,4 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(ecc_is_key_valid);
diff --git a/crypto/ecc.h b/crypto/ecc.h
index 5db82223d485..0f907a860d0b 100644
--- a/crypto/ecc.h
+++ b/crypto/ecc.h
@@ -31,6 +31,59 @@
 
 #include "ecc_curve_defs.h"
 
+const struct ecc_curve *ecc_get_curve(unsigned int curve_id);
+struct ecc_point *ecc_alloc_point(unsigned int ndigits);
+void ecc_free_point(struct ecc_point *p);
+
+void vli_clear(u64 *vli, unsigned int ndigits);
+bool vli_is_zero(const u64 *vli, unsigned int ndigits);
+unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits);
+unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits);
+void vli_set(u64 *dest, const u64 *src, unsigned int ndigits);
+void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
+		     const u64 *src_vli, unsigned int ndigits);
+void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
+		       const u8 *src_buf, unsigned int buf_len);
+int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits);
+u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
+	       unsigned int ndigits);
+void vli_rshift1(u64 *vli, unsigned int ndigits);
+u64 vli_add(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits);
+u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+	    unsigned int ndigits);
+void vli_mult(u64 *result, const u64 *left, const u64 *right,
+	      unsigned int ndigits);
+void vli_square(u64 *result, const u64 *left, unsigned int ndigits);
+void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits);
+void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
+		 const u64 *mod, unsigned int ndigits);
+void vli_mod(u64 *result, const u64 *input, const u64 *mod,
+	     unsigned int ndigits);
+void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits);
+void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
+		  const u64 *mod, unsigned int ndigits);
+bool vli_mmod_fast(u64 *result, u64 *product,
+		   const u64 *curve_prime, unsigned int ndigits);
+void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+		       const u64 *curve_prime, unsigned int ndigits);
+void vli_mod_square_fast(u64 *result, const u64 *left,
+			 const u64 *curve_prime, unsigned int ndigits);
+void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+		 unsigned int ndigits);
+
+bool ecc_point_is_zero(const struct ecc_point *point);
+void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
+			       u64 *curve_prime, unsigned int ndigits);
+void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+		   unsigned int ndigits);
+void ecc_point_mult(struct ecc_point *result,
+		    const struct ecc_point *point, const u64 *scalar,
+		    u64 *initial_z, u64 *curve_prime,
+		    unsigned int ndigits);
+void ecc_swap_digits(const u64 *in, u64 *out, unsigned int ndigits);
+
 /**
  * ecc_is_key_valid() - Validate a given ECDH private key
  *
-- 
1.7.6.3

^ permalink raw reply related

* [PATCH 0/6] Add support for ECDSA algorithm
From: Nitin Kumbhar @ 2017-01-20 11:35 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar

Hello,

This patch series adds support for Elliptic Curve Digital Signature
Algorithm (ECDSA). To reuse existing ECC functionality, which is
added as part of ECDH, it separates out ECC and ECDH so that
only ECC functionality is available for ECDSA even when ECDH is in
a disabled state.

Patch #1 restructures ECC and ECDH code such that ECC is not
dependent on ECDH config.

Patches #2 & #3 add vli and ecc functions which are required
for other Elliptic curve algorithms like ECDSA and ECIES.

Patch #4 adds support for ECDSA. This has been validated for P192
and P256 elliptic curves.

Patches #5 and #6 add ECDSA tests to validate ECDSA functionality
and measure ECDSA performance.

Nitin Kumbhar (6):
  crypto: ecc: separate out ecc and ecdh
  crypto: ecc: add vli and ecc ops
  crypto: ecc: export vli and ecc ops
  crypto: ecdsa: add ECDSA SW implementation
  crypto: testmgr: add ECDSA tests
  crypto: tcrypt: add ECDSA test modes

 crypto/Kconfig            |   14 ++
 crypto/Makefile           |    8 +-
 crypto/ecc.c              |  415 ++++++++++++++++++++++++++++-------------
 crypto/ecc.h              |   98 ++++++----
 crypto/ecc_curve_defs.h   |   51 +----
 crypto/ecc_ecdh.h         |   54 ++++++
 crypto/ecdh.c             |    4 +-
 crypto/ecdh_helper.c      |   94 ++++++++++
 crypto/ecdsa.c            |  331 +++++++++++++++++++++++++++++++++
 crypto/ecdsa_helper.c     |  116 ++++++++++++
 crypto/tcrypt.c           |  250 ++++++++++++++++++++++++-
 crypto/tcrypt.h           |  122 ++++++++++++
 crypto/testmgr.c          |  452 ++++++++++++++++++++++++++++++++++++++++++++-
 crypto/testmgr.h          |  140 ++++++++++++++
 include/crypto/akcipher.h |    5 +-
 include/crypto/ecc.h      |   24 +++
 include/crypto/ecdh.h     |   10 +-
 include/crypto/ecdsa.h    |   29 +++
 18 files changed, 1984 insertions(+), 233 deletions(-)
 create mode 100644 crypto/ecc_ecdh.h
 create mode 100644 crypto/ecdsa.c
 create mode 100644 crypto/ecdsa_helper.c
 create mode 100644 include/crypto/ecc.h
 create mode 100644 include/crypto/ecdsa.h

-- 
1.7.6.3

^ permalink raw reply

* [PATCH 5/6] crypto: testmgr: add ECDSA tests
From: Nitin Kumbhar @ 2017-01-20 11:36 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, Nitin Kumbhar
In-Reply-To: <1484912161-5932-1-git-send-email-nkumbhar@nvidia.com>

Update crypto test manager to include NIST ECDSA
test vectors and various ECDSA tests. These include
tests for ECDSA signing, ECDSA sign-verification,
ECDSA signing and verifying generated signatures and
invalidation of incorrect signatures.

Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
---
 crypto/testmgr.c |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 crypto/testmgr.h |  140 +++++++++++++++++
 2 files changed, 589 insertions(+), 3 deletions(-)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 98eb09782db8..a1db28cbc32d 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * Updated RFC4106 AES-GCM testing.
  *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
@@ -2085,6 +2086,436 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
 	return err;
 }
 
+static int do_test_ecdsa_verify(struct crypto_akcipher *tfm,
+			      struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *m_str = NULL;
+	struct scatterlist src_tab[3], dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	u8 *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	r_str = kzalloc(nbytes, GFP_KERNEL);
+	s_str = kzalloc(nbytes, GFP_KERNEL);
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!r_str || !s_str || !m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(r_str, (u8 *)vec->c + nbytes, nbytes);
+	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* Set src and dst buffers */
+	sg_init_table(src_tab, 3);
+	sg_set_buf(&src_tab[0], m_str, vec->m_size);
+	sg_set_buf(&src_tab[1], r_str, nbytes);
+	sg_set_buf(&src_tab[2], s_str, nbytes);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, src_tab, &dst,
+				   vec->m_size + 2 * nbytes, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa verify operation on sig (r,s) */
+	err = wait_async_op(&result, crypto_akcipher_verify(req));
+	if (err) {
+		pr_err("alg: ecdsa: verify(rs) test failed. err %d\n", err);
+		goto error;
+	}
+error:
+	akcipher_request_free(req);
+	kfree(r_str);
+	kfree(s_str);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int do_test_ecdsa_invalid_verify(struct crypto_akcipher *tfm,
+					struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *m_str = NULL;
+	struct scatterlist src_tab[3], dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	u8 *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	r_str = kzalloc(nbytes, GFP_KERNEL);
+	s_str = kzalloc(nbytes, GFP_KERNEL);
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!r_str || !s_str || !m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
+	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* Set src and dst buffers */
+	sg_init_table(src_tab, 3);
+	/* Intentionally set m_size to 8 to have invalid hash */
+	sg_set_buf(&src_tab[0], m_str, 8);
+	sg_set_buf(&src_tab[1], r_str, nbytes);
+	sg_set_buf(&src_tab[2], s_str, nbytes);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, src_tab, &dst,
+				   vec->m_size + 2 * nbytes, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa verify operation on sig (r,s) */
+	err = wait_async_op(&result, crypto_akcipher_verify(req));
+	if (err != -EBADMSG) {
+		pr_err("alg: ecdsa: invalid verify test failed. err %d\n", err);
+		goto error;
+	}
+	err = 0;
+error:
+	akcipher_request_free(req);
+	kfree(r_str);
+	kfree(s_str);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int do_test_ecdsa_sign_verify(struct crypto_akcipher *tfm,
+				     struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *m_str = NULL;
+	struct scatterlist src_tab[3];
+	struct scatterlist src, dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	void *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/* Set private key */
+	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	sg_init_one(&src, m_str, vec->m_size);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, &src, &dst,
+				   vec->m_size, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa sign operation on message digest */
+	err = wait_async_op(&result, crypto_akcipher_sign(req));
+	if (err) {
+		pr_err("alg: ecdsa: sign test failed. err %d\n", err);
+		goto error;
+	}
+
+	/* verify that signature (r,s) is valid */
+	if (req->dst_len != 2 * nbytes) {
+		pr_err("alg: ecdsa: sign test failed. Invalid sig len\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	/* output contains r and s */
+	r_str = outbuf;
+	s_str = (u8 *)outbuf + nbytes;
+
+	/* Set src and dst buffers */
+	sg_init_table(src_tab, 3);
+	sg_set_buf(&src_tab[0], m_str, vec->m_size);
+	sg_set_buf(&src_tab[1], r_str, nbytes);
+	sg_set_buf(&src_tab[2], s_str, nbytes);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, src_tab, &dst,
+				   vec->m_size + 2 * nbytes, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Run ecdsa verify operation on sig (r,s) */
+	err = wait_async_op(&result, crypto_akcipher_verify(req));
+	if (err) {
+		pr_err("alg: ecdsa: verify test failed. err %d\n", err);
+		goto error;
+	}
+error:
+	akcipher_request_free(req);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int do_test_ecdsa_sign(struct crypto_akcipher *tfm,
+			      struct akcipher_testvec *vec)
+{
+	struct akcipher_request *req = NULL;
+	u8 *r_str = NULL, *s_str = NULL;
+	u8 *k_str = NULL, *m_str = NULL;
+	struct scatterlist src, dst;
+	struct tcrypt_result result;
+	unsigned int outbuf_maxlen;
+	void *outbuf = NULL;
+	unsigned int nbytes;
+	int err;
+
+	/* Alloc akcipher request */
+	req = akcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	/* Set private key */
+	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
+	if (err)
+		goto error;
+
+	/*
+	 * vec->c always contains k, R and S in that order. All are
+	 * of same size and are equal to n i.e. the order of
+	 * an elliptic curve.
+	 */
+	nbytes = vec->c_size / 3;
+
+	k_str = kzalloc(nbytes, GFP_KERNEL);
+	r_str = kzalloc(nbytes, GFP_KERNEL);
+	s_str = kzalloc(nbytes, GFP_KERNEL);
+	m_str = kzalloc(vec->m_size, GFP_KERNEL);
+	if (!k_str || !r_str || !s_str || !m_str) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(k_str, (u8 *)vec->c + 0 * nbytes, nbytes);
+	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
+	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
+	memcpy(m_str, vec->m, vec->m_size);
+
+	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
+	if (outbuf_maxlen < 0) {
+		err = outbuf_maxlen;
+		goto error;
+	}
+	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
+	if (!outbuf) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* Set src and dst buffers */
+	sg_init_one(&src, m_str, vec->m_size);
+	sg_init_one(&dst, outbuf, outbuf_maxlen);
+
+	akcipher_request_set_crypt(req, &src, &dst,
+				   vec->m_size, outbuf_maxlen);
+
+	/* Set up result callback */
+	init_completion(&result.completion);
+	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      tcrypt_complete, &result);
+
+	/* Set K in request for signing */
+	req->info = k_str;
+
+	/* Run ecdsa sign operation on message digest */
+	err = wait_async_op(&result, crypto_akcipher_sign(req));
+	if (err) {
+		pr_err("alg: ecdsa: sign(k) test failed. err %d\n", err);
+		goto error;
+	}
+
+	/* verify that signature (r,s) is valid */
+	if (req->dst_len != 2 * nbytes) {
+		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig len\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	if (memcmp(r_str, sg_virt(req->dst), nbytes)) {
+		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(r)\n");
+		err = -EINVAL;
+		goto error;
+	}
+
+	if (memcmp(s_str, (u8 *)sg_virt(req->dst) + nbytes, nbytes)) {
+		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(s)\n");
+		err = -EINVAL;
+		goto error;
+	}
+error:
+	akcipher_request_free(req);
+	kfree(k_str);
+	kfree(r_str);
+	kfree(s_str);
+	kfree(m_str);
+	kfree(outbuf);
+	return err;
+}
+
+static int test_ecdsa_akcipher(struct crypto_akcipher *tfm, const char *alg,
+		       struct akcipher_testvec *vecs, unsigned int tcount)
+{
+	int i, err = 0;
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_verify(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: verify failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_invalid_verify(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: verify(invl) failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_sign_verify(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: sign/verify failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+
+	for (i = 0; i < tcount; i++) {
+		err = do_test_ecdsa_sign(tfm, &vecs[i]);
+		if (!err)
+			continue;
+
+		pr_err("ecdsa: sign failed on vec %d, err=%d\n",
+		       i + 1, err);
+		goto exit;
+	}
+ exit:
+	pr_info("test_ecdsa: %s\n", err ? "FAILED" : "PASSED");
+	return err;
+}
+
 static int test_akcipher_one(struct crypto_akcipher *tfm,
 			     struct akcipher_testvec *vecs)
 {
@@ -2236,9 +2667,17 @@ static int alg_test_akcipher(const struct alg_test_desc *desc,
 		       driver, PTR_ERR(tfm));
 		return PTR_ERR(tfm);
 	}
-	if (desc->suite.akcipher.vecs)
-		err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs,
-				    desc->suite.akcipher.count);
+
+	if (desc->suite.akcipher.vecs) {
+		if (strncmp(desc->alg, "ecdsa", 5) == 0)
+			err = test_ecdsa_akcipher(tfm, desc->alg,
+						  desc->suite.akcipher.vecs,
+						  desc->suite.akcipher.count);
+		else
+			err = test_akcipher(tfm, desc->alg,
+					    desc->suite.akcipher.vecs,
+					    desc->suite.akcipher.count);
+	}
 
 	crypto_free_akcipher(tfm);
 	return err;
@@ -2982,6 +3421,13 @@ static int alg_test_null(const struct alg_test_desc *desc,
 			.kpp = __VECS(ecdh_tv_template)
 		}
 	}, {
+		.alg = "ecdsa",
+		.test = alg_test_akcipher,
+		.fips_allowed = 1,
+		.suite = {
+			.akcipher = __VECS(ecdsa_tv_template)
+		}
+	}, {
 		.alg = "gcm(aes)",
 		.test = alg_test_aead,
 		.fips_allowed = 1,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 64595f067d72..00bb57f4707a 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -5,6 +5,7 @@
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * Copyright (c) 2007 Nokia Siemens Networks
  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ * Copyright (c) 2017 NVIDIA Corporation
  *
  * Updated RFC4106 AES-GCM testing. Some test vectors were taken from
  * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
@@ -755,6 +756,145 @@ struct kpp_testvec dh_tv_template[] = {
 	}
 };
 
+/*
+ * ECDSA NIST test vectors from SigGenComponent.txt file from
+ * 186-3ecdsasiggencomponenttestvectors.zip for P-192 and P-256
+ * elliptic curves.
+ */
+static struct akcipher_testvec ecdsa_tv_template[] = {
+	{
+#ifndef CONFIG_CRYPTO_FIPS
+		/* [P-192,SHA-1] */
+		.m =
+		/* Msg / Hash */
+		"\x92\x5b\xd6\xf4\x1c\x55\xbe\x3e"
+		"\x49\xb7\x16\xe6\x1d\x42\x12\x3f"
+		"\x42\x79\x80\x60",
+		.m_size = 20,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x01"
+		/* d */
+		"\xf3\xd7\x60\xd6\x75\xf2\xcc\xeb"
+		"\xf0\xd2\xfd\xb3\xb9\x41\x3f\xb0"
+		"\xf8\x4f\x37\xd1\xb3\x37\x4f\xe1"
+		/* Qx */
+		"\xe6\x98\xcf\x5b\x2d\x2d\x98\x94"
+		"\x4c\x49\xa2\x80\x6e\x09\x32\x64"
+		"\xe7\xdb\x08\x0b\xa4\x8e\x00\x07"
+		/* Qy */
+		"\x77\x54\xd6\xe4\xf2\xd7\x1b\xc4"
+		"\x98\x6d\xe2\x5d\x21\xba\x36\xa6"
+		"\x4e\x41\x0b\xd0\x81\xb6\xfa\x76",
+		.key_len = 74,
+		.c =
+		/* k */
+		"\x25\x5f\x68\x89\xa2\x31\xbc\x57"
+		"\x4d\x15\xc4\x12\xfb\x56\x45\x68"
+		"\x83\x07\xa1\x43\x70\xbc\x0a\xcb"
+		/* R */
+		"\x3e\xa6\x58\x62\xb4\x98\x96\x1a"
+		"\xf9\xf2\x5b\xec\x55\xf8\xdd\xff"
+		"\x93\xd7\xd0\xbd\x62\xd9\x94\x69"
+		/* S */
+		"\x41\x9f\x1a\x0e\xc0\x5f\xcf\x73"
+		"\x5b\x40\x21\x85\xbc\x02\xab\x44"
+		"\x37\x90\x34\xa2\x65\x64\xba\x02",
+		.c_size = 72,
+	}, {
+		/* [P-192,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\xd0\xd8\xc0\x99\xe0\xe2\xf7\xf8"
+		"\x87\xe1\x6d\x11\xe1\xcc\x20\x43"
+		"\xaf\xc0\x80\xdb\x47\x72\xfa\xe3"
+		"\x95\xe5\xd1\x34\x7d\x31\xe8\x5a",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x01"
+		/* d */
+		"\x47\x7a\xf2\x5c\x86\xef\x09\x08"
+		"\xa4\x9a\x47\x53\x06\xfc\x61\xbc"
+		"\xa5\x6f\xdd\x7d\x2f\xd2\xed\x24"
+		/* Qx */
+		"\xdc\x14\xd4\xd8\x2e\x1e\x25\x2f"
+		"\x66\x28\xaa\x80\xbc\x38\x6a\x07"
+		"\x8a\x70\xb7\x74\x71\x2d\xf1\x9b"
+		/* Qy */
+		"\x98\x34\x57\x11\xb0\xdc\x3d\xff"
+		"\xfc\xdc\xfe\xa2\x1c\x47\x9e\x4e"
+		"\x82\x08\xfc\x7d\xd0\xc8\x54\x48",
+		.key_len = 74,
+		.c =
+		/* k */
+		"\x3e\x70\xc7\x86\xaf\xaa\x71\x7c"
+		"\x68\x96\xc5\xc3\xec\xb8\x29\xa3"
+		"\xfa\xf7\xa5\x36\xa2\x17\xc8\xa5"
+		/* R */
+		"\xf8\xef\x13\xa8\x86\xe6\x73\x85"
+		"\xdf\x2e\x88\x99\x91\x9b\xc2\x90"
+		"\xea\x1f\x36\xf4\xec\xba\x4a\x35"
+		/* S */
+		"\xc1\x82\x9e\x94\xb7\x58\x2c\x63"
+		"\x8e\xd7\x15\x5a\x38\x47\x30\x9b"
+		"\x1c\x11\x86\xac\x00\x00\xf5\x80",
+		.c_size = 72,
+	}, {
+#endif
+		/* [P-256,SHA-256] */
+		.m =
+		/* Msg / Hash */
+		"\x56\xec\x33\xa1\xa6\xe7\xc4\xdb"
+		"\x77\x03\x90\x1a\xfb\x2e\x1e\x4e"
+		"\x50\x09\xfe\x04\x72\x89\xc5\xc2"
+		"\x42\x13\x6c\xe3\xb7\xf6\xac\x44",
+		.m_size = 32,
+		.key =
+		/* version */
+		"\x01"
+		/* curve_id */
+		"\x02"
+		/* d */
+		"\x64\xb4\x72\xda\x6d\xa5\x54\xca"
+		"\xac\x3e\x4e\x0b\x13\xc8\x44\x5b"
+		"\x1a\x77\xf4\x59\xee\xa8\x4f\x1f"
+		"\x58\x8b\x5f\x71\x3d\x42\x9b\x51"
+		/* Qx */
+		"\x83\xbf\x71\xc2\x46\xff\x59\x3c"
+		"\x2f\xb1\xbf\x4b\xe9\x5d\x56\xd3"
+		"\xcc\x8f\xdb\x48\xa2\xbf\x33\xf0"
+		"\xf4\xc7\x5f\x07\x1c\xe9\xcb\x1c"
+		/* Qy */
+		"\xa9\x4c\x9a\xa8\x5c\xcd\x7c\xdc"
+		"\x78\x4e\x40\xb7\x93\xca\xb7\x6d"
+		"\xe0\x13\x61\x0e\x2c\xdb\x1f\x1a"
+		"\xa2\xf9\x11\x88\xc6\x14\x40\xce",
+		.key_len = 98,
+		.c =
+		/* k */
+		"\xde\x68\x2a\x64\x87\x07\x67\xb9"
+		"\x33\x5d\x4f\x82\x47\x62\x4a\x3b"
+		"\x7f\x3c\xe9\xf9\x45\xf2\x80\xa2"
+		"\x61\x6a\x90\x4b\xb1\xbb\xa1\x94"
+		/* R */
+		"\xac\xc2\xc8\x79\x6f\x5e\xbb\xca"
+		"\x7a\x5a\x55\x6a\x1f\x6b\xfd\x2a"
+		"\xed\x27\x95\x62\xd6\xe3\x43\x88"
+		"\x5b\x79\x14\xb5\x61\x80\xac\xf3"
+		/* S */
+		"\x03\x89\x05\xcc\x2a\xda\xcd\x3c"
+		"\x5a\x17\x6f\xe9\x18\xb2\x97\xef"
+		"\x1c\x37\xf7\x2b\x26\x76\x6c\x78"
+		"\xb2\xa6\x05\xca\x19\x78\xf7\x8b",
+		.c_size = 96,
+	},
+};
+
 struct kpp_testvec ecdh_tv_template[] = {
 	{
 #ifndef CONFIG_CRYPTO_FIPS
-- 
1.7.6.3

^ permalink raw reply related

* Re: [PATCH 4/6] crypto: ecdsa: add ECDSA SW implementation
From: Stephan Müller @ 2017-01-20 13:06 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: herbert, davem, linux-crypto
In-Reply-To: <1484912161-5932-5-git-send-email-nkumbhar@nvidia.com>

Am Freitag, 20. Januar 2017, 17:05:59 CET schrieb Nitin Kumbhar:

Hi Nitin,

> This adds support for ECDSA algorithm. This implementation supports
> sign and verify functions for ECDSA algorithm using akcipher. As ECDSA
> is a signing algorithm dummy functions are added for encrypt() and
> decrypt().
> 
> Helper routines for parsing public and private ECC keys for ECDSA are
> added as well.
> 
> Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
> ---
>  crypto/Kconfig            |    7 +
>  crypto/Makefile           |    3 +
>  crypto/ecdsa.c            |  331
> +++++++++++++++++++++++++++++++++++++++++++++ crypto/ecdsa_helper.c     | 
> 116 ++++++++++++++++
>  include/crypto/akcipher.h |    5 +-
>  include/crypto/ecdsa.h    |   29 ++++
>  6 files changed, 490 insertions(+), 1 deletions(-)
>  create mode 100644 crypto/ecdsa.c
>  create mode 100644 crypto/ecdsa_helper.c
>  create mode 100644 include/crypto/ecdsa.h
> 
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index e240075d6f46..1c5c236b3bbc 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -140,6 +140,13 @@ config CRYPTO_ECDH
>  	help
>  	  Generic implementation of the ECDH algorithm
> 
> +config CRYPTO_ECDSA
> +	tristate "ECDSA algorithm"
> +	select CRYPTO_AKCIPHER
> +	select CRYPTO_ECC
> +	help
> +	  Generic implementation of the ECDSA algorithm
> +
>  config CRYPTO_MANAGER
>  	tristate "Cryptographic algorithm manager"
>  	select CRYPTO_MANAGER2
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 827740a47a37..9c13eb2ade6a 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -38,6 +38,9 @@ obj-$(CONFIG_CRYPTO_ECC) += ecc.o
>  ecdh_generic-y := ecdh.o
>  ecdh_generic-y += ecdh_helper.o
>  obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
> +ecdsa_generic-y := ecdsa.o
> +ecdsa_generic-y += ecdsa_helper.o
> +obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
> 
>  $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
>  $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
> diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
> new file mode 100644
> index 000000000000..d415900af3bd
> --- /dev/null
> +++ b/crypto/ecdsa.c
> @@ -0,0 +1,331 @@
> +/*
> + * ECDSA generic algorithm
> + *
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
> + *
> + * 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/module.h>
> +#include <linux/scatterlist.h>
> +#include <linux/random.h>
> +#include <crypto/internal/akcipher.h>
> +#include <crypto/akcipher.h>
> +#include <crypto/ecdsa.h>
> +
> +#include "ecc.h"
> +
> +struct ecdsa_ctx {
> +	unsigned int curve_id;
> +	unsigned int ndigits;
> +	u64 private_key[ECC_MAX_DIGITS];
> +	u64 public_key[2 * ECC_MAX_DIGITS];
> +};
> +
> +static inline struct ecdsa_ctx *ecdsa_get_ctx(struct crypto_akcipher *tfm)
> +{
> +	return akcipher_tfm_ctx(tfm);
> +}
> +
> +static void ecdsa_parse_msg_hash(struct akcipher_request *req, u64 *msg,
> +				 unsigned int ndigits)
> +{
> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +	unsigned int hash_len, hash_off;
> +	unsigned char *hash, *msg_ptr;
> +	int i;
> +
> +	/*
> +	 * If hash_len == nbytes:
> +	 *	copy nbytes from req
> +	 * If hash_len > nbytes:
> +	 *	copy left most nbytes from hash ignoring LSBs
> +	 * If hash_len < nbytes:
> +	 *	copy hash_len from req and zero remaining bytes
> +	 *	(nbytes - hash_len)
> +	 */
> +	hash_len = req->src[0].length;
> +	hash_off = hash_len <= nbytes ? 0 : hash_len - nbytes;
> +
> +	msg_ptr = (unsigned char *)msg;
> +	hash = sg_virt(&req->src[0]);
> +
> +	for (i = hash_off; i < hash_len; i++)
> +		*msg_ptr++ = hash[i];
> +	for (; i < nbytes; i++)
> +		*msg_ptr++ = 0;
> +}
> +
> +int ecdsa_sign(struct akcipher_request *req)
> +{
> +	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	unsigned int ndigits = ctx->ndigits;
> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +	unsigned int curve_id = ctx->curve_id;
> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
> +	struct ecc_point *x1y1 = NULL;
> +	u64 z[ndigits], d[ndigits];
> +	u64 k[ndigits], k_inv[ndigits];
> +	u64 r[ndigits], s[ndigits];
> +	u64 dr[ndigits], zdr[ndigits];
> +	u8 *r_ptr, *s_ptr;
> +
> +	if (req->dst_len < 2 * nbytes) {
> +		req->dst_len = 2 * nbytes;
> +		return -EINVAL;
> +	}
> +
> +	ecdsa_parse_msg_hash(req, z, ndigits);
> +
> +	/* d */
> +	vli_set(d, (const u64 *)ctx->private_key, ndigits);
> +
> +	/* k */
> +#if defined(CONFIG_CRYPTO_MANAGER2)
> +	if (req->info) {
> +		vli_copy_from_buf(k, ndigits, req->info, nbytes);
> +	} else
> +#endif
> +		get_random_bytes(k, nbytes);

Please use crypto_get_default_rng /crypto_rng_get_bytes / 
crypto_put_default_rng here.

> +
> +	x1y1 = ecc_alloc_point(ndigits);
> +	if (!x1y1)
> +		return -ENOMEM;
> +
> +	/* (x1, y1) = k x G */
> +	ecc_point_mult(x1y1, &curve->g, k, NULL, curve->p, ndigits);
> +
> +	/* r = x1 mod n */
> +	vli_mod(r, x1y1->x, curve->n, ndigits);
> +
> +	/* k^-1 */
> +	vli_mod_inv(k_inv, k, curve->n, ndigits);
> +
> +	/* d . r mod n */
> +	vli_mod_mult(dr, d, r, curve->n, ndigits);
> +
> +	/* z + dr mod n */
> +	vli_mod_add(zdr, z, dr, curve->n, ndigits);
> +
> +	/* k^-1 . ( z + dr) mod n */
> +	vli_mod_mult(s, k_inv, zdr, curve->n, ndigits);
> +
> +	/* write signature (r,s) in dst */
> +	r_ptr = sg_virt(req->dst);
> +	s_ptr = (u8 *)sg_virt(req->dst) + nbytes;
> +
> +	vli_copy_to_buf(r_ptr, nbytes, r, ndigits);
> +	vli_copy_to_buf(s_ptr, nbytes, s, ndigits);
> +
> +	req->dst_len = 2 * nbytes;
> +
> +	ecc_free_point(x1y1);
> +	return 0;
> +}
> +
> +int ecdsa_verify(struct akcipher_request *req)
> +{
> +	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	unsigned int ndigits = ctx->ndigits;
> +	unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +	unsigned int curve_id = ctx->curve_id;
> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
> +	struct ecc_point *x1y1 = NULL, *x2y2 = NULL, *Q = NULL;
> +	u64 r[ndigits], s[ndigits], v[ndigits];
> +	u64 z[ndigits], w[ndigits];
> +	u64 u1[ndigits], u2[ndigits];
> +	u64 x1[ndigits], x2[ndigits];
> +	u64 y1[ndigits], y2[ndigits];
> +	u64 *ctx_qx, *ctx_qy;
> +	int ret;
> +
> +	x1y1 = ecc_alloc_point(ndigits);
> +	x2y2 = ecc_alloc_point(ndigits);
> +	Q = ecc_alloc_point(ndigits);
> +	if (!x1y1 || !x2y2 || !Q) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	ecdsa_parse_msg_hash(req, z, ndigits);
> +
> +	/* Signature r,s */
> +	vli_copy_from_buf(r, ndigits, sg_virt(&req->src[1]), nbytes);
> +	vli_copy_from_buf(s, ndigits, sg_virt(&req->src[2]), nbytes);
> +
> +	/* w = s^-1 mod n */
> +	vli_mod_inv(w, s, curve->n, ndigits);
> +
> +	/* u1 = zw mod n */
> +	vli_mod_mult(u1, z, w, curve->n, ndigits);
> +
> +	/* u2 = rw mod n */
> +	vli_mod_mult(u2, r, w, curve->n, ndigits);
> +
> +	/* u1 . G */
> +	ecc_point_mult(x1y1, &curve->g, u1, NULL, curve->p, ndigits);
> +
> +	/* Q=(Qx,Qy) */
> +	ctx_qx = ctx->public_key;
> +	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
> +	vli_set(Q->x, ctx_qx, ndigits);
> +	vli_set(Q->y, ctx_qy, ndigits);
> +
> +	/* u2 x Q */
> +	ecc_point_mult(x2y2, Q, u2, NULL, curve->p, ndigits);
> +
> +	vli_set(x1, x1y1->x, ndigits);
> +	vli_set(y1, x1y1->y, ndigits);
> +	vli_set(x2, x2y2->x, ndigits);
> +	vli_set(y2, x2y2->y, ndigits);
> +
> +	/* x1y1 + x2y2 => P + Q; P + Q in x2 y2 */
> +	ecc_point_add(x1, y1, x2, y2, curve->p, ndigits);
> +
> +	/* v = x mod n */
> +	vli_mod(v, x2, curve->n, ndigits);
> +
> +	/* validate signature */
> +	ret = vli_cmp(v, r, ndigits) == 0 ? 0 : -EBADMSG;
> + exit:
> +	ecc_free_point(x1y1);
> +	ecc_free_point(x2y2);
> +	ecc_free_point(Q);
> +	return ret;
> +}
> +
> +int ecdsa_dummy_enc(struct akcipher_request *req)
> +{
> +	return -EINVAL;
> +}
> +
> +int ecdsa_dummy_dec(struct akcipher_request *req)
> +{
> +	return -EINVAL;
> +}
> +
> +int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
> +		      unsigned int keylen)
> +{
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	struct ecdsa params;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	u8 *params_qx, *params_qy;
> +	u64 *ctx_qx, *ctx_qy;
> +	int ret = 0;
> +
> +	if (crypto_ecdsa_parse_pub_key(key, keylen, &params))
> +		return -EINVAL;
> +
> +	ndigits = ecdsa_supported_curve(params.curve_id);
> +
> +	ctx->curve_id = params.curve_id;
> +	ctx->ndigits = ndigits;
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	params_qx = params.key;
> +	params_qy = params_qx + ECC_MAX_DIGIT_BYTES;
> +
> +	ctx_qx = ctx->public_key;
> +	ctx_qy = ctx_qx + ECC_MAX_DIGITS;
> +
> +	vli_copy_from_buf(ctx_qx, ndigits, params_qx, nbytes);
> +	vli_copy_from_buf(ctx_qy, ndigits, params_qy, nbytes);
> +
> +	memset(&params, 0, sizeof(params));
> +	return ret;

Shouldn't there be a check that the point is on the curve? As I think the same 
issue is applicable to ECDH, I guess a common service function should be used 
that we can also invoke from ECDH.

> +}
> +
> +int ecdsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
> +		       unsigned int keylen)
> +{
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	struct ecdsa params;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +
> +	if (crypto_ecdsa_parse_priv_key(key, keylen, &params))
> +		return -EINVAL;
> +
> +	ndigits = ecdsa_supported_curve(params.curve_id);
> +
> +	ctx->curve_id = params.curve_id;
> +	ctx->ndigits = ndigits;
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
> +			     (const u8 *)params.key, params.key_size) < 0)
> +		return -EINVAL;
> +
> +	vli_copy_from_buf(ctx->private_key, ndigits, params.key, nbytes);
> +
> +	memset(&params, 0, sizeof(params));
> +	return 0;
> +}
> +
> +int ecdsa_max_size(struct crypto_akcipher *tfm)
> +{
> +	struct ecdsa_ctx *ctx = ecdsa_get_ctx(tfm);
> +	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	/* For r,s */
> +	return 2 * nbytes;
> +}
> +
> +int ecdsa_init_tfm(struct crypto_akcipher *tfm)
> +{
> +	return 0;
> +}
> +
> +void ecdsa_exit_tfm(struct crypto_akcipher *tfm)
> +{
> +}
> +
> +static struct akcipher_alg ecdsa_alg = {
> +	.sign		= ecdsa_sign,
> +	.verify		= ecdsa_verify,
> +	.encrypt	= ecdsa_dummy_enc,
> +	.decrypt	= ecdsa_dummy_dec,
> +	.set_priv_key	= ecdsa_set_priv_key,
> +	.set_pub_key	= ecdsa_set_pub_key,
> +	.max_size	= ecdsa_max_size,
> +	.init		= ecdsa_init_tfm,
> +	.exit		= ecdsa_exit_tfm,
> +	.base = {
> +		.cra_name	= "ecdsa",
> +		.cra_driver_name = "ecdsa-generic",
> +		.cra_priority	= 100,
> +		.cra_module	= THIS_MODULE,
> +		.cra_ctxsize	= sizeof(struct ecdsa_ctx),
> +	},
> +};
> +
> +static int ecdsa_init(void)
> +{
> +	int ret;
> +
> +	ret = crypto_register_akcipher(&ecdsa_alg);
> +	if (ret)
> +		pr_err("ecdsa alg register failed. err:%d\n", ret);
> +	return ret;
> +}
> +
> +static void ecdsa_exit(void)
> +{
> +	crypto_unregister_akcipher(&ecdsa_alg);
> +}
> +
> +module_init(ecdsa_init);
> +module_exit(ecdsa_exit);
> +
> +MODULE_ALIAS_CRYPTO("ecdsa");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ECDSA Generic Algorithm");
> +MODULE_AUTHOR("NVIDIA Corporation");
> diff --git a/crypto/ecdsa_helper.c b/crypto/ecdsa_helper.c
> new file mode 100644
> index 000000000000..d31eb54431a9
> --- /dev/null
> +++ b/crypto/ecdsa_helper.c
> @@ -0,0 +1,116 @@
> +/*
> + * ECDSA helper routines
> + *
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
> + *
> + * 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/export.h>
> +#include <linux/err.h>
> +#include <linux/string.h>
> +#include <crypto/ecdsa.h>
> +
> +#include "ecc.h"
> +
> +#define ECDSA_KEY_MIN_SIZE	(1 + 1 + 24) /* ver + cid + n (P-192) */
> +
> +unsigned int ecdsa_supported_curve(unsigned int curve_id)
> +{
> +	switch (curve_id) {
> +	case ECC_CURVE_NIST_P192: return 3;
> +	case ECC_CURVE_NIST_P256: return 4;
> +	default: return 0;
> +	}
> +}

Wouldn't it be better to have a common function with ECDH as this has almost 
the same code in ecdh_supported_curve?

> +
> +static inline u8 *ecdsa_pack_data(void *dst, const void *src, size_t sz)
> +{
> +	memcpy(dst, src, sz);
> +	return dst + sz;
> +}
> +
> +static inline const u8 *ecdsa_unpack_data(void *dst, const void *src,
> size_t sz) +{
> +	memcpy(dst, src, sz);
> +	return src + sz;
> +}
> +
> +int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
> +			       struct ecdsa *params)
> +{
> +	unsigned char version;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	const u8 *ptr = buf;
> +	u8 *qx, *qy;
> +
> +	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
> +	if (version != 1)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
> +				sizeof(params->curve_id));
> +
> +	ndigits = ecdsa_supported_curve(params->curve_id);
> +	if (!ndigits)
> +		return -EINVAL;
> +
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	/* skip private key */
> +	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
> +
> +	/* copy public key */
> +	qx = params->key;
> +	qy = qx + ECC_MAX_DIGIT_BYTES;
> +
> +	ptr = ecdsa_unpack_data(qx, ptr, nbytes);
> +	ptr = ecdsa_unpack_data(qy, ptr, nbytes);
> +
> +	params->key_size = 2 * nbytes;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_pub_key);
> +
> +int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
> +				struct ecdsa *params)
> +{
> +	unsigned char version;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	const u8 *ptr = buf;
> +
> +	if (unlikely(!buf) || len < ECDSA_KEY_MIN_SIZE)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&version, ptr, sizeof(version));
> +	if (version != 1)
> +		return -EINVAL;
> +
> +	ptr = ecdsa_unpack_data(&params->curve_id, ptr,
> +				sizeof(params->curve_id));
> +
> +	ndigits = ecdsa_supported_curve(params->curve_id);
> +	if (!ndigits)
> +		return -EINVAL;
> +
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	params->key_size = nbytes;
> +
> +	/* copy private key */
> +	ptr = ecdsa_unpack_data(&params->key, ptr, nbytes);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(crypto_ecdsa_parse_priv_key);
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index c37cc59e9bf2..6b34e9043a6f 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -3,6 +3,7 @@
>   *
>   * Copyright (c) 2015, Intel Corporation
>   * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
>   *
>   * 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 @@ -27,6 +28,7 @@
>   *		result.
>   *		In case of error where the dst sgl size was insufficient,
>   *		it will be updated to the size required for the operation.
> + * @info:	Any request specific data needed to process the request.
>   * @__ctx:	Start of private context data
>   */
>  struct akcipher_request {
> @@ -35,6 +37,7 @@ struct akcipher_request {
>  	struct scatterlist *dst;
>  	unsigned int src_len;
>  	unsigned int dst_len;
> +	void *info;
>  	void *__ctx[] CRYPTO_MINALIGN_ATTR;
>  };
> 
> @@ -193,7 +196,7 @@ static inline void crypto_free_akcipher(struct
> crypto_akcipher *tfm) {
>  	struct akcipher_request *req;
> 
> -	req = kmalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
> +	req = kzalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp);
>  	if (likely(req))
>  		akcipher_request_set_tfm(req, tfm);
> 
> diff --git a/include/crypto/ecdsa.h b/include/crypto/ecdsa.h
> new file mode 100644
> index 000000000000..c71d21e654b9
> --- /dev/null
> +++ b/include/crypto/ecdsa.h
> @@ -0,0 +1,29 @@
> +/*
> + * ECC parameters for ECDSA
> + *
> + * Copyright (c) 2017, NVIDIA Corporation. All Rights Reserved.
> + *
> + * 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 _CRYPTO_ECDSA_
> +#define _CRYPTO_ECDSA_
> +
> +#include <crypto/ecc.h>
> +
> +struct ecdsa {
> +	unsigned char curve_id;
> +	unsigned char key[2 * ECC_MAX_DIGIT_BYTES];
> +	unsigned short key_size;
> +};
> +
> +unsigned int ecdsa_supported_curve(unsigned int curve_id);
> +int crypto_ecdsa_parse_pub_key(const char *buf, unsigned int len,
> +			       struct ecdsa *params);
> +int crypto_ecdsa_parse_priv_key(const char *buf, unsigned int len,
> +				struct ecdsa *params);
> +#endif /* _CRYPTO_ECDSA_ */

I would like to see soem documentation here similar to the ecdh.h. Especially, 
can you please add documentation which type of point representation you expect 
as input (e.g. affine representation)?

Ciao
Stephan

^ permalink raw reply

* Re: [PATCH 5/6] crypto: testmgr: add ECDSA tests
From: Stephan Müller @ 2017-01-20 13:19 UTC (permalink / raw)
  To: Nitin Kumbhar; +Cc: herbert, davem, linux-crypto
In-Reply-To: <1484912161-5932-6-git-send-email-nkumbhar@nvidia.com>

Am Freitag, 20. Januar 2017, 17:06:00 CET schrieb Nitin Kumbhar:

Hi Nitin,

> Update crypto test manager to include NIST ECDSA
> test vectors and various ECDSA tests. These include
> tests for ECDSA signing, ECDSA sign-verification,
> ECDSA signing and verifying generated signatures and
> invalidation of incorrect signatures.
> 
> Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
> ---
>  crypto/testmgr.c |  452
> +++++++++++++++++++++++++++++++++++++++++++++++++++++- crypto/testmgr.h | 
> 140 +++++++++++++++++
>  2 files changed, 589 insertions(+), 3 deletions(-)
> 
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 98eb09782db8..a1db28cbc32d 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -5,6 +5,7 @@
>   * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
>   * Copyright (c) 2007 Nokia Siemens Networks
>   * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
> + * Copyright (c) 2017 NVIDIA Corporation
>   *
>   * Updated RFC4106 AES-GCM testing.
>   *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
> @@ -2085,6 +2086,436 @@ static int alg_test_kpp(const struct alg_test_desc
> *desc, const char *driver, return err;
>  }
> 
> +static int do_test_ecdsa_verify(struct crypto_akcipher *tfm,
> +			      struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *m_str = NULL;
> +	struct scatterlist src_tab[3], dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	u8 *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	r_str = kzalloc(nbytes, GFP_KERNEL);
> +	s_str = kzalloc(nbytes, GFP_KERNEL);
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!r_str || !s_str || !m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(r_str, (u8 *)vec->c + nbytes, nbytes);
> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Set src and dst buffers */
> +	sg_init_table(src_tab, 3);
> +	sg_set_buf(&src_tab[0], m_str, vec->m_size);
> +	sg_set_buf(&src_tab[1], r_str, nbytes);
> +	sg_set_buf(&src_tab[2], s_str, nbytes);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, src_tab, &dst,
> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa verify operation on sig (r,s) */
> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: verify(rs) test failed. err %d\n", err);
> +		goto error;
> +	}
> +error:
> +	akcipher_request_free(req);
> +	kfree(r_str);
> +	kfree(s_str);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}
> +
> +static int do_test_ecdsa_invalid_verify(struct crypto_akcipher *tfm,
> +					struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *m_str = NULL;
> +	struct scatterlist src_tab[3], dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	u8 *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	r_str = kzalloc(nbytes, GFP_KERNEL);
> +	s_str = kzalloc(nbytes, GFP_KERNEL);
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!r_str || !s_str || !m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Set src and dst buffers */
> +	sg_init_table(src_tab, 3);
> +	/* Intentionally set m_size to 8 to have invalid hash */
> +	sg_set_buf(&src_tab[0], m_str, 8);
> +	sg_set_buf(&src_tab[1], r_str, nbytes);
> +	sg_set_buf(&src_tab[2], s_str, nbytes);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, src_tab, &dst,
> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa verify operation on sig (r,s) */
> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
> +	if (err != -EBADMSG) {
> +		pr_err("alg: ecdsa: invalid verify test failed. err %d\n", err);
> +		goto error;
> +	}
> +	err = 0;
> +error:
> +	akcipher_request_free(req);
> +	kfree(r_str);
> +	kfree(s_str);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}

There seems to be a lot of code duplication between 
do_test_ecdsa_invalid_verify and do_test_ecdsa_verify -- can this be 
eliminated?
> +
> +static int do_test_ecdsa_sign_verify(struct crypto_akcipher *tfm,
> +				     struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *m_str = NULL;
> +	struct scatterlist src_tab[3];
> +	struct scatterlist src, dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	void *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	sg_init_one(&src, m_str, vec->m_size);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, &src, &dst,
> +				   vec->m_size, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa sign operation on message digest */
> +	err = wait_async_op(&result, crypto_akcipher_sign(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: sign test failed. err %d\n", err);
> +		goto error;
> +	}
> +
> +	/* verify that signature (r,s) is valid */
> +	if (req->dst_len != 2 * nbytes) {
> +		pr_err("alg: ecdsa: sign test failed. Invalid sig len\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +
> +	/* output contains r and s */
> +	r_str = outbuf;
> +	s_str = (u8 *)outbuf + nbytes;
> +
> +	/* Set src and dst buffers */
> +	sg_init_table(src_tab, 3);
> +	sg_set_buf(&src_tab[0], m_str, vec->m_size);
> +	sg_set_buf(&src_tab[1], r_str, nbytes);
> +	sg_set_buf(&src_tab[2], s_str, nbytes);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, src_tab, &dst,
> +				   vec->m_size + 2 * nbytes, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Run ecdsa verify operation on sig (r,s) */
> +	err = wait_async_op(&result, crypto_akcipher_verify(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: verify test failed. err %d\n", err);
> +		goto error;
> +	}
> +error:
> +	akcipher_request_free(req);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}
> +
> +static int do_test_ecdsa_sign(struct crypto_akcipher *tfm,
> +			      struct akcipher_testvec *vec)
> +{
> +	struct akcipher_request *req = NULL;
> +	u8 *r_str = NULL, *s_str = NULL;
> +	u8 *k_str = NULL, *m_str = NULL;
> +	struct scatterlist src, dst;
> +	struct tcrypt_result result;
> +	unsigned int outbuf_maxlen;
> +	void *outbuf = NULL;
> +	unsigned int nbytes;
> +	int err;
> +
> +	/* Alloc akcipher request */
> +	req = akcipher_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return -ENOMEM;
> +
> +	/* Set private key */
> +	err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len);
> +	if (err)
> +		goto error;
> +
> +	/*
> +	 * vec->c always contains k, R and S in that order. All are
> +	 * of same size and are equal to n i.e. the order of
> +	 * an elliptic curve.
> +	 */
> +	nbytes = vec->c_size / 3;
> +
> +	k_str = kzalloc(nbytes, GFP_KERNEL);
> +	r_str = kzalloc(nbytes, GFP_KERNEL);
> +	s_str = kzalloc(nbytes, GFP_KERNEL);
> +	m_str = kzalloc(vec->m_size, GFP_KERNEL);
> +	if (!k_str || !r_str || !s_str || !m_str) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +	memcpy(k_str, (u8 *)vec->c + 0 * nbytes, nbytes);
> +	memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes);
> +	memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes);
> +	memcpy(m_str, vec->m, vec->m_size);
> +
> +	outbuf_maxlen = crypto_akcipher_maxsize(tfm);
> +	if (outbuf_maxlen < 0) {
> +		err = outbuf_maxlen;
> +		goto error;
> +	}
> +	outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL);
> +	if (!outbuf) {
> +		err = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Set src and dst buffers */
> +	sg_init_one(&src, m_str, vec->m_size);
> +	sg_init_one(&dst, outbuf, outbuf_maxlen);
> +
> +	akcipher_request_set_crypt(req, &src, &dst,
> +				   vec->m_size, outbuf_maxlen);
> +
> +	/* Set up result callback */
> +	init_completion(&result.completion);
> +	akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				      tcrypt_complete, &result);
> +
> +	/* Set K in request for signing */
> +	req->info = k_str;
> +
> +	/* Run ecdsa sign operation on message digest */
> +	err = wait_async_op(&result, crypto_akcipher_sign(req));
> +	if (err) {
> +		pr_err("alg: ecdsa: sign(k) test failed. err %d\n", err);
> +		goto error;
> +	}
> +
> +	/* verify that signature (r,s) is valid */
> +	if (req->dst_len != 2 * nbytes) {
> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig len\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +
> +	if (memcmp(r_str, sg_virt(req->dst), nbytes)) {
> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(r)\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +
> +	if (memcmp(s_str, (u8 *)sg_virt(req->dst) + nbytes, nbytes)) {
> +		pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(s)\n");
> +		err = -EINVAL;
> +		goto error;
> +	}
> +error:
> +	akcipher_request_free(req);
> +	kfree(k_str);
> +	kfree(r_str);
> +	kfree(s_str);
> +	kfree(m_str);
> +	kfree(outbuf);
> +	return err;
> +}

Same here -- there seem to be a lot of code duplication -- can this be 
reduced?
> +
> +static int test_ecdsa_akcipher(struct crypto_akcipher *tfm, const char
> *alg, +		       struct akcipher_testvec *vecs, unsigned int tcount)
> +{
> +	int i, err = 0;
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_verify(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: verify failed on vec %d, err=%d\n",
> +		       i + 1, err);

All of these pr_err logs here and below should be removed as these errors seem 
to be already logged.

> +		goto exit;
> +	}
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_invalid_verify(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: verify(invl) failed on vec %d, err=%d\n",
> +		       i + 1, err);
> +		goto exit;
> +	}
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_sign_verify(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: sign/verify failed on vec %d, err=%d\n",
> +		       i + 1, err);
> +		goto exit;
> +	}
> +
> +	for (i = 0; i < tcount; i++) {
> +		err = do_test_ecdsa_sign(tfm, &vecs[i]);
> +		if (!err)
> +			continue;
> +
> +		pr_err("ecdsa: sign failed on vec %d, err=%d\n",
> +		       i + 1, err);
> +		goto exit;
> +	}
> + exit:
> +	pr_info("test_ecdsa: %s\n", err ? "FAILED" : "PASSED");

This log message should go away.

> +	return err;
> +}
> +
>  static int test_akcipher_one(struct crypto_akcipher *tfm,
>  			     struct akcipher_testvec *vecs)
>  {
> @@ -2236,9 +2667,17 @@ static int alg_test_akcipher(const struct
> alg_test_desc *desc, driver, PTR_ERR(tfm));
>  		return PTR_ERR(tfm);
>  	}
> -	if (desc->suite.akcipher.vecs)
> -		err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs,
> -				    desc->suite.akcipher.count);
> +
> +	if (desc->suite.akcipher.vecs) {
> +		if (strncmp(desc->alg, "ecdsa", 5) == 0)
> +			err = test_ecdsa_akcipher(tfm, desc->alg,
> +						  desc->suite.akcipher.vecs,
> +						  desc->suite.akcipher.count);
> +		else
> +			err = test_akcipher(tfm, desc->alg,
> +					    desc->suite.akcipher.vecs,
> +					    desc->suite.akcipher.count);
> +	}
> 
>  	crypto_free_akcipher(tfm);
>  	return err;
> @@ -2982,6 +3421,13 @@ static int alg_test_null(const struct alg_test_desc
> *desc, .kpp = __VECS(ecdh_tv_template)
>  		}
>  	}, {
> +		.alg = "ecdsa",
> +		.test = alg_test_akcipher,
> +		.fips_allowed = 1,
> +		.suite = {
> +			.akcipher = __VECS(ecdsa_tv_template)
> +		}
> +	}, {



Ciao
Stephan

^ permalink raw reply

* Re: [PATCH 0/2] Introduce AMD Secure Processor device
From: Brijesh Singh @ 2017-01-20 15:40 UTC (permalink / raw)
  To: Greg KH
  Cc: brijesh.singh, thomas.lendacky, herbert, arnd, lambert.quentin,
	gary.hook, linux-kernel, Julia.Lawall, weiyongjun1, linux-crypto,
	umgwanakikbuti
In-Reply-To: <20170120084530.GA25333@kroah.com>


On 01/20/2017 02:45 AM, Greg KH wrote:
> On Thu, Jan 19, 2017 at 02:03:12PM -0600, Brijesh Singh wrote:
>> Hi Greg,
>>
>> On 01/19/2017 12:21 PM, Greg KH wrote:
>>> On Thu, Jan 19, 2017 at 01:07:50PM -0500, Brijesh Singh wrote:
>>>> The CCP device (drivers/crypto/ccp/ccp.ko) is part of AMD Secure Processor,
>>>> which is not dedicated solely to crypto. The AMD Secure Processor includes
>>>> CCP and PSP (Platform Secure Processor) devices.
>>>>
>>>> This patch series moves the CCP device driver to the misc directory and
>>>> creates a framework that allows functional component of the AMD Secure
>>>> Processor to be initialized and handled appropriately.
>>>
>>> Why the misc directory?  I don't see the justification here...
>>>
>>
>> Since this driver is not solely for crypto purposes and do not fit in any of
>> the standard categories hence I thought of moving it into misc directory. I
>> am open to other suggestions unless Herbert is ok with leaving it into
>> crypto and allowing the addition of the Secure Processor support.
>>
>> The patch series allows the CCP driver to support other Secure Processor
>> functions, e.g Secure Encrypted Virtualization (SEV) key management. In
>> past, I tried to add SEV support into existing CCP driver [1] but we quickly
>> learned that CCP driver should be moved outside the crypto directory
>> otherwise will end up adding non crypto code into drivers/crypto directory.
>> Once this cleanup is accepted then I can work to add SEV support inside the
>> CCP driver.
>>
>> [1] http://marc.info/?l=linux-kernel&m=147204118426151&w=2
>
> Ok, what type of interface will this driver have with userspace and/or
> other parts of the kernel?  Is there a misc char device burried in there
> somewhere (I couldn't find it in the big diff sent out), or is this
> driver just creating specific apis that other parts of the kernel will
> call if available?
>

Eventually, the driver will export functions which will be used by KVM
to encrypt the guest memory and more. Additionally, If SEV device is 
detected then driver will create a misc char device which can be used by 
userspace to import/export certificates etc.

I do realize that we need to get some more context on why this 
refactoring is needed and how it will benefit the SEV device 
integration. I will drop this patch for now, will include it as part of 
next SEV RFC patch series (which provides the complete context with 
examples).

thanks,

~ Brijesh

> I think we need to see more code here, broken up into sane and
> reviewable pieces, before we could either say "No don't do that!" or
> "sure, let me go merge these!" :)
>
> thanks,
>
> greg k-h
>

^ permalink raw reply

* Re: [PATCH 2/2] misc: amd-sp: introduce the AMD Secure Processor device
From: kbuild test robot @ 2017-01-20 16:20 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: kbuild-all, thomas.lendacky, herbert, arnd, gregkh,
	lambert.quentin, gary.hook, linux-kernel, Julia.Lawall,
	weiyongjun1, linux-crypto, umgwanakikbuti, brijesh.singh
In-Reply-To: <148484929157.30852.14374439914599162367.stgit@brijesh-build-machine>

[-- Attachment #1: Type: text/plain, Size: 1152 bytes --]

Hi Brijesh,

[auto build test WARNING on cryptodev/master]
[also build test WARNING on next-20170120]
[cannot apply to char-misc/char-misc-testing v4.10-rc4]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Brijesh-Singh/Introduce-AMD-Secure-Processor-device/20170120-185157
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

warning: (CRYPTO_DEV_CCP_CRYPTO) selects AMD_SP which has unmet direct dependencies ((X86 && PCI || ARM64 && (OF_ADDRESS || ACPI)) && HAS_IOMEM)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 48199 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2] crypto: move CCP device driver to misc
From: kbuild test robot @ 2017-01-20 16:33 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: kbuild-all, thomas.lendacky, herbert, arnd, gregkh,
	lambert.quentin, gary.hook, linux-kernel, Julia.Lawall,
	weiyongjun1, linux-crypto, umgwanakikbuti, brijesh.singh
In-Reply-To: <148484928147.30852.7911360215597694759.stgit@brijesh-build-machine>

[-- Attachment #1: Type: text/plain, Size: 9273 bytes --]

Hi Brijesh,

[auto build test ERROR on cryptodev/master]
[also build test ERROR on next-20170120]
[cannot apply to char-misc/char-misc-testing v4.10-rc4]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Brijesh-Singh/Introduce-AMD-Secure-Processor-device/20170120-185157
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: um-allyesconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=um 

All errors (new ones prefixed by >>):

   arch/um/drivers/built-in.o: In function `vde_open_real':
   (.text+0xc9a1): warning: Using 'getgrnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `vde_open_real':
   (.text+0xc7ec): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `vde_open_real':
   (.text+0xcb05): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametoaddr':
   (.text+0x1d595): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametonetaddr':
   (.text+0x1d635): warning: Using 'getnetbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametoproto':
   (.text+0x1d855): warning: Using 'getprotobyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametoport':
   (.text+0x1d687): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   drivers/built-in.o: In function `ccp_init_dm_workarea':
>> drivers/misc/amd-sp/ccp-ops.c:141: undefined reference to `dma_pool_alloc'
   drivers/built-in.o: In function `ccp_init_dm_workarea':
   include/linux/dma-mapping.h:190: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_sg_free':
   include/linux/dma-mapping.h:242: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_dm_free':
>> drivers/misc/amd-sp/ccp-ops.c:112: undefined reference to `dma_pool_free'
   drivers/built-in.o: In function `ccp_dm_free':
   include/linux/dma-mapping.h:207: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_init_data':
   include/linux/dma-mapping.h:227: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_destroy':
>> drivers/misc/amd-sp/ccp-dev-v3.c:501: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `ccp_init':
>> drivers/misc/amd-sp/ccp-dev-v3.c:337: undefined reference to `dma_pool_create'
   drivers/misc/amd-sp/ccp-dev-v3.c:456: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `ccp5_destroy':
   include/linux/dma-mapping.h:484: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:490: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp5_init':
>> drivers/misc/amd-sp/ccp-dev-v5.c:676: undefined reference to `dma_pool_create'
   drivers/built-in.o: In function `ccp5_init':
   include/linux/dma-mapping.h:463: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp5_init':
>> drivers/misc/amd-sp/ccp-dev-v5.c:861: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `ccp_platform_probe':
   drivers/misc/amd-sp/ccp-platform.c:148: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `ccp_platform_probe':
   include/linux/dma-mapping.h:555: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_cmd_callback':
   drivers/misc/amd-sp/ccp-dmaengine.c:204: undefined reference to `dma_run_dependencies'
   drivers/built-in.o: In function `ccp_alloc_dma_desc':
   drivers/misc/amd-sp/ccp-dmaengine.c:306: undefined reference to `dma_async_tx_descriptor_init'
   drivers/built-in.o: In function `ccp_dmaengine_register':
   drivers/misc/amd-sp/ccp-dmaengine.c:705: undefined reference to `dma_async_device_register'
   drivers/built-in.o: In function `ccp_dmaengine_unregister':
   drivers/misc/amd-sp/ccp-dmaengine.c:724: undefined reference to `dma_async_device_unregister'
   drivers/built-in.o: In function `img_ascii_lcd_probe':
   drivers/auxdisplay/img-ascii-lcd.c:384: undefined reference to `devm_ioremap_resource'
   collect2: error: ld returned 1 exit status

vim +141 drivers/misc/amd-sp/ccp-ops.c

63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  106  }
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  107  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  108  static void ccp_dm_free(struct ccp_dm_workarea *wa)
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  109  {
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  110  	if (wa->length <= CCP_DMAPOOL_MAX_SIZE) {
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  111  		if (wa->address)
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12 @112  			dma_pool_free(wa->dma_pool, wa->address,
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  113  				      wa->dma.address);
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  114  	} else {
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  115  		if (wa->dma.address)
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  116  			dma_unmap_single(wa->dev, wa->dma.address, wa->length,
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  117  					 wa->dma.dir);
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  118  		kfree(wa->address);
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  119  	}
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  120  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  121  	wa->address = NULL;
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  122  	wa->dma.address = 0;
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  123  }
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  124  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  125  static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  126  				struct ccp_cmd_queue *cmd_q,
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  127  				unsigned int len,
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  128  				enum dma_data_direction dir)
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  129  {
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  130  	memset(wa, 0, sizeof(*wa));
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  131  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  132  	if (!len)
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  133  		return 0;
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  134  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  135  	wa->dev = cmd_q->ccp->dev;
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  136  	wa->length = len;
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  137  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  138  	if (len <= CCP_DMAPOOL_MAX_SIZE) {
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  139  		wa->dma_pool = cmd_q->dma_pool;
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  140  
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12 @141  		wa->address = dma_pool_alloc(wa->dma_pool, GFP_KERNEL,
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  142  					     &wa->dma.address);
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  143  		if (!wa->address)
63b94509 drivers/crypto/ccp/ccp-ops.c Tom Lendacky 2013-11-12  144  			return -ENOMEM;

:::::: The code at line 141 was first introduced by commit
:::::: 63b945091a070d8d4275dc0f7699ba22cd5f9435 crypto: ccp - CCP device driver and interface support

:::::: TO: Tom Lendacky <thomas.lendacky@amd.com>
:::::: CC: Herbert Xu <herbert@gondor.apana.org.au>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 18805 bytes --]

^ permalink raw reply

* Re: [PATCH 00/13] crypto: copy AAD during encrypt for AEAD ciphers
From: Cyrille Pitchen @ 2017-01-20 17:07 UTC (permalink / raw)
  To: Herbert Xu, Stephan Müller; +Cc: linux-crypto
In-Reply-To: <20170113113906.GA24096@gondor.apana.org.au>

Hi all,

Le 13/01/2017 à 12:39, Herbert Xu a écrit :
> On Fri, Jan 13, 2017 at 12:36:56PM +0100, Stephan Müller wrote:
>>
>> I thought I understood that you would not want to see it in any 
>> implementation. But, ok, if you want to leave it.
> 
> If you remove it from authenc then authenc will be broken.
> 

Hence if the copy of the associated data is needed in the crypto/authenc.c
driver, then I should also keep this copy in the drivers/crypto/atmel-aes.c
for authenc(hmac(shaX),cbc-aes) algorithms [1], shouldn't I?

If so, should I keep the current not optimized implementation of
atmel_aes_authenc_copy_assoc() or try to use the code extracted by Stephan
from crypto/authenc.c using the null cipher as proposed in this thread?

As said earlier in this thread, copying the associated data is not a so big
deal when compared to the main crypto processing.

For instance, with IPSec ESP with AES in CBC mode, the associated data
layout should be:
Security Parameters Index (SPI): 4 bytes
Sequence Number: 4 bytes
AES IV: 16 bytes

So it's only a 24 byte copy.

I've taken Stephan's other comments into account from his review of the
atmel-authenc driver so I'm preparing a new series but I don't know what to
do for the associated data copy.

Please let me know what you recommend, thanks!

Best regards,

Cyrille


[1] https://lkml.org/lkml/2016/12/22/306

^ permalink raw reply

* Re: [PATCH 0/2] Introduce AMD Secure Processor device
From: Greg KH @ 2017-01-20 17:39 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: thomas.lendacky, herbert, arnd, lambert.quentin, gary.hook,
	linux-kernel, Julia.Lawall, weiyongjun1, linux-crypto,
	umgwanakikbuti
In-Reply-To: <129bc948-6836-bf0f-832e-525f0805c549@amd.com>

On Fri, Jan 20, 2017 at 09:40:49AM -0600, Brijesh Singh wrote:
> 
> On 01/20/2017 02:45 AM, Greg KH wrote:
> > On Thu, Jan 19, 2017 at 02:03:12PM -0600, Brijesh Singh wrote:
> > > Hi Greg,
> > > 
> > > On 01/19/2017 12:21 PM, Greg KH wrote:
> > > > On Thu, Jan 19, 2017 at 01:07:50PM -0500, Brijesh Singh wrote:
> > > > > The CCP device (drivers/crypto/ccp/ccp.ko) is part of AMD Secure Processor,
> > > > > which is not dedicated solely to crypto. The AMD Secure Processor includes
> > > > > CCP and PSP (Platform Secure Processor) devices.
> > > > > 
> > > > > This patch series moves the CCP device driver to the misc directory and
> > > > > creates a framework that allows functional component of the AMD Secure
> > > > > Processor to be initialized and handled appropriately.
> > > > 
> > > > Why the misc directory?  I don't see the justification here...
> > > > 
> > > 
> > > Since this driver is not solely for crypto purposes and do not fit in any of
> > > the standard categories hence I thought of moving it into misc directory. I
> > > am open to other suggestions unless Herbert is ok with leaving it into
> > > crypto and allowing the addition of the Secure Processor support.
> > > 
> > > The patch series allows the CCP driver to support other Secure Processor
> > > functions, e.g Secure Encrypted Virtualization (SEV) key management. In
> > > past, I tried to add SEV support into existing CCP driver [1] but we quickly
> > > learned that CCP driver should be moved outside the crypto directory
> > > otherwise will end up adding non crypto code into drivers/crypto directory.
> > > Once this cleanup is accepted then I can work to add SEV support inside the
> > > CCP driver.
> > > 
> > > [1] http://marc.info/?l=linux-kernel&m=147204118426151&w=2
> > 
> > Ok, what type of interface will this driver have with userspace and/or
> > other parts of the kernel?  Is there a misc char device burried in there
> > somewhere (I couldn't find it in the big diff sent out), or is this
> > driver just creating specific apis that other parts of the kernel will
> > call if available?
> > 
> 
> Eventually, the driver will export functions which will be used by KVM
> to encrypt the guest memory and more. Additionally, If SEV device is
> detected then driver will create a misc char device which can be used by
> userspace to import/export certificates etc.

Why create a new api for certificates, why not just use the existing
kernel key handling for it?

Having a random char device for something like this is going to be rough
to approve, I'll wait for the patches before I start objecting really
hard :)

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH 2/2] misc: amd-sp: introduce the AMD Secure Processor device
From: kbuild test robot @ 2017-01-20 19:51 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: kbuild-all, thomas.lendacky, herbert, arnd, gregkh,
	lambert.quentin, gary.hook, linux-kernel, Julia.Lawall,
	weiyongjun1, linux-crypto, umgwanakikbuti, brijesh.singh
In-Reply-To: <148484929157.30852.14374439914599162367.stgit@brijesh-build-machine>

[-- Attachment #1: Type: text/plain, Size: 10497 bytes --]

Hi Brijesh,

[auto build test ERROR on cryptodev/master]
[also build test ERROR on next-20170120]
[cannot apply to char-misc/char-misc-testing v4.10-rc4]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Brijesh-Singh/Introduce-AMD-Secure-Processor-device/20170120-185157
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: um-allyesconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=um 

All error/warnings (new ones prefixed by >>):

warning: (AMD_CCP && SND_SOC_SH4_SIU) selects DMADEVICES which has unmet direct dependencies (HAS_DMA)
   arch/um/drivers/built-in.o: In function `vde_open_real':
   (.text+0xc9a1): warning: Using 'getgrnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `vde_open_real':
   (.text+0xc7ec): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `vde_open_real':
   (.text+0xcb05): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametoaddr':
   (.text+0x1d595): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametonetaddr':
   (.text+0x1d635): warning: Using 'getnetbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametoproto':
   (.text+0x1d855): warning: Using 'getprotobyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   arch/um/drivers/built-in.o: In function `pcap_nametoport':
   (.text+0x1d687): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
   crypto/built-in.o: In function `async_memcpy':
   include/linux/dma-mapping.h:257: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:257: undefined reference to `bad_dma_ops'
   crypto/built-in.o: In function `async_xor':
   include/linux/dma-mapping.h:257: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:257: undefined reference to `bad_dma_ops'
   crypto/built-in.o: In function `async_xor_val':
   include/linux/dma-mapping.h:257: undefined reference to `bad_dma_ops'
   crypto/built-in.o:include/linux/dma-mapping.h:257: more undefined references to `bad_dma_ops' follow
   drivers/built-in.o: In function `dwc_desc_get':
>> include/linux/dmapool.h:30: undefined reference to `dma_pool_alloc'
   drivers/built-in.o: In function `dwc_desc_put':
>> drivers/dma/dw/core.c:137: undefined reference to `dma_pool_free'
   drivers/dma/dw/core.c:133: undefined reference to `dma_pool_free'
   drivers/built-in.o: In function `dw_dma_probe':
>> drivers/dma/dw/core.c:1508: undefined reference to `dmam_pool_create'
   drivers/built-in.o: In function `dw_probe':
>> drivers/dma/dw/platform.c:192: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `dw_probe':
   include/linux/dma-mapping.h:555: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `fsl_edma_free_desc':
>> drivers/dma/fsl-edma.c:288: undefined reference to `dma_pool_free'
   drivers/built-in.o: In function `fsl_edma_alloc_desc':
>> drivers/dma/fsl-edma.c:525: undefined reference to `dma_pool_alloc'
   drivers/dma/fsl-edma.c:525: undefined reference to `dma_pool_free'
   drivers/built-in.o: In function `fsl_edma_free_chan_resources':
>> drivers/dma/fsl-edma.c:808: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `fsl_edma_alloc_chan_resources':
>> drivers/dma/fsl-edma.c:788: undefined reference to `dma_pool_create'
   drivers/built-in.o: In function `fsl_edma_probe':
>> drivers/dma/fsl-edma.c:898: undefined reference to `devm_ioremap_resource'
   drivers/dma/fsl-edma.c:906: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `idma64_desc_free':
>> drivers/dma/idma64.c:214: undefined reference to `dma_pool_free'
   drivers/built-in.o: In function `idma64_free_chan_resources':
>> drivers/dma/idma64.c:520: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `idma64_alloc_chan_resources':
>> drivers/dma/idma64.c:504: undefined reference to `dma_pool_create'
   drivers/built-in.o: In function `idma64_platform_probe':
>> drivers/dma/idma64.c:644: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `idma64_platform_probe':
   include/linux/dma-mapping.h:555: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `idma64_prep_slave_sg':
>> drivers/dma/idma64.c:315: undefined reference to `dma_pool_alloc'
   drivers/built-in.o: In function `hidma_mgmt_probe':
>> drivers/dma/qcom/hidma_mgmt.c:165: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `hidma_ll_init':
>> drivers/dma/qcom/hidma_ll.c:749: undefined reference to `dmam_alloc_coherent'
   drivers/built-in.o: In function `hidma_probe':
>> drivers/dma/qcom/hidma.c:735: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `hidma_probe':
   include/linux/dma-mapping.h:555: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:542: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   drivers/built-in.o:include/linux/dma-mapping.h:542: more undefined references to `bad_dma_ops' follow
   drivers/built-in.o: In function `sp_platform_probe':
>> drivers/misc/amd-sp/sp-platform.c:133: undefined reference to `devm_ioremap_resource'
   drivers/built-in.o: In function `sp_platform_probe':
   include/linux/dma-mapping.h:555: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:555: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:544: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_dev_suspend':
>> include/linux/spinlock.h:362: undefined reference to `ccp_queues_suspended'
   drivers/built-in.o: In function `ccp_destroy':
   drivers/misc/amd-sp/ccp-dev-v3.c:534: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `ccp_init':
   drivers/misc/amd-sp/ccp-dev-v3.c:370: undefined reference to `dma_pool_create'
   drivers/misc/amd-sp/ccp-dev-v3.c:489: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `ccp5_destroy':
   include/linux/dma-mapping.h:484: undefined reference to `bad_dma_ops'
   include/linux/dma-mapping.h:490: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp5_init':
   drivers/misc/amd-sp/ccp-dev-v5.c:707: undefined reference to `dma_pool_create'
   drivers/built-in.o: In function `ccp5_init':
   include/linux/dma-mapping.h:463: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp5_init':
   drivers/misc/amd-sp/ccp-dev-v5.c:892: undefined reference to `dma_pool_destroy'
   drivers/built-in.o: In function `ccp_init_dm_workarea':
   drivers/misc/amd-sp/ccp-ops.c:141: undefined reference to `dma_pool_alloc'
   drivers/built-in.o: In function `ccp_init_dm_workarea':
   include/linux/dma-mapping.h:190: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_sg_free':
   include/linux/dma-mapping.h:242: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_dm_free':
   drivers/misc/amd-sp/ccp-ops.c:112: undefined reference to `dma_pool_free'
   drivers/built-in.o: In function `ccp_dm_free':
   include/linux/dma-mapping.h:207: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `ccp_init_data':
   include/linux/dma-mapping.h:227: undefined reference to `bad_dma_ops'
   drivers/built-in.o: In function `img_ascii_lcd_probe':
   drivers/auxdisplay/img-ascii-lcd.c:384: undefined reference to `devm_ioremap_resource'
   collect2: error: ld returned 1 exit status

vim +30 include/linux/dmapool.h

dd0fc66f Al Viro         2005-10-07  24  void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
3a11ec5e Victor Fusco    2005-09-10  25  		     dma_addr_t *handle);
^1da177e Linus Torvalds  2005-04-16  26  
ad82362b Sean O. Stalley 2015-09-08  27  static inline void *dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags,
ad82362b Sean O. Stalley 2015-09-08  28  				    dma_addr_t *handle)
ad82362b Sean O. Stalley 2015-09-08  29  {
ad82362b Sean O. Stalley 2015-09-08 @30  	return dma_pool_alloc(pool, mem_flags | __GFP_ZERO, handle);
ad82362b Sean O. Stalley 2015-09-08  31  }
ad82362b Sean O. Stalley 2015-09-08  32  
^1da177e Linus Torvalds  2005-04-16  33  void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr);

:::::: The code at line 30 was first introduced by commit
:::::: ad82362b2defd4adad87d8538617b2f51a4bf9c3 mm: add dma_pool_zalloc() call to DMA API

:::::: TO: Sean O. Stalley <sean.stalley@intel.com>
:::::: CC: Linus Torvalds <torvalds@linux-foundation.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 18897 bytes --]

^ permalink raw reply

* Re: [PATCH 00/13] crypto: copy AAD during encrypt for AEAD ciphers
From: Stephan Müller @ 2017-01-20 20:28 UTC (permalink / raw)
  To: Cyrille Pitchen; +Cc: Herbert Xu, linux-crypto
In-Reply-To: <2a4fab23-3ea7-a0f7-7c30-55d301f51ec9@atmel.com>

Am Freitag, 20. Januar 2017, 18:07:04 CET schrieb Cyrille Pitchen:

Hi Cyrille,

> 
> I've taken Stephan's other comments into account from his review of the
> atmel-authenc driver so I'm preparing a new series but I don't know what to
> do for the associated data copy.
> 
> Please let me know what you recommend, thanks!

The question is where the null context shall be saved. As Herbert mentioned, 
he may not want to have it in crypto_aead.

Herbert, as this implementation also requires the copy, shall we leave the 
null context in crypto_aead? If so, Cyrille can simply use patch 01 from this 
series and apply the change to his code similar to what I did in patches 02 - 
13.

Ciao
Stephan

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox