* [PATCH v2 04/12] crypto: atmel-sha: redefine SHA_FLAGS_SHA* flags to match SHA_MR_ALGO_SHA*
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch modifies the SHA_FLAGS_SHA* flags: those algo flags are now
organized as values of a single bitfield instead of individual bits.
This allows to reduce the number of bits needed to encode all possible
values. Also the new values match the SHA_MR_ALGO_SHA* values hence
the algorithm bitfield of the SHA_MR register could simply be set with:
mr = (mr & ~SHA_FLAGS_ALGO_MASK) | (ctx->flags & SHA_FLAGS_ALGO_MASK)
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha-regs.h | 1 +
drivers/crypto/atmel-sha.c | 45 +++++++++++++++++++++++++++++------------
2 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
index e08897109cab..deb0b0b15096 100644
--- a/drivers/crypto/atmel-sha-regs.h
+++ b/drivers/crypto/atmel-sha-regs.h
@@ -19,6 +19,7 @@
#define SHA_MR_PROCDLY (1 << 4)
#define SHA_MR_UIHV (1 << 5)
#define SHA_MR_UIEHV (1 << 6)
+#define SHA_MR_ALGO_MASK GENMASK(10, 8)
#define SHA_MR_ALGO_SHA1 (0 << 8)
#define SHA_MR_ALGO_SHA256 (1 << 8)
#define SHA_MR_ALGO_SHA384 (2 << 8)
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 643d79a05dda..b29a4e5bc404 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -51,14 +51,16 @@
#define SHA_FLAGS_CPU BIT(5)
#define SHA_FLAGS_DMA_READY BIT(6)
+/* bits[10:8] are reserved. */
+#define SHA_FLAGS_ALGO_MASK SHA_MR_ALGO_MASK
+#define SHA_FLAGS_SHA1 SHA_MR_ALGO_SHA1
+#define SHA_FLAGS_SHA256 SHA_MR_ALGO_SHA256
+#define SHA_FLAGS_SHA384 SHA_MR_ALGO_SHA384
+#define SHA_FLAGS_SHA512 SHA_MR_ALGO_SHA512
+#define SHA_FLAGS_SHA224 SHA_MR_ALGO_SHA224
+
#define SHA_FLAGS_FINUP BIT(16)
#define SHA_FLAGS_SG BIT(17)
-#define SHA_FLAGS_ALGO_MASK GENMASK(22, 18)
-#define SHA_FLAGS_SHA1 BIT(18)
-#define SHA_FLAGS_SHA224 BIT(19)
-#define SHA_FLAGS_SHA256 BIT(20)
-#define SHA_FLAGS_SHA384 BIT(21)
-#define SHA_FLAGS_SHA512 BIT(22)
#define SHA_FLAGS_ERROR BIT(23)
#define SHA_FLAGS_PAD BIT(24)
#define SHA_FLAGS_RESTORE BIT(25)
@@ -264,7 +266,9 @@ static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
bits[1] = cpu_to_be64(size[0] << 3);
bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61);
- if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) {
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ case SHA_FLAGS_SHA384:
+ case SHA_FLAGS_SHA512:
index = ctx->bufcnt & 0x7f;
padlen = (index < 112) ? (112 - index) : ((128+112) - index);
*(ctx->buffer + ctx->bufcnt) = 0x80;
@@ -272,7 +276,9 @@ static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
ctx->bufcnt += padlen + 16;
ctx->flags |= SHA_FLAGS_PAD;
- } else {
+ break;
+
+ default:
index = ctx->bufcnt & 0x3f;
padlen = (index < 56) ? (56 - index) : ((64+56) - index);
*(ctx->buffer + ctx->bufcnt) = 0x80;
@@ -280,6 +286,7 @@ static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
ctx->bufcnt += padlen + 8;
ctx->flags |= SHA_FLAGS_PAD;
+ break;
}
}
@@ -828,16 +835,28 @@ static void atmel_sha_copy_ready_hash(struct ahash_request *req)
if (!req->result)
return;
- if (ctx->flags & SHA_FLAGS_SHA1)
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ default:
+ case SHA_FLAGS_SHA1:
memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
- else if (ctx->flags & SHA_FLAGS_SHA224)
+ break;
+
+ case SHA_FLAGS_SHA224:
memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE);
- else if (ctx->flags & SHA_FLAGS_SHA256)
+ break;
+
+ case SHA_FLAGS_SHA256:
memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
- else if (ctx->flags & SHA_FLAGS_SHA384)
+ break;
+
+ case SHA_FLAGS_SHA384:
memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE);
- else
+ break;
+
+ case SHA_FLAGS_SHA512:
memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE);
+ break;
+ }
}
static int atmel_sha_finish(struct ahash_request *req)
--
2.7.4
^ permalink raw reply related
* [PATCH v2 05/12] crypto: atmel-sha: add atmel_sha_wait_for_data_ready()
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: Cyrille Pitchen, linux-crypto, linux-arm-kernel, linux-kernel
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch simply defines a helper function to test the 'Data Ready' flag
of the Status Register. It also gives a chance for the crypto request to
be processed synchronously if this 'Data Ready' flag is already set when
polling the Status Register. Indeed, running synchronously avoid the
latency of the 'Data Ready' interrupt.
When the 'Data Ready' flag has not been set yet, we enable the associated
interrupt and resume processing the crypto request asynchronously from the
'done' task just as before.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index b29a4e5bc404..be0d72cf4352 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -434,6 +434,19 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
atmel_sha_write(dd, SHA_MR, valmr);
}
+static inline int atmel_sha_wait_for_data_ready(struct atmel_sha_dev *dd,
+ atmel_sha_fn_t resume)
+{
+ u32 isr = atmel_sha_read(dd, SHA_ISR);
+
+ if (unlikely(isr & SHA_INT_DATARDY))
+ return resume(dd);
+
+ dd->resume = resume;
+ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
+ return -EINPROGRESS;
+}
+
static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
size_t length, int final)
{
--
2.7.4
^ permalink raw reply related
* [PATCH v2 06/12] crypto: atmel-sha: add SHA_MR_MODE_IDATAR0
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch defines an alias macro to SHA_MR_MODE_PDC, which is not suited
for DMA usage.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha-regs.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
index deb0b0b15096..8d62d31eda08 100644
--- a/drivers/crypto/atmel-sha-regs.h
+++ b/drivers/crypto/atmel-sha-regs.h
@@ -16,6 +16,7 @@
#define SHA_MR_MODE_MANUAL 0x0
#define SHA_MR_MODE_AUTO 0x1
#define SHA_MR_MODE_PDC 0x2
+#define SHA_MR_MODE_IDATAR0 0x2
#define SHA_MR_PROCDLY (1 << 4)
#define SHA_MR_UIHV (1 << 5)
#define SHA_MR_UIEHV (1 << 6)
--
2.7.4
^ permalink raw reply related
* [PATCH v2 07/12] crypto: atmel-sha: add atmel_sha_cpu_start()
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch adds a simple function to perform data transfer with PIO, hence
handled by the CPU.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index be0d72cf4352..58d9ca8ac0f2 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -64,6 +64,8 @@
#define SHA_FLAGS_ERROR BIT(23)
#define SHA_FLAGS_PAD BIT(24)
#define SHA_FLAGS_RESTORE BIT(25)
+#define SHA_FLAGS_IDATAR0 BIT(26)
+#define SHA_FLAGS_WAIT_DATARDY BIT(27)
#define SHA_OP_UPDATE 1
#define SHA_OP_FINAL 2
@@ -141,6 +143,7 @@ struct atmel_sha_dev {
struct ahash_request *req;
bool is_async;
atmel_sha_fn_t resume;
+ atmel_sha_fn_t cpu_transfer_complete;
struct atmel_sha_dma dma_lch_in;
@@ -1317,6 +1320,93 @@ static irqreturn_t atmel_sha_irq(int irq, void *dev_id)
return IRQ_NONE;
}
+
+/* CPU transfer functions */
+
+static int atmel_sha_cpu_transfer(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ const u32 *words = (const u32 *)ctx->buffer;
+ size_t i, num_words;
+ u32 isr, din, din_inc;
+
+ din_inc = (ctx->flags & SHA_FLAGS_IDATAR0) ? 0 : 1;
+ for (;;) {
+ /* Write data into the Input Data Registers. */
+ num_words = DIV_ROUND_UP(ctx->bufcnt, sizeof(u32));
+ for (i = 0, din = 0; i < num_words; ++i, din += din_inc)
+ atmel_sha_write(dd, SHA_REG_DIN(din), words[i]);
+
+ ctx->offset += ctx->bufcnt;
+ ctx->total -= ctx->bufcnt;
+
+ if (!ctx->total)
+ break;
+
+ /*
+ * Prepare next block:
+ * Fill ctx->buffer now with the next data to be written into
+ * IDATARx: it gives time for the SHA hardware to process
+ * the current data so the SHA_INT_DATARDY flag might be set
+ * in SHA_ISR when polling this register at the beginning of
+ * the next loop.
+ */
+ ctx->bufcnt = min_t(size_t, ctx->block_size, ctx->total);
+ scatterwalk_map_and_copy(ctx->buffer, ctx->sg,
+ ctx->offset, ctx->bufcnt, 0);
+
+ /* Wait for hardware to be ready again. */
+ isr = atmel_sha_read(dd, SHA_ISR);
+ if (!(isr & SHA_INT_DATARDY)) {
+ /* Not ready yet. */
+ dd->resume = atmel_sha_cpu_transfer;
+ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
+ return -EINPROGRESS;
+ }
+ }
+
+ if (unlikely(!(ctx->flags & SHA_FLAGS_WAIT_DATARDY)))
+ return dd->cpu_transfer_complete(dd);
+
+ return atmel_sha_wait_for_data_ready(dd, dd->cpu_transfer_complete);
+}
+
+static int atmel_sha_cpu_start(struct atmel_sha_dev *dd,
+ struct scatterlist *sg,
+ unsigned int len,
+ bool idatar0_only,
+ bool wait_data_ready,
+ atmel_sha_fn_t resume)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+
+ if (!len)
+ return resume(dd);
+
+ ctx->flags &= ~(SHA_FLAGS_IDATAR0 | SHA_FLAGS_WAIT_DATARDY);
+
+ if (idatar0_only)
+ ctx->flags |= SHA_FLAGS_IDATAR0;
+
+ if (wait_data_ready)
+ ctx->flags |= SHA_FLAGS_WAIT_DATARDY;
+
+ ctx->sg = sg;
+ ctx->total = len;
+ ctx->offset = 0;
+
+ /* Prepare the first block to be written. */
+ ctx->bufcnt = min_t(size_t, ctx->block_size, ctx->total);
+ scatterwalk_map_and_copy(ctx->buffer, ctx->sg,
+ ctx->offset, ctx->bufcnt, 0);
+
+ dd->cpu_transfer_complete = resume;
+ return atmel_sha_cpu_transfer(dd);
+}
+
+
static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
{
int i;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 08/12] crypto: atmel-sha: add simple DMA transfers
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch adds a simple function to perform data transfer with the DMA
controller.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha.c | 116 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 58d9ca8ac0f2..a4fc60b67099 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -123,6 +123,9 @@ struct atmel_sha_ctx {
struct atmel_sha_dma {
struct dma_chan *chan;
struct dma_slave_config dma_conf;
+ struct scatterlist *sg;
+ int nents;
+ unsigned int last_sg_length;
};
struct atmel_sha_dev {
@@ -1321,6 +1324,119 @@ static irqreturn_t atmel_sha_irq(int irq, void *dev_id)
}
+/* DMA transfer functions */
+
+static bool atmel_sha_dma_check_aligned(struct atmel_sha_dev *dd,
+ struct scatterlist *sg,
+ size_t len)
+{
+ struct atmel_sha_dma *dma = &dd->dma_lch_in;
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ size_t bs = ctx->block_size;
+ int nents;
+
+ for (nents = 0; sg; sg = sg_next(sg), ++nents) {
+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+ return false;
+
+ /*
+ * This is the last sg, the only one that is allowed to
+ * have an unaligned length.
+ */
+ if (len <= sg->length) {
+ dma->nents = nents + 1;
+ dma->last_sg_length = sg->length;
+ sg->length = ALIGN(len, sizeof(u32));
+ return true;
+ }
+
+ /* All other sg lengths MUST be aligned to the block size. */
+ if (!IS_ALIGNED(sg->length, bs))
+ return false;
+
+ len -= sg->length;
+ }
+
+ return false;
+}
+
+static void atmel_sha_dma_callback2(void *data)
+{
+ struct atmel_sha_dev *dd = data;
+ struct atmel_sha_dma *dma = &dd->dma_lch_in;
+ struct scatterlist *sg;
+ int nents;
+
+ dmaengine_terminate_all(dma->chan);
+ dma_unmap_sg(dd->dev, dma->sg, dma->nents, DMA_TO_DEVICE);
+
+ sg = dma->sg;
+ for (nents = 0; nents < dma->nents - 1; ++nents)
+ sg = sg_next(sg);
+ sg->length = dma->last_sg_length;
+
+ dd->is_async = true;
+ (void)atmel_sha_wait_for_data_ready(dd, dd->resume);
+}
+
+static int atmel_sha_dma_start(struct atmel_sha_dev *dd,
+ struct scatterlist *src,
+ size_t len,
+ atmel_sha_fn_t resume)
+{
+ struct atmel_sha_dma *dma = &dd->dma_lch_in;
+ struct dma_slave_config *config = &dma->dma_conf;
+ struct dma_chan *chan = dma->chan;
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+ unsigned int sg_len;
+ int err;
+
+ dd->resume = resume;
+
+ /*
+ * dma->nents has already been initialized by
+ * atmel_sha_dma_check_aligned().
+ */
+ dma->sg = src;
+ sg_len = dma_map_sg(dd->dev, dma->sg, dma->nents, DMA_TO_DEVICE);
+ if (!sg_len) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ config->src_maxburst = 16;
+ config->dst_maxburst = 16;
+ err = dmaengine_slave_config(chan, config);
+ if (err)
+ goto unmap_sg;
+
+ desc = dmaengine_prep_slave_sg(chan, dma->sg, sg_len, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ err = -ENOMEM;
+ goto unmap_sg;
+ }
+
+ desc->callback = atmel_sha_dma_callback2;
+ desc->callback_param = dd;
+ cookie = dmaengine_submit(desc);
+ err = dma_submit_error(cookie);
+ if (err)
+ goto unmap_sg;
+
+ dma_async_issue_pending(chan);
+
+ return -EINPROGRESS;
+
+unmap_sg:
+ dma_unmap_sg(dd->dev, dma->sg, dma->nents, DMA_TO_DEVICE);
+exit:
+ return atmel_sha_complete(dd, err);
+}
+
+
/* CPU transfer functions */
static int atmel_sha_cpu_transfer(struct atmel_sha_dev *dd)
--
2.7.4
^ permalink raw reply related
* [PATCH v2 10/12] crypto: atmel-aes: fix atmel_aes_handle_queue()
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch fixes the value returned by atmel_aes_handle_queue(), which
could have been wrong previously when the crypto request was started
synchronously but became asynchronous during the ctx->start() call.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-aes.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 0e3d0d655b96..9fd2f63b8bc0 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -879,6 +879,7 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
struct crypto_async_request *areq, *backlog;
struct atmel_aes_base_ctx *ctx;
unsigned long flags;
+ bool start_async;
int err, ret = 0;
spin_lock_irqsave(&dd->lock, flags);
@@ -904,10 +905,12 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
dd->areq = areq;
dd->ctx = ctx;
- dd->is_async = (areq != new_areq);
+ start_async = (areq != new_areq);
+ dd->is_async = start_async;
+ /* WARNING: ctx->start() MAY change dd->is_async. */
err = ctx->start(dd);
- return (dd->is_async) ? ret : err;
+ return (start_async) ? ret : err;
}
--
2.7.4
^ permalink raw reply related
* [PATCH v2 11/12] crypto: atmel-authenc: add support to authenc(hmac(shaX),Y(aes)) modes
From: Cyrille Pitchen @ 2016-12-22 16:38 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patchs allows to combine the AES and SHA hardware accelerators on
some Atmel SoCs. Doing so, AES blocks are only written to/read from the
AES hardware. Those blocks are also transferred from the AES to the SHA
accelerator internally, without additionnal accesses to the system busses.
Hence, the AES and SHA accelerators work in parallel to process all the
data blocks, instead of serializing the process by (de)crypting those
blocks first then authenticating them after like the generic
crypto/authenc.c driver does.
Of course, both the AES and SHA hardware accelerators need to be available
before we can start to process the data blocks. Hence we use their crypto
request queue to synchronize both drivers.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/Kconfig | 12 +
drivers/crypto/atmel-aes-regs.h | 16 ++
drivers/crypto/atmel-aes.c | 471 +++++++++++++++++++++++++++++++++++++++-
drivers/crypto/atmel-authenc.h | 64 ++++++
drivers/crypto/atmel-sha-regs.h | 14 ++
drivers/crypto/atmel-sha.c | 344 +++++++++++++++++++++++++++--
6 files changed, 906 insertions(+), 15 deletions(-)
create mode 100644 drivers/crypto/atmel-authenc.h
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 79564785ae30..719a868d8ea1 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -415,6 +415,18 @@ config CRYPTO_DEV_BFIN_CRC
Newer Blackfin processors have CRC hardware. Select this if you
want to use the Blackfin CRC module.
+config CRYPTO_DEV_ATMEL_AUTHENC
+ tristate "Support for Atmel IPSEC/SSL hw accelerator"
+ depends on (ARCH_AT91 && HAS_DMA) || COMPILE_TEST
+ select CRYPTO_AUTHENC
+ select CRYPTO_DEV_ATMEL_AES
+ select CRYPTO_DEV_ATMEL_SHA
+ help
+ Some Atmel processors can combine the AES and SHA hw accelerators
+ to enhance support of IPSEC/SSL.
+ Select this if you want to use the Atmel modules for
+ authenc(hmac(shaX),Y(cbc)) algorithms.
+
config CRYPTO_DEV_ATMEL_AES
tristate "Support for Atmel AES hw accelerator"
depends on HAS_DMA
diff --git a/drivers/crypto/atmel-aes-regs.h b/drivers/crypto/atmel-aes-regs.h
index 0ec04407b533..7694679802b3 100644
--- a/drivers/crypto/atmel-aes-regs.h
+++ b/drivers/crypto/atmel-aes-regs.h
@@ -68,6 +68,22 @@
#define AES_CTRR 0x98
#define AES_GCMHR(x) (0x9c + ((x) * 0x04))
+#define AES_EMR 0xb0
+#define AES_EMR_APEN BIT(0) /* Auto Padding Enable */
+#define AES_EMR_APM BIT(1) /* Auto Padding Mode */
+#define AES_EMR_APM_IPSEC 0x0
+#define AES_EMR_APM_SSL BIT(1)
+#define AES_EMR_PLIPEN BIT(4) /* PLIP Enable */
+#define AES_EMR_PLIPD BIT(5) /* PLIP Decipher */
+#define AES_EMR_PADLEN_MASK (0xFu << 8)
+#define AES_EMR_PADLEN_OFFSET 8
+#define AES_EMR_PADLEN(padlen) (((padlen) << AES_EMR_PADLEN_OFFSET) &\
+ AES_EMR_PADLEN_MASK)
+#define AES_EMR_NHEAD_MASK (0xFu << 16)
+#define AES_EMR_NHEAD_OFFSET 16
+#define AES_EMR_NHEAD(nhead) (((nhead) << AES_EMR_NHEAD_OFFSET) &\
+ AES_EMR_NHEAD_MASK)
+
#define AES_TWR(x) (0xc0 + ((x) * 0x04))
#define AES_ALPHAR(x) (0xd0 + ((x) * 0x04))
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 9fd2f63b8bc0..3c651e0c3113 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -41,6 +41,7 @@
#include <linux/platform_data/crypto-atmel.h>
#include <dt-bindings/dma/at91.h>
#include "atmel-aes-regs.h"
+#include "atmel-authenc.h"
#define ATMEL_AES_PRIORITY 300
@@ -78,6 +79,7 @@
#define AES_FLAGS_INIT BIT(2)
#define AES_FLAGS_BUSY BIT(3)
#define AES_FLAGS_DUMP_REG BIT(4)
+#define AES_FLAGS_OWN_SHA BIT(5)
#define AES_FLAGS_PERSISTENT (AES_FLAGS_INIT | AES_FLAGS_BUSY)
@@ -92,6 +94,7 @@ struct atmel_aes_caps {
bool has_ctr32;
bool has_gcm;
bool has_xts;
+ bool has_authenc;
u32 max_burst_size;
};
@@ -144,10 +147,31 @@ struct atmel_aes_xts_ctx {
u32 key2[AES_KEYSIZE_256 / sizeof(u32)];
};
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+struct atmel_aes_authenc_ctx {
+ struct atmel_aes_base_ctx base;
+ struct atmel_sha_authenc_ctx *auth;
+};
+#endif
+
struct atmel_aes_reqctx {
unsigned long mode;
};
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+struct atmel_aes_authenc_reqctx {
+ struct atmel_aes_reqctx base;
+
+ struct scatterlist src[2];
+ struct scatterlist dst[2];
+ size_t textlen;
+ u32 digest[SHA512_DIGEST_SIZE / sizeof(u32)];
+
+ /* auth_req MUST be place last. */
+ struct ahash_request auth_req;
+};
+#endif
+
struct atmel_aes_dma {
struct dma_chan *chan;
struct scatterlist *sg;
@@ -291,6 +315,9 @@ static const char *atmel_aes_reg_name(u32 offset, char *tmp, size_t sz)
snprintf(tmp, sz, "GCMHR[%u]", (offset - AES_GCMHR(0)) >> 2);
break;
+ case AES_EMR:
+ return "EMR";
+
case AES_TWR(0):
case AES_TWR(1):
case AES_TWR(2):
@@ -463,8 +490,16 @@ static inline bool atmel_aes_is_encrypt(const struct atmel_aes_dev *dd)
return (dd->flags & AES_FLAGS_ENCRYPT);
}
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err);
+#endif
+
static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
{
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+ atmel_aes_authenc_complete(dd, err);
+#endif
+
clk_disable(dd->iclk);
dd->flags &= ~AES_FLAGS_BUSY;
@@ -1931,6 +1966,407 @@ static struct crypto_alg aes_xts_alg = {
}
};
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+/* authenc aead functions */
+
+static int atmel_aes_authenc_start(struct atmel_aes_dev *dd);
+static int atmel_aes_authenc_init(struct atmel_aes_dev *dd, int err,
+ bool is_async);
+static int atmel_aes_authenc_transfer(struct atmel_aes_dev *dd, int err,
+ bool is_async);
+static int atmel_aes_authenc_digest(struct atmel_aes_dev *dd);
+static int atmel_aes_authenc_final(struct atmel_aes_dev *dd, int err,
+ bool is_async);
+
+static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err)
+{
+ struct aead_request *req = aead_request_cast(dd->areq);
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+
+ if (err && (dd->flags & AES_FLAGS_OWN_SHA))
+ atmel_sha_authenc_abort(&rctx->auth_req);
+ dd->flags &= ~AES_FLAGS_OWN_SHA;
+}
+
+static int atmel_aes_authenc_copy_assoc(struct aead_request *req)
+{
+ size_t buflen, assoclen = req->assoclen;
+ off_t skip = 0;
+ u8 buf[256];
+
+ while (assoclen) {
+ buflen = min_t(size_t, assoclen, sizeof(buf));
+
+ if (sg_pcopy_to_buffer(req->src, sg_nents(req->src),
+ buf, buflen, skip) != buflen)
+ return -EINVAL;
+
+ if (sg_pcopy_from_buffer(req->dst, sg_nents(req->dst),
+ buf, buflen, skip) != buflen)
+ return -EINVAL;
+
+ skip += buflen;
+ assoclen -= buflen;
+ }
+
+ return 0;
+}
+
+static int atmel_aes_authenc_start(struct atmel_aes_dev *dd)
+{
+ struct aead_request *req = aead_request_cast(dd->areq);
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
+ int err;
+
+ atmel_aes_set_mode(dd, &rctx->base);
+
+ err = atmel_aes_hw_init(dd);
+ if (err)
+ return atmel_aes_complete(dd, err);
+
+ return atmel_sha_authenc_schedule(&rctx->auth_req, ctx->auth,
+ atmel_aes_authenc_init, dd);
+}
+
+static int atmel_aes_authenc_init(struct atmel_aes_dev *dd, int err,
+ bool is_async)
+{
+ struct aead_request *req = aead_request_cast(dd->areq);
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+
+ if (is_async)
+ dd->is_async = true;
+ if (err)
+ return atmel_aes_complete(dd, err);
+
+ /* If here, we've got the ownership of the SHA device. */
+ dd->flags |= AES_FLAGS_OWN_SHA;
+
+ /* Configure the SHA device. */
+ return atmel_sha_authenc_init(&rctx->auth_req,
+ req->src, req->assoclen,
+ rctx->textlen,
+ atmel_aes_authenc_transfer, dd);
+}
+
+static int atmel_aes_authenc_transfer(struct atmel_aes_dev *dd, int err,
+ bool is_async)
+{
+ struct aead_request *req = aead_request_cast(dd->areq);
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+ bool enc = atmel_aes_is_encrypt(dd);
+ struct scatterlist *src, *dst;
+ u32 iv[AES_BLOCK_SIZE / sizeof(u32)];
+ u32 emr;
+
+ if (is_async)
+ dd->is_async = true;
+ if (err)
+ return atmel_aes_complete(dd, err);
+
+ /* Prepare src and dst scatter-lists to transfer cipher/plain texts. */
+ src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen);
+ dst = src;
+
+ if (req->src != req->dst) {
+ err = atmel_aes_authenc_copy_assoc(req);
+ if (err)
+ return atmel_aes_complete(dd, err);
+
+ dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
+ }
+
+ /* Configure the AES device. */
+ memcpy(iv, req->iv, sizeof(iv));
+
+ /*
+ * Here we always set the 2nd parameter of atmel_aes_write_ctrl() to
+ * 'true' even if the data transfer is actually performed by the CPU (so
+ * not by the DMA) because we must force the AES_MR_SMOD bitfield to the
+ * value AES_MR_SMOD_IDATAR0. Indeed, both AES_MR_SMOD and SHA_MR_SMOD
+ * must be set to *_MR_SMOD_IDATAR0.
+ */
+ atmel_aes_write_ctrl(dd, true, iv);
+ emr = AES_EMR_PLIPEN;
+ if (!enc)
+ emr |= AES_EMR_PLIPD;
+ atmel_aes_write(dd, AES_EMR, emr);
+
+ /* Transfer data. */
+ return atmel_aes_dma_start(dd, src, dst, rctx->textlen,
+ atmel_aes_authenc_digest);
+}
+
+static int atmel_aes_authenc_digest(struct atmel_aes_dev *dd)
+{
+ struct aead_request *req = aead_request_cast(dd->areq);
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+
+ /* atmel_sha_authenc_final() releases the SHA device. */
+ dd->flags &= ~AES_FLAGS_OWN_SHA;
+ return atmel_sha_authenc_final(&rctx->auth_req,
+ rctx->digest, sizeof(rctx->digest),
+ atmel_aes_authenc_final, dd);
+}
+
+static int atmel_aes_authenc_final(struct atmel_aes_dev *dd, int err,
+ bool is_async)
+{
+ struct aead_request *req = aead_request_cast(dd->areq);
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ bool enc = atmel_aes_is_encrypt(dd);
+ u32 idigest[SHA512_DIGEST_SIZE / sizeof(u32)], *odigest = rctx->digest;
+ u32 offs, authsize;
+
+ if (is_async)
+ dd->is_async = true;
+ if (err)
+ goto complete;
+
+ offs = req->assoclen + rctx->textlen;
+ authsize = crypto_aead_authsize(tfm);
+ if (enc) {
+ scatterwalk_map_and_copy(odigest, req->dst, offs, authsize, 1);
+ } else {
+ scatterwalk_map_and_copy(idigest, req->src, offs, authsize, 0);
+ if (crypto_memneq(idigest, odigest, authsize))
+ err = -EBADMSG;
+ }
+
+complete:
+ return atmel_aes_complete(dd, err);
+}
+
+static int atmel_aes_authenc_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
+ struct crypto_authenc_keys keys;
+ u32 flags;
+ int err;
+
+ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
+ goto badkey;
+
+ if (keys.enckeylen > sizeof(ctx->base.key))
+ goto badkey;
+
+ /* Save auth key. */
+ flags = crypto_aead_get_flags(tfm);
+ err = atmel_sha_authenc_setkey(ctx->auth,
+ keys.authkey, keys.authkeylen,
+ &flags);
+ crypto_aead_set_flags(tfm, flags & CRYPTO_TFM_RES_MASK);
+ if (err)
+ return err;
+
+ /* Save enc key. */
+ ctx->base.keylen = keys.enckeylen;
+ memcpy(ctx->base.key, keys.enckey, keys.enckeylen);
+
+ return 0;
+
+badkey:
+ crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+}
+
+static int atmel_aes_authenc_init_tfm(struct crypto_aead *tfm,
+ unsigned long auth_mode)
+{
+ struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned int auth_reqsize = atmel_sha_authenc_get_reqsize();
+
+ ctx->auth = atmel_sha_authenc_spawn(auth_mode);
+ if (IS_ERR(ctx->auth))
+ return PTR_ERR(ctx->auth);
+
+ crypto_aead_set_reqsize(tfm, (sizeof(struct atmel_aes_authenc_reqctx) +
+ auth_reqsize));
+ ctx->base.start = atmel_aes_authenc_start;
+
+ return 0;
+}
+
+static int atmel_aes_authenc_hmac_sha1_init_tfm(struct crypto_aead *tfm)
+{
+ return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA1);
+}
+
+static int atmel_aes_authenc_hmac_sha224_init_tfm(struct crypto_aead *tfm)
+{
+ return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA224);
+}
+
+static int atmel_aes_authenc_hmac_sha256_init_tfm(struct crypto_aead *tfm)
+{
+ return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA256);
+}
+
+static int atmel_aes_authenc_hmac_sha384_init_tfm(struct crypto_aead *tfm)
+{
+ return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA384);
+}
+
+static int atmel_aes_authenc_hmac_sha512_init_tfm(struct crypto_aead *tfm)
+{
+ return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA512);
+}
+
+static void atmel_aes_authenc_exit_tfm(struct crypto_aead *tfm)
+{
+ struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
+
+ atmel_sha_authenc_free(ctx->auth);
+}
+
+static int atmel_aes_authenc_crypt(struct aead_request *req,
+ unsigned long mode)
+{
+ struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct atmel_aes_base_ctx *ctx = crypto_aead_ctx(tfm);
+ u32 authsize = crypto_aead_authsize(tfm);
+ bool enc = (mode & AES_FLAGS_ENCRYPT);
+ struct atmel_aes_dev *dd;
+
+ /* Compute text length. */
+ rctx->textlen = req->cryptlen - (enc ? 0 : authsize);
+
+ /*
+ * Currently, empty messages are not supported yet:
+ * the SHA auto-padding can be used only on non-empty messages.
+ * Hence a special case needs to be implemented for empty message.
+ */
+ if (!rctx->textlen && !req->assoclen)
+ return -EINVAL;
+
+ rctx->base.mode = mode;
+ ctx->block_size = AES_BLOCK_SIZE;
+
+ dd = atmel_aes_find_dev(ctx);
+ if (!dd)
+ return -ENODEV;
+
+ return atmel_aes_handle_queue(dd, &req->base);
+}
+
+static int atmel_aes_authenc_cbc_aes_encrypt(struct aead_request *req)
+{
+ return atmel_aes_authenc_crypt(req, AES_FLAGS_CBC | AES_FLAGS_ENCRYPT);
+}
+
+static int atmel_aes_authenc_cbc_aes_decrypt(struct aead_request *req)
+{
+ return atmel_aes_authenc_crypt(req, AES_FLAGS_CBC);
+}
+
+static struct aead_alg aes_authenc_algs[] = {
+{
+ .setkey = atmel_aes_authenc_setkey,
+ .encrypt = atmel_aes_authenc_cbc_aes_encrypt,
+ .decrypt = atmel_aes_authenc_cbc_aes_decrypt,
+ .init = atmel_aes_authenc_hmac_sha1_init_tfm,
+ .exit = atmel_aes_authenc_exit_tfm,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+
+ .base = {
+ .cra_name = "authenc(hmac(sha1),cbc(aes))",
+ .cra_driver_name = "atmel-authenc-hmac-sha1-cbc-aes",
+ .cra_priority = ATMEL_AES_PRIORITY,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_authenc_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+{
+ .setkey = atmel_aes_authenc_setkey,
+ .encrypt = atmel_aes_authenc_cbc_aes_encrypt,
+ .decrypt = atmel_aes_authenc_cbc_aes_decrypt,
+ .init = atmel_aes_authenc_hmac_sha224_init_tfm,
+ .exit = atmel_aes_authenc_exit_tfm,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+
+ .base = {
+ .cra_name = "authenc(hmac(sha224),cbc(aes))",
+ .cra_driver_name = "atmel-authenc-hmac-sha224-cbc-aes",
+ .cra_priority = ATMEL_AES_PRIORITY,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_authenc_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+{
+ .setkey = atmel_aes_authenc_setkey,
+ .encrypt = atmel_aes_authenc_cbc_aes_encrypt,
+ .decrypt = atmel_aes_authenc_cbc_aes_decrypt,
+ .init = atmel_aes_authenc_hmac_sha256_init_tfm,
+ .exit = atmel_aes_authenc_exit_tfm,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+
+ .base = {
+ .cra_name = "authenc(hmac(sha256),cbc(aes))",
+ .cra_driver_name = "atmel-authenc-hmac-sha256-cbc-aes",
+ .cra_priority = ATMEL_AES_PRIORITY,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_authenc_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+{
+ .setkey = atmel_aes_authenc_setkey,
+ .encrypt = atmel_aes_authenc_cbc_aes_encrypt,
+ .decrypt = atmel_aes_authenc_cbc_aes_decrypt,
+ .init = atmel_aes_authenc_hmac_sha384_init_tfm,
+ .exit = atmel_aes_authenc_exit_tfm,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+
+ .base = {
+ .cra_name = "authenc(hmac(sha384),cbc(aes))",
+ .cra_driver_name = "atmel-authenc-hmac-sha384-cbc-aes",
+ .cra_priority = ATMEL_AES_PRIORITY,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_authenc_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+{
+ .setkey = atmel_aes_authenc_setkey,
+ .encrypt = atmel_aes_authenc_cbc_aes_encrypt,
+ .decrypt = atmel_aes_authenc_cbc_aes_decrypt,
+ .init = atmel_aes_authenc_hmac_sha512_init_tfm,
+ .exit = atmel_aes_authenc_exit_tfm,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+
+ .base = {
+ .cra_name = "authenc(hmac(sha512),cbc(aes))",
+ .cra_driver_name = "atmel-authenc-hmac-sha512-cbc-aes",
+ .cra_priority = ATMEL_AES_PRIORITY,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_authenc_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+};
+#endif /* CONFIG_CRYPTO_DEV_ATMEL_AUTHENC */
/* Probe functions */
@@ -2040,6 +2476,12 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
{
int i;
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+ if (dd->caps.has_authenc)
+ for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++)
+ crypto_unregister_aead(&aes_authenc_algs[i]);
+#endif
+
if (dd->caps.has_xts)
crypto_unregister_alg(&aes_xts_alg);
@@ -2081,8 +2523,25 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
goto err_aes_xts_alg;
}
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+ if (dd->caps.has_authenc) {
+ for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) {
+ err = crypto_register_aead(&aes_authenc_algs[i]);
+ if (err)
+ goto err_aes_authenc_alg;
+ }
+ }
+#endif
+
return 0;
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+ /* i = ARRAY_SIZE(aes_authenc_algs); */
+err_aes_authenc_alg:
+ for (j = 0; j < i; j++)
+ crypto_unregister_aead(&aes_authenc_algs[j]);
+ crypto_unregister_alg(&aes_xts_alg);
+#endif
err_aes_xts_alg:
crypto_unregister_aead(&aes_gcm_alg);
err_aes_gcm_alg:
@@ -2103,6 +2562,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
dd->caps.has_ctr32 = 0;
dd->caps.has_gcm = 0;
dd->caps.has_xts = 0;
+ dd->caps.has_authenc = 0;
dd->caps.max_burst_size = 1;
/* keep only major version number */
@@ -2113,6 +2573,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
dd->caps.has_ctr32 = 1;
dd->caps.has_gcm = 1;
dd->caps.has_xts = 1;
+ dd->caps.has_authenc = 1;
dd->caps.max_burst_size = 4;
break;
case 0x200:
@@ -2271,6 +2732,13 @@ static int atmel_aes_probe(struct platform_device *pdev)
atmel_aes_get_cap(aes_dd);
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+ if (aes_dd->caps.has_authenc && !atmel_sha_authenc_is_ready()) {
+ err = -EPROBE_DEFER;
+ goto iclk_unprepare;
+ }
+#endif
+
err = atmel_aes_buff_init(aes_dd);
if (err)
goto err_aes_buff;
@@ -2307,7 +2775,8 @@ static int atmel_aes_probe(struct platform_device *pdev)
tasklet_kill(&aes_dd->done_task);
tasklet_kill(&aes_dd->queue_task);
aes_dd_err:
- dev_err(dev, "initialization failed.\n");
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "initialization failed.\n");
return err;
}
diff --git a/drivers/crypto/atmel-authenc.h b/drivers/crypto/atmel-authenc.h
new file mode 100644
index 000000000000..2a60d1224143
--- /dev/null
+++ b/drivers/crypto/atmel-authenc.h
@@ -0,0 +1,64 @@
+/*
+ * API for Atmel Secure Protocol Layers Improved Performances (SPLIP)
+ *
+ * Copyright (C) 2016 Atmel Corporation
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale.
+ */
+
+#ifndef __ATMEL_AUTHENC_H__
+#define __ATMEL_AUTHENC_H__
+
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+
+#include <crypto/authenc.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include "atmel-sha-regs.h"
+
+struct atmel_aes_dev;
+typedef int (*atmel_aes_authenc_fn_t)(struct atmel_aes_dev *, int, bool);
+
+struct atmel_sha_authenc_ctx;
+
+bool atmel_sha_authenc_is_ready(void);
+unsigned int atmel_sha_authenc_get_reqsize(void);
+
+struct atmel_sha_authenc_ctx *atmel_sha_authenc_spawn(unsigned long mode);
+void atmel_sha_authenc_free(struct atmel_sha_authenc_ctx *auth);
+int atmel_sha_authenc_setkey(struct atmel_sha_authenc_ctx *auth,
+ const u8 *key, unsigned int keylen,
+ u32 *flags);
+
+int atmel_sha_authenc_schedule(struct ahash_request *req,
+ struct atmel_sha_authenc_ctx *auth,
+ atmel_aes_authenc_fn_t cb,
+ struct atmel_aes_dev *dd);
+int atmel_sha_authenc_init(struct ahash_request *req,
+ struct scatterlist *assoc, unsigned int assoclen,
+ unsigned int textlen,
+ atmel_aes_authenc_fn_t cb,
+ struct atmel_aes_dev *dd);
+int atmel_sha_authenc_final(struct ahash_request *req,
+ u32 *digest, unsigned int digestlen,
+ atmel_aes_authenc_fn_t cb,
+ struct atmel_aes_dev *dd);
+void atmel_sha_authenc_abort(struct ahash_request *req);
+
+#endif /* CONFIG_CRYPTO_DEV_ATMEL_AUTHENC */
+
+#endif /* __ATMEL_AUTHENC_H__ */
diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
index 1b9f3d33079e..1b0eba4a2706 100644
--- a/drivers/crypto/atmel-sha-regs.h
+++ b/drivers/crypto/atmel-sha-regs.h
@@ -29,6 +29,20 @@
#define SHA_MR_HMAC (1 << 11)
#define SHA_MR_DUALBUFF (1 << 16)
+#define SHA_FLAGS_ALGO_MASK SHA_MR_ALGO_MASK
+#define SHA_FLAGS_SHA1 SHA_MR_ALGO_SHA1
+#define SHA_FLAGS_SHA256 SHA_MR_ALGO_SHA256
+#define SHA_FLAGS_SHA384 SHA_MR_ALGO_SHA384
+#define SHA_FLAGS_SHA512 SHA_MR_ALGO_SHA512
+#define SHA_FLAGS_SHA224 SHA_MR_ALGO_SHA224
+#define SHA_FLAGS_HMAC SHA_MR_HMAC
+#define SHA_FLAGS_HMAC_SHA1 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA1)
+#define SHA_FLAGS_HMAC_SHA256 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA256)
+#define SHA_FLAGS_HMAC_SHA384 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA384)
+#define SHA_FLAGS_HMAC_SHA512 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA512)
+#define SHA_FLAGS_HMAC_SHA224 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA224)
+#define SHA_FLAGS_MODE_MASK (SHA_FLAGS_HMAC | SHA_FLAGS_ALGO_MASK)
+
#define SHA_IER 0x10
#define SHA_IDR 0x14
#define SHA_IMR 0x18
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 78c3c02e4483..cc5294dbead4 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -41,6 +41,7 @@
#include <crypto/internal/hash.h>
#include <linux/platform_data/crypto-atmel.h>
#include "atmel-sha-regs.h"
+#include "atmel-authenc.h"
/* SHA flags */
#define SHA_FLAGS_BUSY BIT(0)
@@ -52,19 +53,6 @@
#define SHA_FLAGS_DMA_READY BIT(6)
/* bits[11:8] are reserved. */
-#define SHA_FLAGS_ALGO_MASK SHA_MR_ALGO_MASK
-#define SHA_FLAGS_SHA1 SHA_MR_ALGO_SHA1
-#define SHA_FLAGS_SHA256 SHA_MR_ALGO_SHA256
-#define SHA_FLAGS_SHA384 SHA_MR_ALGO_SHA384
-#define SHA_FLAGS_SHA512 SHA_MR_ALGO_SHA512
-#define SHA_FLAGS_SHA224 SHA_MR_ALGO_SHA224
-#define SHA_FLAGS_HMAC SHA_MR_HMAC
-#define SHA_FLAGS_HMAC_SHA1 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA1)
-#define SHA_FLAGS_HMAC_SHA256 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA256)
-#define SHA_FLAGS_HMAC_SHA384 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA384)
-#define SHA_FLAGS_HMAC_SHA512 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA512)
-#define SHA_FLAGS_HMAC_SHA224 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA224)
-#define SHA_FLAGS_MODE_MASK (SHA_FLAGS_HMAC | SHA_FLAGS_ALGO_MASK)
#define SHA_FLAGS_FINUP BIT(16)
#define SHA_FLAGS_SG BIT(17)
@@ -156,6 +144,7 @@ struct atmel_sha_dev {
struct crypto_queue queue;
struct ahash_request *req;
bool is_async;
+ bool force_complete;
atmel_sha_fn_t resume;
atmel_sha_fn_t cpu_transfer_complete;
@@ -198,7 +187,7 @@ static inline int atmel_sha_complete(struct atmel_sha_dev *dd, int err)
clk_disable(dd->iclk);
- if (dd->is_async && req->base.complete)
+ if ((dd->is_async || dd->force_complete) && req->base.complete)
req->base.complete(&req->base, err);
/* handle new request */
@@ -992,6 +981,7 @@ static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
dd->req = ahash_request_cast(async_req);
start_async = (dd->req != req);
dd->is_async = start_async;
+ dd->force_complete = false;
/* WARNING: ctx->start() MAY change dd->is_async. */
err = ctx->start(dd);
@@ -2100,6 +2090,332 @@ static struct ahash_alg sha_hmac_algs[] = {
},
};
+#ifdef CONFIG_CRYPTO_DEV_ATMEL_AUTHENC
+/* authenc functions */
+
+static int atmel_sha_authenc_init2(struct atmel_sha_dev *dd);
+static int atmel_sha_authenc_init_done(struct atmel_sha_dev *dd);
+static int atmel_sha_authenc_final_done(struct atmel_sha_dev *dd);
+
+
+struct atmel_sha_authenc_ctx {
+ struct crypto_ahash *tfm;
+};
+
+struct atmel_sha_authenc_reqctx {
+ struct atmel_sha_reqctx base;
+
+ atmel_aes_authenc_fn_t cb;
+ struct atmel_aes_dev *aes_dev;
+
+ /* _init() parameters. */
+ struct scatterlist *assoc;
+ u32 assoclen;
+ u32 textlen;
+
+ /* _final() parameters. */
+ u32 *digest;
+ unsigned int digestlen;
+};
+
+static void atmel_sha_authenc_complete(struct crypto_async_request *areq,
+ int err)
+{
+ struct ahash_request *req = areq->data;
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+
+ authctx->cb(authctx->aes_dev, err, authctx->base.dd->is_async);
+}
+
+static int atmel_sha_authenc_start(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ int err;
+
+ /*
+ * Force atmel_sha_complete() to call req->base.complete(), ie
+ * atmel_sha_authenc_complete(), which in turn calls authctx->cb().
+ */
+ dd->force_complete = true;
+
+ err = atmel_sha_hw_init(dd);
+ return authctx->cb(authctx->aes_dev, err, dd->is_async);
+}
+
+bool atmel_sha_authenc_is_ready(void)
+{
+ struct atmel_sha_ctx dummy;
+
+ dummy.dd = NULL;
+ return (atmel_sha_find_dev(&dummy) != NULL);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_is_ready);
+
+unsigned int atmel_sha_authenc_get_reqsize(void)
+{
+ return sizeof(struct atmel_sha_authenc_reqctx);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_get_reqsize);
+
+struct atmel_sha_authenc_ctx *atmel_sha_authenc_spawn(unsigned long mode)
+{
+ struct atmel_sha_authenc_ctx *auth;
+ struct crypto_ahash *tfm;
+ struct atmel_sha_ctx *tctx;
+ const char *name;
+ int err = -EINVAL;
+
+ switch (mode & SHA_FLAGS_MODE_MASK) {
+ case SHA_FLAGS_HMAC_SHA1:
+ name = "atmel-hmac-sha1";
+ break;
+
+ case SHA_FLAGS_HMAC_SHA224:
+ name = "atmel-hmac-sha224";
+ break;
+
+ case SHA_FLAGS_HMAC_SHA256:
+ name = "atmel-hmac-sha256";
+ break;
+
+ case SHA_FLAGS_HMAC_SHA384:
+ name = "atmel-hmac-sha384";
+ break;
+
+ case SHA_FLAGS_HMAC_SHA512:
+ name = "atmel-hmac-sha512";
+ break;
+
+ default:
+ goto error;
+ }
+
+ tfm = crypto_alloc_ahash(name,
+ CRYPTO_ALG_TYPE_AHASH,
+ CRYPTO_ALG_TYPE_AHASH_MASK);
+ if (IS_ERR(tfm)) {
+ err = PTR_ERR(tfm);
+ goto error;
+ }
+ tctx = crypto_ahash_ctx(tfm);
+ tctx->start = atmel_sha_authenc_start;
+ tctx->flags = mode;
+
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth) {
+ err = -ENOMEM;
+ goto err_free_ahash;
+ }
+ auth->tfm = tfm;
+
+ return auth;
+
+err_free_ahash:
+ crypto_free_ahash(tfm);
+error:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_spawn);
+
+void atmel_sha_authenc_free(struct atmel_sha_authenc_ctx *auth)
+{
+ if (auth)
+ crypto_free_ahash(auth->tfm);
+ kfree(auth);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_free);
+
+int atmel_sha_authenc_setkey(struct atmel_sha_authenc_ctx *auth,
+ const u8 *key, unsigned int keylen,
+ u32 *flags)
+{
+ struct crypto_ahash *tfm = auth->tfm;
+ int err;
+
+ crypto_ahash_clear_flags(tfm, CRYPTO_TFM_REQ_MASK);
+ crypto_ahash_set_flags(tfm, *flags & CRYPTO_TFM_REQ_MASK);
+ err = crypto_ahash_setkey(tfm, key, keylen);
+ *flags = crypto_ahash_get_flags(tfm);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_setkey);
+
+int atmel_sha_authenc_schedule(struct ahash_request *req,
+ struct atmel_sha_authenc_ctx *auth,
+ atmel_aes_authenc_fn_t cb,
+ struct atmel_aes_dev *aes_dev)
+{
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ struct atmel_sha_reqctx *ctx = &authctx->base;
+ struct crypto_ahash *tfm = auth->tfm;
+ struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct atmel_sha_dev *dd;
+
+ /* Reset request context (MUST be done first). */
+ memset(authctx, 0, sizeof(*authctx));
+
+ /* Get SHA device. */
+ dd = atmel_sha_find_dev(tctx);
+ if (!dd)
+ return cb(aes_dev, -ENODEV, false);
+
+ /* Init request context. */
+ ctx->dd = dd;
+ ctx->buflen = SHA_BUFFER_LEN;
+ authctx->cb = cb;
+ authctx->aes_dev = aes_dev;
+ ahash_request_set_tfm(req, tfm);
+ ahash_request_set_callback(req, 0, atmel_sha_authenc_complete, req);
+
+ return atmel_sha_handle_queue(dd, req);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_schedule);
+
+int atmel_sha_authenc_init(struct ahash_request *req,
+ struct scatterlist *assoc, unsigned int assoclen,
+ unsigned int textlen,
+ atmel_aes_authenc_fn_t cb,
+ struct atmel_aes_dev *aes_dev)
+{
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ struct atmel_sha_reqctx *ctx = &authctx->base;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ struct atmel_sha_dev *dd = ctx->dd;
+
+ if (unlikely(!IS_ALIGNED(assoclen, sizeof(u32))))
+ return atmel_sha_complete(dd, -EINVAL);
+
+ authctx->cb = cb;
+ authctx->aes_dev = aes_dev;
+ authctx->assoc = assoc;
+ authctx->assoclen = assoclen;
+ authctx->textlen = textlen;
+
+ ctx->flags = hmac->base.flags;
+ return atmel_sha_hmac_setup(dd, atmel_sha_authenc_init2);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_init);
+
+static int atmel_sha_authenc_init2(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ struct atmel_sha_reqctx *ctx = &authctx->base;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ size_t hs = ctx->hash_size;
+ size_t i, num_words = hs / sizeof(u32);
+ u32 mr, msg_size;
+
+ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV);
+ for (i = 0; i < num_words; ++i)
+ atmel_sha_write(dd, SHA_REG_DIN(i), hmac->ipad[i]);
+
+ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIEHV);
+ for (i = 0; i < num_words; ++i)
+ atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]);
+
+ mr = (SHA_MR_MODE_IDATAR0 |
+ SHA_MR_HMAC |
+ SHA_MR_DUALBUFF);
+ mr |= ctx->flags & SHA_FLAGS_ALGO_MASK;
+ atmel_sha_write(dd, SHA_MR, mr);
+
+ msg_size = authctx->assoclen + authctx->textlen;
+ atmel_sha_write(dd, SHA_MSR, msg_size);
+ atmel_sha_write(dd, SHA_BCR, msg_size);
+
+ atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
+
+ /* Process assoc data. */
+ return atmel_sha_cpu_start(dd, authctx->assoc, authctx->assoclen,
+ true, false,
+ atmel_sha_authenc_init_done);
+}
+
+static int atmel_sha_authenc_init_done(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+
+ return authctx->cb(authctx->aes_dev, 0, dd->is_async);
+}
+
+int atmel_sha_authenc_final(struct ahash_request *req,
+ u32 *digest, unsigned int digestlen,
+ atmel_aes_authenc_fn_t cb,
+ struct atmel_aes_dev *aes_dev)
+{
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ struct atmel_sha_reqctx *ctx = &authctx->base;
+ struct atmel_sha_dev *dd = ctx->dd;
+
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ case SHA_FLAGS_SHA1:
+ authctx->digestlen = SHA1_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA224:
+ authctx->digestlen = SHA224_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA256:
+ authctx->digestlen = SHA256_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA384:
+ authctx->digestlen = SHA384_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA512:
+ authctx->digestlen = SHA512_DIGEST_SIZE;
+ break;
+
+ default:
+ return atmel_sha_complete(dd, -EINVAL);
+ }
+ if (authctx->digestlen > digestlen)
+ authctx->digestlen = digestlen;
+
+ authctx->cb = cb;
+ authctx->aes_dev = aes_dev;
+ authctx->digest = digest;
+ return atmel_sha_wait_for_data_ready(dd,
+ atmel_sha_authenc_final_done);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_final);
+
+static int atmel_sha_authenc_final_done(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ size_t i, num_words = authctx->digestlen / sizeof(u32);
+
+ for (i = 0; i < num_words; ++i)
+ authctx->digest[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i));
+
+ return atmel_sha_complete(dd, 0);
+}
+
+void atmel_sha_authenc_abort(struct ahash_request *req)
+{
+ struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req);
+ struct atmel_sha_reqctx *ctx = &authctx->base;
+ struct atmel_sha_dev *dd = ctx->dd;
+
+ /* Prevent atmel_sha_complete() from calling req->base.complete(). */
+ dd->is_async = false;
+ dd->force_complete = false;
+ (void)atmel_sha_complete(dd, 0);
+}
+EXPORT_SYMBOL_GPL(atmel_sha_authenc_abort);
+
+#endif /* CONFIG_CRYPTO_DEV_ATMEL_AUTHENC */
+
+
static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
{
int i;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 12/12] crypto: atmel-sha: add verbose debug facilities to print hw register names
From: Cyrille Pitchen @ 2016-12-22 16:38 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
When VERBOSE_DEBUG is defined and SHA_FLAGS_DUMP_REG flag is set in
dd->flags, this patch prints the register names and values when performing
IO accesses.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha.c | 110 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 108 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index cc5294dbead4..22d0c0c118da 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -51,6 +51,7 @@
#define SHA_FLAGS_INIT BIT(4)
#define SHA_FLAGS_CPU BIT(5)
#define SHA_FLAGS_DMA_READY BIT(6)
+#define SHA_FLAGS_DUMP_REG BIT(7)
/* bits[11:8] are reserved. */
@@ -167,14 +168,118 @@ static struct atmel_sha_drv atmel_sha = {
.lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock),
};
+#ifdef VERBOSE_DEBUG
+static const char *atmel_sha_reg_name(u32 offset, char *tmp, size_t sz, bool wr)
+{
+ switch (offset) {
+ case SHA_CR:
+ return "CR";
+
+ case SHA_MR:
+ return "MR";
+
+ case SHA_IER:
+ return "IER";
+
+ case SHA_IDR:
+ return "IDR";
+
+ case SHA_IMR:
+ return "IMR";
+
+ case SHA_ISR:
+ return "ISR";
+
+ case SHA_MSR:
+ return "MSR";
+
+ case SHA_BCR:
+ return "BCR";
+
+ case SHA_REG_DIN(0):
+ case SHA_REG_DIN(1):
+ case SHA_REG_DIN(2):
+ case SHA_REG_DIN(3):
+ case SHA_REG_DIN(4):
+ case SHA_REG_DIN(5):
+ case SHA_REG_DIN(6):
+ case SHA_REG_DIN(7):
+ case SHA_REG_DIN(8):
+ case SHA_REG_DIN(9):
+ case SHA_REG_DIN(10):
+ case SHA_REG_DIN(11):
+ case SHA_REG_DIN(12):
+ case SHA_REG_DIN(13):
+ case SHA_REG_DIN(14):
+ case SHA_REG_DIN(15):
+ snprintf(tmp, sz, "IDATAR[%u]", (offset - SHA_REG_DIN(0)) >> 2);
+ break;
+
+ case SHA_REG_DIGEST(0):
+ case SHA_REG_DIGEST(1):
+ case SHA_REG_DIGEST(2):
+ case SHA_REG_DIGEST(3):
+ case SHA_REG_DIGEST(4):
+ case SHA_REG_DIGEST(5):
+ case SHA_REG_DIGEST(6):
+ case SHA_REG_DIGEST(7):
+ case SHA_REG_DIGEST(8):
+ case SHA_REG_DIGEST(9):
+ case SHA_REG_DIGEST(10):
+ case SHA_REG_DIGEST(11):
+ case SHA_REG_DIGEST(12):
+ case SHA_REG_DIGEST(13):
+ case SHA_REG_DIGEST(14):
+ case SHA_REG_DIGEST(15):
+ if (wr)
+ snprintf(tmp, sz, "IDATAR[%u]",
+ 16u + ((offset - SHA_REG_DIGEST(0)) >> 2));
+ else
+ snprintf(tmp, sz, "ODATAR[%u]",
+ (offset - SHA_REG_DIGEST(0)) >> 2);
+ break;
+
+ case SHA_HW_VERSION:
+ return "HWVER";
+
+ default:
+ snprintf(tmp, sz, "0x%02x", offset);
+ break;
+ }
+
+ return tmp;
+}
+
+#endif /* VERBOSE_DEBUG */
+
static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset)
{
- return readl_relaxed(dd->io_base + offset);
+ u32 value = readl_relaxed(dd->io_base + offset);
+
+#ifdef VERBOSE_DEBUG
+ if (dd->flags & SHA_FLAGS_DUMP_REG) {
+ char tmp[16];
+
+ dev_vdbg(dd->dev, "read 0x%08x from %s\n", value,
+ atmel_sha_reg_name(offset, tmp, sizeof(tmp), false));
+ }
+#endif /* VERBOSE_DEBUG */
+
+ return value;
}
static inline void atmel_sha_write(struct atmel_sha_dev *dd,
u32 offset, u32 value)
{
+#ifdef VERBOSE_DEBUG
+ if (dd->flags & SHA_FLAGS_DUMP_REG) {
+ char tmp[16];
+
+ dev_vdbg(dd->dev, "write 0x%08x into %s\n", value,
+ atmel_sha_reg_name(offset, tmp, sizeof(tmp), true));
+ }
+#endif /* VERBOSE_DEBUG */
+
writel_relaxed(value, dd->io_base + offset);
}
@@ -183,7 +288,8 @@ static inline int atmel_sha_complete(struct atmel_sha_dev *dd, int err)
struct ahash_request *req = dd->req;
dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
- SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
+ SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY |
+ SHA_FLAGS_DUMP_REG);
clk_disable(dd->iclk);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 09/12] crypto: atmel-sha: add support to hmac(shaX)
From: Cyrille Pitchen @ 2016-12-22 16:37 UTC (permalink / raw)
To: herbert, davem, nicolas.ferre
Cc: linux-crypto, linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <cover.1482424395.git.cyrille.pitchen@atmel.com>
This patch adds support to the hmac(shaX) algorithms.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/crypto/atmel-sha-regs.h | 4 +
drivers/crypto/atmel-sha.c | 598 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 601 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
index 8d62d31eda08..1b9f3d33079e 100644
--- a/drivers/crypto/atmel-sha-regs.h
+++ b/drivers/crypto/atmel-sha-regs.h
@@ -26,6 +26,7 @@
#define SHA_MR_ALGO_SHA384 (2 << 8)
#define SHA_MR_ALGO_SHA512 (3 << 8)
#define SHA_MR_ALGO_SHA224 (4 << 8)
+#define SHA_MR_HMAC (1 << 11)
#define SHA_MR_DUALBUFF (1 << 16)
#define SHA_IER 0x10
@@ -42,6 +43,9 @@
#define SHA_ISR_URAT_MR (0x2 << 12)
#define SHA_ISR_URAT_WO (0x5 << 12)
+#define SHA_MSR 0x20
+#define SHA_BCR 0x30
+
#define SHA_HW_VERSION 0xFC
#define SHA_TPR 0x108
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index a4fc60b67099..78c3c02e4483 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -51,13 +51,20 @@
#define SHA_FLAGS_CPU BIT(5)
#define SHA_FLAGS_DMA_READY BIT(6)
-/* bits[10:8] are reserved. */
+/* bits[11:8] are reserved. */
#define SHA_FLAGS_ALGO_MASK SHA_MR_ALGO_MASK
#define SHA_FLAGS_SHA1 SHA_MR_ALGO_SHA1
#define SHA_FLAGS_SHA256 SHA_MR_ALGO_SHA256
#define SHA_FLAGS_SHA384 SHA_MR_ALGO_SHA384
#define SHA_FLAGS_SHA512 SHA_MR_ALGO_SHA512
#define SHA_FLAGS_SHA224 SHA_MR_ALGO_SHA224
+#define SHA_FLAGS_HMAC SHA_MR_HMAC
+#define SHA_FLAGS_HMAC_SHA1 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA1)
+#define SHA_FLAGS_HMAC_SHA256 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA256)
+#define SHA_FLAGS_HMAC_SHA384 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA384)
+#define SHA_FLAGS_HMAC_SHA512 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA512)
+#define SHA_FLAGS_HMAC_SHA224 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA224)
+#define SHA_FLAGS_MODE_MASK (SHA_FLAGS_HMAC | SHA_FLAGS_ALGO_MASK)
#define SHA_FLAGS_FINUP BIT(16)
#define SHA_FLAGS_SG BIT(17)
@@ -67,8 +74,10 @@
#define SHA_FLAGS_IDATAR0 BIT(26)
#define SHA_FLAGS_WAIT_DATARDY BIT(27)
+#define SHA_OP_INIT 0
#define SHA_OP_UPDATE 1
#define SHA_OP_FINAL 2
+#define SHA_OP_DIGEST 3
#define SHA_BUFFER_LEN (PAGE_SIZE / 16)
@@ -80,6 +89,7 @@ struct atmel_sha_caps {
bool has_sha224;
bool has_sha_384_512;
bool has_uihv;
+ bool has_hmac;
};
struct atmel_sha_dev;
@@ -105,6 +115,7 @@ struct atmel_sha_reqctx {
unsigned int total; /* total request */
size_t block_size;
+ size_t hash_size;
u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
};
@@ -152,6 +163,8 @@ struct atmel_sha_dev {
struct atmel_sha_caps caps;
+ struct scatterlist tmp;
+
u32 hw_version;
};
@@ -1522,11 +1535,579 @@ static int atmel_sha_cpu_start(struct atmel_sha_dev *dd,
return atmel_sha_cpu_transfer(dd);
}
+static int atmel_sha_cpu_hash(struct atmel_sha_dev *dd,
+ const void *data, unsigned int datalen,
+ bool auto_padding,
+ atmel_sha_fn_t resume)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ u32 msglen = (auto_padding) ? datalen : 0;
+ u32 mr = SHA_MR_MODE_AUTO;
+
+ if (!(IS_ALIGNED(datalen, ctx->block_size) || auto_padding))
+ return atmel_sha_complete(dd, -EINVAL);
+
+ mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK);
+ atmel_sha_write(dd, SHA_MR, mr);
+ atmel_sha_write(dd, SHA_MSR, msglen);
+ atmel_sha_write(dd, SHA_BCR, msglen);
+ atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
+
+ sg_init_one(&dd->tmp, data, datalen);
+ return atmel_sha_cpu_start(dd, &dd->tmp, datalen, false, true, resume);
+}
+
+
+/* hmac functions */
+
+struct atmel_sha_hmac_key {
+ bool valid;
+ unsigned int keylen;
+ u8 buffer[SHA512_BLOCK_SIZE];
+ u8 *keydup;
+};
+
+static inline void atmel_sha_hmac_key_init(struct atmel_sha_hmac_key *hkey)
+{
+ memset(hkey, 0, sizeof(*hkey));
+}
+
+static inline void atmel_sha_hmac_key_release(struct atmel_sha_hmac_key *hkey)
+{
+ kfree(hkey->keydup);
+ memset(hkey, 0, sizeof(*hkey));
+}
+
+static inline int atmel_sha_hmac_key_set(struct atmel_sha_hmac_key *hkey,
+ const u8 *key,
+ unsigned int keylen)
+{
+ atmel_sha_hmac_key_release(hkey);
+
+ if (keylen > sizeof(hkey->buffer)) {
+ hkey->keydup = kmemdup(key, keylen, GFP_KERNEL);
+ if (!hkey->keydup)
+ return -ENOMEM;
+
+ } else {
+ memcpy(hkey->buffer, key, keylen);
+ }
+
+ hkey->valid = true;
+ hkey->keylen = keylen;
+ return 0;
+}
+
+static inline bool atmel_sha_hmac_key_get(const struct atmel_sha_hmac_key *hkey,
+ const u8 **key,
+ unsigned int *keylen)
+{
+ if (!hkey->valid)
+ return false;
+
+ *keylen = hkey->keylen;
+ *key = (hkey->keydup) ? hkey->keydup : hkey->buffer;
+ return true;
+}
+
+
+struct atmel_sha_hmac_ctx {
+ struct atmel_sha_ctx base;
+
+ struct atmel_sha_hmac_key hkey;
+ u32 ipad[SHA512_BLOCK_SIZE / sizeof(u32)];
+ u32 opad[SHA512_BLOCK_SIZE / sizeof(u32)];
+ atmel_sha_fn_t resume;
+};
+
+static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd,
+ atmel_sha_fn_t resume);
+static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd,
+ const u8 *key, unsigned int keylen);
+static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd);
+static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd);
+static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd);
+static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd);
+
+static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd);
+static int atmel_sha_hmac_final(struct atmel_sha_dev *dd);
+static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd);
+static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd);
+
+static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd,
+ atmel_sha_fn_t resume)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ unsigned int keylen;
+ const u8 *key;
+ size_t bs;
+
+ hmac->resume = resume;
+ switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
+ case SHA_FLAGS_SHA1:
+ ctx->block_size = SHA1_BLOCK_SIZE;
+ ctx->hash_size = SHA1_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA224:
+ ctx->block_size = SHA224_BLOCK_SIZE;
+ ctx->hash_size = SHA256_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA256:
+ ctx->block_size = SHA256_BLOCK_SIZE;
+ ctx->hash_size = SHA256_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA384:
+ ctx->block_size = SHA384_BLOCK_SIZE;
+ ctx->hash_size = SHA512_DIGEST_SIZE;
+ break;
+
+ case SHA_FLAGS_SHA512:
+ ctx->block_size = SHA512_BLOCK_SIZE;
+ ctx->hash_size = SHA512_DIGEST_SIZE;
+ break;
+
+ default:
+ return atmel_sha_complete(dd, -EINVAL);
+ }
+ bs = ctx->block_size;
+
+ if (likely(!atmel_sha_hmac_key_get(&hmac->hkey, &key, &keylen)))
+ return resume(dd);
+
+ /* Compute K' from K. */
+ if (unlikely(keylen > bs))
+ return atmel_sha_hmac_prehash_key(dd, key, keylen);
+
+ /* Prepare ipad. */
+ memcpy((u8 *)hmac->ipad, key, keylen);
+ memset((u8 *)hmac->ipad + keylen, 0, bs - keylen);
+ return atmel_sha_hmac_compute_ipad_hash(dd);
+}
+
+static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd,
+ const u8 *key, unsigned int keylen)
+{
+ return atmel_sha_cpu_hash(dd, key, keylen, true,
+ atmel_sha_hmac_prehash_key_done);
+}
+
+static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ size_t ds = crypto_ahash_digestsize(tfm);
+ size_t bs = ctx->block_size;
+ size_t i, num_words = ds / sizeof(u32);
+
+ /* Prepare ipad. */
+ for (i = 0; i < num_words; ++i)
+ hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i));
+ memset((u8 *)hmac->ipad + ds, 0, bs - ds);
+ return atmel_sha_hmac_compute_ipad_hash(dd);
+}
+
+static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ size_t bs = ctx->block_size;
+ size_t i, num_words = bs / sizeof(u32);
+
+ memcpy(hmac->opad, hmac->ipad, bs);
+ for (i = 0; i < num_words; ++i) {
+ hmac->ipad[i] ^= 0x36363636;
+ hmac->opad[i] ^= 0x5c5c5c5c;
+ }
+
+ return atmel_sha_cpu_hash(dd, hmac->ipad, bs, false,
+ atmel_sha_hmac_compute_opad_hash);
+}
+
+static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ size_t bs = ctx->block_size;
+ size_t hs = ctx->hash_size;
+ size_t i, num_words = hs / sizeof(u32);
+
+ for (i = 0; i < num_words; ++i)
+ hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i));
+ return atmel_sha_cpu_hash(dd, hmac->opad, bs, false,
+ atmel_sha_hmac_setup_done);
+}
+
+static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ size_t hs = ctx->hash_size;
+ size_t i, num_words = hs / sizeof(u32);
+
+ for (i = 0; i < num_words; ++i)
+ hmac->opad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i));
+ atmel_sha_hmac_key_release(&hmac->hkey);
+ return hmac->resume(dd);
+}
+
+static int atmel_sha_hmac_start(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ int err;
+
+ err = atmel_sha_hw_init(dd);
+ if (err)
+ return atmel_sha_complete(dd, err);
+
+ switch (ctx->op) {
+ case SHA_OP_INIT:
+ err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_init_done);
+ break;
+
+ case SHA_OP_UPDATE:
+ dd->resume = atmel_sha_done;
+ err = atmel_sha_update_req(dd);
+ break;
+
+ case SHA_OP_FINAL:
+ dd->resume = atmel_sha_hmac_final;
+ err = atmel_sha_final_req(dd);
+ break;
+
+ case SHA_OP_DIGEST:
+ err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_digest2);
+ break;
+
+ default:
+ return atmel_sha_complete(dd, -EINVAL);
+ }
+
+ return err;
+}
+
+static int atmel_sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+
+ if (atmel_sha_hmac_key_set(&hmac->hkey, key, keylen)) {
+ crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int atmel_sha_hmac_init(struct ahash_request *req)
+{
+ int err;
+
+ err = atmel_sha_init(req);
+ if (err)
+ return err;
+
+ return atmel_sha_enqueue(req, SHA_OP_INIT);
+}
+
+static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ size_t bs = ctx->block_size;
+ size_t hs = ctx->hash_size;
+
+ ctx->bufcnt = 0;
+ ctx->digcnt[0] = bs;
+ ctx->digcnt[1] = 0;
+ ctx->flags |= SHA_FLAGS_RESTORE;
+ memcpy(ctx->digest, hmac->ipad, hs);
+ return atmel_sha_complete(dd, 0);
+}
+
+static int atmel_sha_hmac_final(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ u32 *digest = (u32 *)ctx->digest;
+ size_t ds = crypto_ahash_digestsize(tfm);
+ size_t bs = ctx->block_size;
+ size_t hs = ctx->hash_size;
+ size_t i, num_words;
+ u32 mr;
+
+ /* Save d = SHA((K' + ipad) | msg). */
+ num_words = ds / sizeof(u32);
+ for (i = 0; i < num_words; ++i)
+ digest[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i));
+
+ /* Restore context to finish computing SHA((K' + opad) | d). */
+ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV);
+ num_words = hs / sizeof(u32);
+ for (i = 0; i < num_words; ++i)
+ atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]);
+
+ mr = SHA_MR_MODE_AUTO | SHA_MR_UIHV;
+ mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK);
+ atmel_sha_write(dd, SHA_MR, mr);
+ atmel_sha_write(dd, SHA_MSR, bs + ds);
+ atmel_sha_write(dd, SHA_BCR, ds);
+ atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
+
+ sg_init_one(&dd->tmp, digest, ds);
+ return atmel_sha_cpu_start(dd, &dd->tmp, ds, false, true,
+ atmel_sha_hmac_final_done);
+}
+
+static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd)
+{
+ /*
+ * req->result might not be sizeof(u32) aligned, so copy the
+ * digest into ctx->digest[] before memcpy() the data into
+ * req->result.
+ */
+ atmel_sha_copy_hash(dd->req);
+ atmel_sha_copy_ready_hash(dd->req);
+ return atmel_sha_complete(dd, 0);
+}
+
+static int atmel_sha_hmac_digest(struct ahash_request *req)
+{
+ int err;
+
+ err = atmel_sha_init(req);
+ if (err)
+ return err;
+
+ return atmel_sha_enqueue(req, SHA_OP_DIGEST);
+}
+
+static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd)
+{
+ struct ahash_request *req = dd->req;
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm);
+ size_t hs = ctx->hash_size;
+ size_t i, num_words = hs / sizeof(u32);
+ bool use_dma = false;
+ u32 mr;
+
+ /* Special case for empty message. */
+ if (!req->nbytes)
+ return atmel_sha_complete(dd, -EINVAL); // TODO:
+
+ /* Check DMA threshold and alignment. */
+ if (req->nbytes > ATMEL_SHA_DMA_THRESHOLD &&
+ atmel_sha_dma_check_aligned(dd, req->src, req->nbytes))
+ use_dma = true;
+
+ /* Write both initial hash values to compute a HMAC. */
+ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV);
+ for (i = 0; i < num_words; ++i)
+ atmel_sha_write(dd, SHA_REG_DIN(i), hmac->ipad[i]);
+
+ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIEHV);
+ for (i = 0; i < num_words; ++i)
+ atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]);
+
+ /* Write the Mode, Message Size, Bytes Count then Control Registers. */
+ mr = (SHA_MR_HMAC | SHA_MR_DUALBUFF);
+ mr |= ctx->flags & SHA_FLAGS_ALGO_MASK;
+ if (use_dma)
+ mr |= SHA_MR_MODE_IDATAR0;
+ else
+ mr |= SHA_MR_MODE_AUTO;
+ atmel_sha_write(dd, SHA_MR, mr);
+
+ atmel_sha_write(dd, SHA_MSR, req->nbytes);
+ atmel_sha_write(dd, SHA_BCR, req->nbytes);
+
+ atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
+
+ /* Process data. */
+ if (use_dma)
+ return atmel_sha_dma_start(dd, req->src, req->nbytes,
+ atmel_sha_hmac_final_done);
+
+ return atmel_sha_cpu_start(dd, req->src, req->nbytes, false, true,
+ atmel_sha_hmac_final_done);
+}
+
+static int atmel_sha_hmac_cra_init(struct crypto_tfm *tfm)
+{
+ struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm);
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct atmel_sha_reqctx));
+ hmac->base.start = atmel_sha_hmac_start;
+ atmel_sha_hmac_key_init(&hmac->hkey);
+
+ return 0;
+}
+
+static void atmel_sha_hmac_cra_exit(struct crypto_tfm *tfm)
+{
+ struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm);
+
+ atmel_sha_hmac_key_release(&hmac->hkey);
+}
+
+static struct ahash_alg sha_hmac_algs[] = {
+{
+ .init = atmel_sha_hmac_init,
+ .update = atmel_sha_update,
+ .final = atmel_sha_final,
+ .digest = atmel_sha_hmac_digest,
+ .setkey = atmel_sha_hmac_setkey,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
+ .base = {
+ .cra_name = "hmac(sha1)",
+ .cra_driver_name = "atmel-hmac-sha1",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_sha_hmac_cra_init,
+ .cra_exit = atmel_sha_hmac_cra_exit,
+ }
+ }
+},
+{
+ .init = atmel_sha_hmac_init,
+ .update = atmel_sha_update,
+ .final = atmel_sha_final,
+ .digest = atmel_sha_hmac_digest,
+ .setkey = atmel_sha_hmac_setkey,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
+ .halg = {
+ .digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
+ .base = {
+ .cra_name = "hmac(sha224)",
+ .cra_driver_name = "atmel-hmac-sha224",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_sha_hmac_cra_init,
+ .cra_exit = atmel_sha_hmac_cra_exit,
+ }
+ }
+},
+{
+ .init = atmel_sha_hmac_init,
+ .update = atmel_sha_update,
+ .final = atmel_sha_final,
+ .digest = atmel_sha_hmac_digest,
+ .setkey = atmel_sha_hmac_setkey,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
+ .base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "atmel-hmac-sha256",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_sha_hmac_cra_init,
+ .cra_exit = atmel_sha_hmac_cra_exit,
+ }
+ }
+},
+{
+ .init = atmel_sha_hmac_init,
+ .update = atmel_sha_update,
+ .final = atmel_sha_final,
+ .digest = atmel_sha_hmac_digest,
+ .setkey = atmel_sha_hmac_setkey,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
+ .halg = {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
+ .base = {
+ .cra_name = "hmac(sha384)",
+ .cra_driver_name = "atmel-hmac-sha384",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_sha_hmac_cra_init,
+ .cra_exit = atmel_sha_hmac_cra_exit,
+ }
+ }
+},
+{
+ .init = atmel_sha_hmac_init,
+ .update = atmel_sha_update,
+ .final = atmel_sha_final,
+ .digest = atmel_sha_hmac_digest,
+ .setkey = atmel_sha_hmac_setkey,
+ .export = atmel_sha_export,
+ .import = atmel_sha_import,
+ .halg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct atmel_sha_reqctx),
+ .base = {
+ .cra_name = "hmac(sha512)",
+ .cra_driver_name = "atmel-hmac-sha512",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_sha_hmac_cra_init,
+ .cra_exit = atmel_sha_hmac_cra_exit,
+ }
+ }
+},
+};
static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
{
int i;
+ if (dd->caps.has_hmac)
+ for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++)
+ crypto_unregister_ahash(&sha_hmac_algs[i]);
+
for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++)
crypto_unregister_ahash(&sha_1_256_algs[i]);
@@ -1563,8 +2144,21 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
}
}
+ if (dd->caps.has_hmac) {
+ for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) {
+ err = crypto_register_ahash(&sha_hmac_algs[i]);
+ if (err)
+ goto err_sha_hmac_algs;
+ }
+ }
+
return 0;
+ /*i = ARRAY_SIZE(sha_hmac_algs);*/
+err_sha_hmac_algs:
+ for (j = 0; j < i; j++)
+ crypto_unregister_ahash(&sha_hmac_algs[j]);
+ i = ARRAY_SIZE(sha_384_512_algs);
err_sha_384_512_algs:
for (j = 0; j < i; j++)
crypto_unregister_ahash(&sha_384_512_algs[j]);
@@ -1634,6 +2228,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
dd->caps.has_sha224 = 0;
dd->caps.has_sha_384_512 = 0;
dd->caps.has_uihv = 0;
+ dd->caps.has_hmac = 0;
/* keep only major version number */
switch (dd->hw_version & 0xff0) {
@@ -1643,6 +2238,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
dd->caps.has_sha224 = 1;
dd->caps.has_sha_384_512 = 1;
dd->caps.has_uihv = 1;
+ dd->caps.has_hmac = 1;
break;
case 0x420:
dd->caps.has_dma = 1;
--
2.7.4
^ permalink raw reply related
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Andy Lutomirski @ 2016-12-22 16:53 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: Hannes Frederic Sowa, Daniel Borkmann, Alexei Starovoitov,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <CAHmME9pvPXiBu5TUYJL7gED7b=iXKrkXu45fXstnBFe77Esv5Q@mail.gmail.com>
On Thu, Dec 22, 2016 at 8:28 AM, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> Hi all,
>
> I don't know what your design requirements are for this. It looks like
> you're generating some kind of crypto digest of a program, and you
> need to avoid collisions. If you'd like to go with a PRF (keyed hash
> function) that uses some kernel secret key, then I'd strongly suggest
> using Keyed-Blake2. Alternatively, if you need for userspace to be
> able to calculate the same hash, and don't want to use some kernel
> secret, then I'd still suggest using Blake2, which will be fast and
> secure.
>
> If you can wait until January, I'll work on a commit adding the
> primitive to the tree. I've already written it and I just need to get
> things cleaned up.
>
>> Blake2 is both less stable (didn't they slightly change it recently?)
>
> No, Blake2 is very stable. It's also extremely secure and has been
> extensively studied. Not to mention it's faster than SHA2. And if you
> want to use it as a PRF, it's obvious better suited and faster to use
> Blake2's keyed PRF mode than HMAC-SHA2.
>
> If you don't care about performance, and you don't want to use a PRF,
> then just use SHA2-256. If you're particularly concerned about certain
> types of attacks, you could go with SHA2-512 truncated to 256 bytes,
> but somehow I doubt you need this.
I don't think this cares about performance. (Well, it cares about
performance, but the verifier will likely dominiate the cost by such a
large margin that the hash algo doesn't matter.) And staying
FIPS-compliant-ish is worth a little bit, so I'd advocate for
something in the SHA2 family.
> If userspace hasn't landed, can we get away with changing this code
> after 4.10? Or should we just fix it before 4.10? Or should we revert
> it before 4.10? Development-policy-things like this I have zero clue
> about, so I heed to your guidance.
I think it should be fixed or reverted before 4.10.
--Andy
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Hannes Frederic Sowa @ 2016-12-22 16:59 UTC (permalink / raw)
To: Andy Lutomirski, Daniel Borkmann, Alexei Starovoitov
Cc: Jason A. Donenfeld, kernel-hardening@lists.openwall.com,
Theodore Ts'o, Netdev, LKML, Linux Crypto Mailing List,
David Laight, Eric Dumazet, Linus Torvalds, Eric Biggers,
Tom Herbert, Andi Kleen, David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <CALCETrUATPeaCJTQZN2h=ct6HH-xLt4V8T0PfPHNFGFN2HWtTA@mail.gmail.com>
On Thu, 2016-12-22 at 08:07 -0800, Andy Lutomirski wrote:
> On Thu, Dec 22, 2016 at 7:51 AM, Hannes Frederic Sowa
> <hannes@stressinduktion.org> wrote:
> > On Thu, 2016-12-22 at 16:41 +0100, Jason A. Donenfeld wrote:
> > > Hi Hannes,
> > >
> > > On Thu, Dec 22, 2016 at 4:33 PM, Hannes Frederic Sowa
> > > <hannes@stressinduktion.org> wrote:
> > > > IPv6 you cannot touch anymore. The hashing algorithm is part of uAPI.
> > > > You don't want to give people new IPv6 addresses with the same stable
> > > > secret (across reboots) after a kernel upgrade. Maybe they lose
> > > > connectivity then and it is extra work?
> > >
> > > Ahh, too bad. So it goes.
> >
> > If no other users survive we can put it into the ipv6 module.
> >
> > > > The bpf hash stuff can be changed during this merge window, as it is
> > > > not yet in a released kernel. Albeit I would probably have preferred
> > > > something like sha256 here, which can be easily replicated by user
> > > > space tools (minus the problem of patching out references to not
> > > > hashable data, which must be zeroed).
> > >
> > > Oh, interesting, so time is of the essence then. Do you want to handle
> > > changing the new eBPF code to something not-SHA1 before it's too late,
> > > as part of a ne
>
> w patchset that can fast track itself to David? And
> > > then I can preserve my large series for the next merge window.
> >
> > This algorithm should be a non-seeded algorithm, because the hashes
> > should be stable and verifiable by user space tooling. Thus this would
> > need a hashing algorithm that is hardened against pre-image
> > attacks/collision resistance, which siphash is not. I would prefer some
> > higher order SHA algorithm for that actually.
> >
>
> You mean:
>
> commit 7bd509e311f408f7a5132fcdde2069af65fa05ae
> Author: Daniel Borkmann <daniel@iogearbox.net>
> Date: Sun Dec 4 23:19:41 2016 +0100
>
> bpf: add prog_digest and expose it via fdinfo/netlink
>
>
> Yes, please! This actually matters for security -- imagine a
> malicious program brute-forcing a collision so that it gets loaded
> wrong. And this is IMO a use case for SHA-256 or SHA-512/256
> (preferably the latter). Speed basically doesn't matter here and
> Blake2 is both less stable (didn't they slightly change it recently?)
> and much less well studied.
We don't prevent ebpf programs being loaded based on the digest but
just to uniquely identify loaded programs from user space and match up
with their source.
There have been talks about signing bpf programs, thus this would
probably need another digest algorithm additionally to that one,
wasting probably instructions. Probably going somewhere in direction of
PKCS#7 might be the thing to do (which leads to the problem to make
PKCS#7 attackable by ordinary unpriv users, hmpf).
> My inclination would have been to seed them with something that isn't
> exposed to userspace for the precise reason that it would prevent user
> code from making assumptions about what's in the hash. But if there's
> a use case for why user code needs to be able to calculate the hash on
> its own, then that's fine. But perhaps the actual fdinfo string
> should be "sha256:abcd1234..." to give some flexibility down the road.
>
> Also:
>
> + result = (__force __be32 *)fp->digest;
> + for (i = 0; i < SHA_DIGEST_WORDS; i++)
> + result[i] = cpu_to_be32(fp->digest[i]);
>
> Everyone, please, please, please don't open-code crypto primitives.
> Is this and the code above it even correct? It might be but on a very
> brief glance it looks wrong to me. If you're doing this to avoid
> depending on crypto, then fix crypto so you can pull in the algorithm
> without pulling in the whole crypto core.
The hashing is not a proper sha1 neither, unfortunately. I think that
is why it will have a custom implementation in iproute2?
I wondered if bpf program loading should have used the module loading
infrastructure from the beginning...
> At the very least, there should be a separate function that calculates
> the hash of a buffer and that function should explicitly run itself
> against test vectors of various lengths to make sure that it's
> calculating what it claims to be calculating. And it doesn't look
> like the userspace code has landed, so, if this thing isn't
> calculating SHA1 correctly, it's plausible that no one has noticed.
I hope this was known from the beginning, this is not sha1 unfortunately.
But ebpf elf programs also need preprocessing to get rid of some
embedded load-depending data, so maybe it was considered to be just
enough?
Bye,
Hannes
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Andy Lutomirski @ 2016-12-22 17:25 UTC (permalink / raw)
To: Hannes Frederic Sowa
Cc: Daniel Borkmann, Alexei Starovoitov, Jason A. Donenfeld,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <1482425969.2673.5.camel@stressinduktion.org>
On Thu, Dec 22, 2016 at 8:59 AM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> On Thu, 2016-12-22 at 08:07 -0800, Andy Lutomirski wrote:
>> On Thu, Dec 22, 2016 at 7:51 AM, Hannes Frederic Sowa
>> <hannes@stressinduktion.org> wrote:
>> > On Thu, 2016-12-22 at 16:41 +0100, Jason A. Donenfeld wrote:
>> > > Hi Hannes,
>> > >
>> > > On Thu, Dec 22, 2016 at 4:33 PM, Hannes Frederic Sowa
>> > > <hannes@stressinduktion.org> wrote:
>> > > > IPv6 you cannot touch anymore. The hashing algorithm is part of uAPI.
>> > > > You don't want to give people new IPv6 addresses with the same stable
>> > > > secret (across reboots) after a kernel upgrade. Maybe they lose
>> > > > connectivity then and it is extra work?
>> > >
>> > > Ahh, too bad. So it goes.
>> >
>> > If no other users survive we can put it into the ipv6 module.
>> >
>> > > > The bpf hash stuff can be changed during this merge window, as it is
>> > > > not yet in a released kernel. Albeit I would probably have preferred
>> > > > something like sha256 here, which can be easily replicated by user
>> > > > space tools (minus the problem of patching out references to not
>> > > > hashable data, which must be zeroed).
>> > >
>> > > Oh, interesting, so time is of the essence then. Do you want to handle
>> > > changing the new eBPF code to something not-SHA1 before it's too late,
>> > > as part of a ne
>>
>> w patchset that can fast track itself to David? And
>> > > then I can preserve my large series for the next merge window.
>> >
>> > This algorithm should be a non-seeded algorithm, because the hashes
>> > should be stable and verifiable by user space tooling. Thus this would
>> > need a hashing algorithm that is hardened against pre-image
>> > attacks/collision resistance, which siphash is not. I would prefer some
>> > higher order SHA algorithm for that actually.
>> >
>>
>> You mean:
>>
>> commit 7bd509e311f408f7a5132fcdde2069af65fa05ae
>> Author: Daniel Borkmann <daniel@iogearbox.net>
>> Date: Sun Dec 4 23:19:41 2016 +0100
>>
>> bpf: add prog_digest and expose it via fdinfo/netlink
>>
>>
>> Yes, please! This actually matters for security -- imagine a
>> malicious program brute-forcing a collision so that it gets loaded
>> wrong. And this is IMO a use case for SHA-256 or SHA-512/256
>> (preferably the latter). Speed basically doesn't matter here and
>> Blake2 is both less stable (didn't they slightly change it recently?)
>> and much less well studied.
>
> We don't prevent ebpf programs being loaded based on the digest but
> just to uniquely identify loaded programs from user space and match up
> with their source.
The commit log talks about using the hash to see if the program has
already been compiled and JITted. If that's done, then a collision
will directly cause the kernel to malfunction.
>> My inclination would have been to seed them with something that isn't
>> exposed to userspace for the precise reason that it would prevent user
>> code from making assumptions about what's in the hash. But if there's
>> a use case for why user code needs to be able to calculate the hash on
>> its own, then that's fine. But perhaps the actual fdinfo string
>> should be "sha256:abcd1234..." to give some flexibility down the road.
>>
>> Also:
>>
>> + result = (__force __be32 *)fp->digest;
>> + for (i = 0; i < SHA_DIGEST_WORDS; i++)
>> + result[i] = cpu_to_be32(fp->digest[i]);
>>
>> Everyone, please, please, please don't open-code crypto primitives.
>> Is this and the code above it even correct? It might be but on a very
>> brief glance it looks wrong to me. If you're doing this to avoid
>> depending on crypto, then fix crypto so you can pull in the algorithm
>> without pulling in the whole crypto core.
>
> The hashing is not a proper sha1 neither, unfortunately. I think that
> is why it will have a custom implementation in iproute2?
Putting on crypto hat:
NAK NAK NAK NAK NAK. "The Linux kernel invented a new primitive in
2016 when people know better and is going to handle it by porting that
new primitive to userspace" is not a particularly good argument.
Okay, crypto hack back off.
>
> I wondered if bpf program loading should have used the module loading
> infrastructure from the beginning...
That would be way too complicated and would be nasty for the unprivileged cases.
>
>> At the very least, there should be a separate function that calculates
>> the hash of a buffer and that function should explicitly run itself
>> against test vectors of various lengths to make sure that it's
>> calculating what it claims to be calculating. And it doesn't look
>> like the userspace code has landed, so, if this thing isn't
>> calculating SHA1 correctly, it's plausible that no one has noticed.
>
> I hope this was known from the beginning, this is not sha1 unfortunately.
>
> But ebpf elf programs also need preprocessing to get rid of some
> embedded load-depending data, so maybe it was considered to be just
> enough?
I suspect it was actually an accident.
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Hannes Frederic Sowa @ 2016-12-22 17:49 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Daniel Borkmann, Alexei Starovoitov, Jason A. Donenfeld,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <CALCETrW_T1v4qKPJDs5dXwAnAit3M52AWMH-K+GJLb1WoLMuRQ@mail.gmail.com>
On Thu, 2016-12-22 at 09:25 -0800, Andy Lutomirski wrote:
> On Thu, Dec 22, 2016 at 8:59 AM, Hannes Frederic Sowa
> <hannes@stressinduktion.org> wrote:
> > On Thu, 2016-12-22 at 08:07 -0800, Andy Lutomirski wrote:
> > >
> > > You mean:
> > >
> > > commit 7bd509e311f408f7a5132fcdde2069af65fa05ae
> > > Author: Daniel Borkmann <daniel@iogearbox.net>
> > > Date: Sun Dec 4 23:19:41 2016 +0100
> > >
> > > bpf: add prog_digest and expose it via fdinfo/netlink
> > >
> > >
> > > Yes, please! This actually matters for security -- imagine a
> > > malicious program brute-forcing a collision so that it gets loaded
> > > wrong. And this is IMO a use case for SHA-256 or SHA-512/256
> > > (preferably the latter). Speed basically doesn't matter here and
> > > Blake2 is both less stable (didn't they slightly change it recently?)
> > > and much less well studied.
> >
> > We don't prevent ebpf programs being loaded based on the digest but
> > just to uniquely identify loaded programs from user space and match up
> > with their source.
>
> The commit log talks about using the hash to see if the program has
> already been compiled and JITted. If that's done, then a collision
> will directly cause the kernel to malfunction.
Yeah, it still shouldn't crash the kernel but it could cause
malfunctions because assumptions are not met from user space thus it
could act in a strange way:
My personal biggest concern is that users of this API will at some
point in time assume this digist is unique (as a key itself for a
hashtables f.e.), while it is actually not (and not enforced so by the
kernel). If you can get an unpriv ebpf program inserted to the kernel
with the same weak hash, a controller daemon could pick it up and bind
it to another ebpf hook, probably outside of the unpriv realm the user
was in before. Only the sorting matters, which might be unstable and is
not guaranteed by anything in most hash table based data structures.
The API seems flawed to me.
> > > My inclination would have been to seed them with something that isn't
> > > exposed to userspace for the precise reason that it would prevent user
> > > code from making assumptions about what's in the hash. But if there's
> > > a use case for why user code needs to be able to calculate the hash on
> > > its own, then that's fine. But perhaps the actual fdinfo string
> > > should be "sha256:abcd1234..." to give some flexibility down the road.
To add to this, I am very much in favor of that. Right now it doesn't
have a name because it is a custom algorithm. ;)
> > >
> > > Also:
> > >
> > > + result = (__force __be32 *)fp->digest;
> > > + for (i = 0; i < SHA_DIGEST_WORDS; i++)
> > > + result[i] = cpu_to_be32(fp->digest[i]);
> > >
> > > Everyone, please, please, please don't open-code crypto primitives.
> > > Is this and the code above it even correct? It might be but on a very
> > > brief glance it looks wrong to me. If you're doing this to avoid
> > > depending on crypto, then fix crypto so you can pull in the algorithm
> > > without pulling in the whole crypto core.
> >
> > The hashing is not a proper sha1 neither, unfortunately. I think that
> > is why it will have a custom implementation in iproute2?
>
> Putting on crypto hat:
>
> NAK NAK NAK NAK NAK. "The Linux kernel invented a new primitive in
> 2016 when people know better and is going to handle it by porting that
> new primitive to userspace" is not a particularly good argument.
>
> Okay, crypto hack back off.
>
> >
> > I wondered if bpf program loading should have used the module loading
> > infrastructure from the beginning...
>
> That would be way too complicated and would be nasty for the unprivileged cases.
I was more or less just thinking about using the syscalls and user
space representation not the generic infrastructure, as it is anyway
too much concerned with real kernel modules (would probably also solve
your cgroup-ebpf thread, as it can be passed by unique name or name and
hash ;) ). Anyway...
> > > At the very least, there should be a separate function that calculates
> > > the hash of a buffer and that function should explicitly run itself
> > > against test vectors of various lengths to make sure that it's
> > > calculating what it claims to be calculating. And it doesn't look
> > > like the userspace code has landed, so, if this thing isn't
> > > calculating SHA1 correctly, it's plausible that no one has noticed.
> >
> > I hope this was known from the beginning, this is not sha1 unfortunately.
> >
> > But ebpf elf programs also need preprocessing to get rid of some
> > embedded load-depending data, so maybe it was considered to be just
> > enough?
>
> I suspect it was actually an accident.
Maybe, I don't know.
Bye,
Hannes
^ permalink raw reply
* Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5
From: Hannes Frederic Sowa @ 2016-12-22 18:08 UTC (permalink / raw)
To: Theodore Ts'o, Jason A. Donenfeld, kernel-hardening,
Andy Lutomirski, Netdev, LKML, Linux Crypto Mailing List,
David Laight, Eric Dumazet, Linus Torvalds, Eric Biggers,
Tom Herbert, Andi Kleen, David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <20161222155447.u3ayvw4gmorhswjv@thunk.org>
On 22.12.2016 16:54, Theodore Ts'o wrote:
> On Thu, Dec 22, 2016 at 02:10:33PM +0100, Jason A. Donenfeld wrote:
>> On Thu, Dec 22, 2016 at 1:47 PM, Hannes Frederic Sowa
>> <hannes@stressinduktion.org> wrote:
>>> following up on what appears to be a random subject: ;)
>>>
>>> IIRC, ext4 code by default still uses half_md4 for hashing of filenames
>>> in the htree. siphash seems to fit this use case pretty good.
>>
>> I saw this too. I'll try to address it in v8 of this series.
>
> This is a separate issue, and this series is getting a bit too
> complex. So I'd suggest pushing this off to a separate change.
>
> Changing the htree hash algorithm is an on-disk format change, and so
> we couldn't roll it out until e2fsprogs gets updated and rolled out
> pretty broadley. In fact George sent me patches to add siphash as a
> hash algorithm for htree a while back (for both the kernel and
> e2fsprogs), but I never got around to testing and applying them,
> mainly because while it's technically faster, I had other higher
> priority issues to work on --- and see previous comments regarding
> pixel peeping. Improving the hash algorithm by tens or even hundreds
> of nanoseconds isn't really going to matter since we only do a htree
> lookup on a file creation or cold cache lookup, and the SSD or HDD I/O
> times will dominate. And from the power perspective, saving
> microwatts of CPU power isn't going to matter if you're going to be
> spinning up the storage device....
I wasn't concerned about performance but more about DoS resilience. I
wonder how safe half md4 actually is in terms of allowing users to
generate long hash chains in the filesystem (in terms of length
extension attacks against half_md4).
In ext4, is it actually possible that a "disrupter" learns about the
hashing secret in the way how the inodes are returned during getdents?
Thanks,
Hannes
^ permalink raw reply
* Re: Re: [PATCH v7 3/6] random: use SipHash in place of MD5
From: Jason A. Donenfeld @ 2016-12-22 18:13 UTC (permalink / raw)
To: Hannes Frederic Sowa
Cc: Theodore Ts'o, kernel-hardening, Andy Lutomirski, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <32db19ab-0c19-628c-3475-2ccb8050563a@stressinduktion.org>
On Thu, Dec 22, 2016 at 7:08 PM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> I wasn't concerned about performance but more about DoS resilience. I
> wonder how safe half md4 actually is in terms of allowing users to
> generate long hash chains in the filesystem (in terms of length
> extension attacks against half_md4).
AFAIK, this is a real vulnerability that needs to be addressed.
Judging by Ted's inquiry about my siphash testing suite, I assume he's
probably tinkering around with it as we speak. :)
Meanwhile I've separated things into several trees:
1. chacha20 rng, already submitted:
https://git.zx2c4.com/linux-dev/log/?h=random-next
2. md5 cleanup, not yet submitted:
https://git.zx2c4.com/linux-dev/log/?h=md5-cleanup
3. md4 cleanup, already submitted:
https://git.zx2c4.com/linux-dev/log/?h=ext4-next-md4-cleanup
4. siphash and networking, not yet submitted as a x/4 series:
https://git.zx2c4.com/linux-dev/log/?h=net-next-siphash
I'll submit (4) in a couple of days, waiting for any comments on the
existing patch-set.
Jason
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Jason A. Donenfeld @ 2016-12-22 18:19 UTC (permalink / raw)
To: Hannes Frederic Sowa
Cc: Andy Lutomirski, Daniel Borkmann, Alexei Starovoitov,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <1482425969.2673.5.camel@stressinduktion.org>
On Thu, Dec 22, 2016 at 5:59 PM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> We don't prevent ebpf programs being loaded based on the digest but
> just to uniquely identify loaded programs from user space and match up
> with their source.
Okay, so in that case, a weak hashing function like SHA1 could result
in a real vulnerability. Therefore, this SHA1 stuff needs to be
reverted immediately, pending a different implementation. If this has
ever shipped in a kernel version, it could even deserve a CVE. No
SHA1!
> The hashing is not a proper sha1 neither, unfortunately. I think that
> is why it will have a custom implementation in iproute2?
Jeepers creepers. So for some ungodly reason, LKML has invented yet
another homebrewed crypto primitive. This story really gets more
horrifying every day. No bueno.
So yea, let's revert and re-commit (repeal and replace? just
kidding...). Out with SHA-1, in with Blake2 or SHA2.
Jason
^ permalink raw reply
* Re: [PATCH v3 2/2] crypto: mediatek - add DT bindings documentation
From: Rob Herring @ 2016-12-22 18:41 UTC (permalink / raw)
To: Ryder Lee
Cc: Herbert Xu, David S. Miller, Matthias Brugger,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sean Wang,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Roy Luo,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-crypto-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1482114045-18716-3-git-send-email-ryder.lee-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
On Mon, Dec 19, 2016 at 10:20:45AM +0800, Ryder Lee wrote:
> Add DT bindings documentation for the crypto driver
>
> Signed-off-by: Ryder Lee <ryder.lee-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> ---
> .../devicetree/bindings/crypto/mediatek-crypto.txt | 27 ++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/crypto/mediatek-crypto.txt
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 11/12] crypto: atmel-authenc: add support to authenc(hmac(shaX),Y(aes)) modes
From: kbuild test robot @ 2016-12-22 18:49 UTC (permalink / raw)
To: Cyrille Pitchen
Cc: kbuild-all, herbert, davem, nicolas.ferre, linux-crypto,
linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <2bf61b215c2c0729a20017cd8aa02cf99c5ddb1a.1482422983.git.cyrille.pitchen@atmel.com>
[-- Attachment #1: Type: text/plain, Size: 1715 bytes --]
Hi Cyrille,
[auto build test ERROR on cryptodev/master]
[also build test ERROR on next-20161222]
[cannot apply to v4.9]
[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/Cyrille-Pitchen/crypto-atmel-authenc-add-support-to-authenc-hmac-shaX-Y-aes-modes/20161223-012130
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: i386-allmodconfig (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=i386
All error/warnings (new ones prefixed by >>):
warning: (CRYPTO_DEV_ATMEL_AUTHENC) selects CRYPTO_DEV_ATMEL_SHA which has unmet direct dependencies (CRYPTO && CRYPTO_HW && ARCH_AT91)
>> drivers/crypto/atmel-aes.c:44:27: fatal error: atmel-authenc.h: No such file or directory
#include "atmel-authenc.h"
^
compilation terminated.
--
>> drivers/crypto/atmel-sha.c:44:27: fatal error: atmel-authenc.h: No such file or directory
#include "atmel-authenc.h"
^
compilation terminated.
vim +44 drivers/crypto/atmel-aes.c
38 #include <crypto/aes.h>
39 #include <crypto/xts.h>
40 #include <crypto/internal/aead.h>
41 #include <linux/platform_data/crypto-atmel.h>
42 #include <dt-bindings/dma/at91.h>
43 #include "atmel-aes-regs.h"
> 44 #include "atmel-authenc.h"
45
46 #define ATMEL_AES_PRIORITY 300
47
---
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: 56834 bytes --]
^ permalink raw reply
* Re: George's crazy full state idea (Re: HalfSipHash Acceptable Usage)
From: George Spelvin @ 2016-12-22 19:24 UTC (permalink / raw)
To: luto, luto
Cc: ak, davem, David.Laight, djb, ebiggers3, eric.dumazet, hannes,
Jason, jeanphilippe.aumasson, kernel-hardening, linux-crypto,
linux-kernel, linux, netdev, tom, torvalds, tytso, vegard.nossum
In-Reply-To: <CALCETrUSM7KDNuVqh169241PNumJVOF5hrNQUq=k5Fnet6nSgA@mail.gmail.com>
> Having slept on this, I like it less. The problem is that a
> backtracking attacker doesn't just learn H(random seed || entropy_0 ||
> secret || ...) -- they learn the internal state of the hash function
> that generates that value. This probably breaks any attempt to apply
> security properties of the hash function. For example, the internal
> state could easily contain a whole bunch of prior outputs it in
> verbatim.
The problem is, anti-backtracing is in severe tension with your desire
to use unmodified SipHash.
First of all, I'd like to repeat that it isn't a design goal of the current
generator and isn't necessary.
The current generator just returns hash[0] from the MD5 state, then
leaves the state stored. The fact that it conceals earlier outputs is
an accident of the Davies-Meyer structure of md5_transform.
It isn't necessary, because every secret generated is stored unencrypted
for as long as it's of value. A few values are used for retransmit
backoffs and random MAC addresses. Those are revealed to the world as
soon as they're used.
Most values are used for ASLR. These address are of interest to an
attacker trying to mount a buffer-overflow attack, but that only lasts
as long as the process is running to receive buffers. After the process
exits, knowledge of its layout is worthless.
And this is stored as long as it's running in kernel-accessible data,
so storing a *second* copy in less conveniently kernel-accessible data
(the RNG state) doesn't make the situation any worse.
In addition to the above, if you're assuming a state capture, then
since we have (for necessary efficieny reasons) a negligible about of
fresh entropy, an attacker has the secret key and can predict *future*
outputs very easily.
Given that information, an attacker doesn't need to learn the layout of
vulnerable server X. If they have a buffer overflow, they can crash
the current instance and wait for a fresh image to be started (with a
known address space) to launch their attack at.
Kernel state capture attacks are a very unlikely attack, mostly because
it's a narrow target a hair's breadth away from the much more interesting
outright kernel compromise (attacker gains write access as well as read)
which renders all this fancy cryptanaysis moot.
Now, the main point: it's not likely to be solvable.
The problem with unmodified SipHash is that is has only 64 bits of
output. No mix-back mechanism can get around the fundamental problem
that that's too small to prevent a brute-force guessing attack. You need
wider mix-back. And getting more output from unmodified SipHash requires
more finalization rounds, which is expensive.
(Aside: 64 bits does have the advantage that it can't be brute-forced on
the attacked machine. It must be exfiltrated to the attacker, and the
solution returned to the attack code. But doing this is getting easier
all the time.)
Adding antibacktracking to SipHash is trivial: just add a Davies-Meyer
structure around its internal state. Remember the internal state before
hashing in the entropy and secret, generate the output, then add the
previous and final states together for storage.
This is a standard textbook construction, very cheap, and doesn't touch
the compression function which is the target of analysis and attacks,
but it requires poking around in SipHash's internal state. (And people
who read the textbooks without understanding them will get upset because
the textbooks all talk about using this construction with block ciphers,
and SipHash's compression function is not advertised as a block cipher.)
Alternative designs exist; you could extract additional output from
earlier rounds of SipHash, using the duplex sponge construction you
mentioned earlier. That output would be used for mixback purposes *only*,
so wouldn't affect the security proof of the "primary" output.
But this is also getting creative with SipHash's internals.
Now, you could use a completely *different* cryptographic primitive
to enforce one-way-ness, and apply SipHash as a strong output transform,
but that doesn't feel like good design, and is probably more expensive.
Finally, your discomfort about an attacker learning the internal state...
if an attacker knows the key and the input, they can construct the
internal state. Yes, we could discard the internal state and construct
a fresh one on the next call to get_random_int, but what are you going
to key it with? What are you going to feed it? What keeps *that*
internal state any more secret from an attacker than one that's explicitly
stored?
Keeping the internal state around is a cacheing optimization, that's all.
*If* you're assuming a state capture, the only thing secret from the
attacker is any fresh entropy collected between the time of capture
and the time of generation. Due to mandatory efficiency requirements,
this is very small.
I really think you're wishing for the impossible here.
A final note: although I'm disagreeing with you, thank you very much for
the informed discussion. Knowing that someone will read and think about
this message carefully has forced me to think it through carefully myself.
For example, clearly stating the concern over starting new processes
with predictable layout, and the limits on the fresh entropy supply,
has made me realize that there *is* a possible source: each exec()
is passed 128 bits from get_random_bytes in the AT_RANDOM element of
its auxv. Since get_random_int() accesses "current" anyway, we could
store some seed material there rather than using "pid". While this is
not fresh for each call to get_random_int, it *is* fresh for each new
address space whose layout is being randomized.
^ permalink raw reply
* Re: George's crazy full state idea (Re: HalfSipHash Acceptable Usage)
From: Andy Lutomirski @ 2016-12-22 19:32 UTC (permalink / raw)
To: George Spelvin
Cc: Andrew Lutomirski, Andi Kleen, David S. Miller, David Laight,
D. J. Bernstein, Eric Biggers, Eric Dumazet, Hannes Frederic Sowa,
Jason A. Donenfeld, Jean-Philippe Aumasson,
kernel-hardening@lists.openwall.com, Linux Crypto Mailing List,
linux-kernel@vger.kernel.org, Network Development, Tom Herbert,
Linus Torvalds, Ted Ts'o
In-Reply-To: <20161222192445.963.qmail@ns.sciencehorizons.net>
On Thu, Dec 22, 2016 at 11:24 AM, George Spelvin
<linux@sciencehorizons.net> wrote:
>> Having slept on this, I like it less. The problem is that a
>> backtracking attacker doesn't just learn H(random seed || entropy_0 ||
>> secret || ...) -- they learn the internal state of the hash function
>> that generates that value. This probably breaks any attempt to apply
>> security properties of the hash function. For example, the internal
>> state could easily contain a whole bunch of prior outputs it in
>> verbatim.
>
> The problem is, anti-backtracing is in severe tension with your desire
> to use unmodified SipHash.
>
> First of all, I'd like to repeat that it isn't a design goal of the current
> generator and isn't necessary.
Agreed.
> Now, the main point: it's not likely to be solvable.
>
> The problem with unmodified SipHash is that is has only 64 bits of
> output. No mix-back mechanism can get around the fundamental problem
> that that's too small to prevent a brute-force guessing attack. You need
> wider mix-back. And getting more output from unmodified SipHash requires
> more finalization rounds, which is expensive.
It could only mix the output back in every two calls, in which case
you can backtrack up to one call but you need to do 2^128 work to
backtrack farther. But yes, this is getting excessively complicated.
> Finally, your discomfort about an attacker learning the internal state...
> if an attacker knows the key and the input, they can construct the
> internal state. Yes, we could discard the internal state and construct
> a fresh one on the next call to get_random_int, but what are you going
> to key it with? What are you going to feed it? What keeps *that*
> internal state any more secret from an attacker than one that's explicitly
> stored?
I do tend to like Ted's version in which we use batched
get_random_bytes() output. If it's fast enough, it's simpler and lets
us get the full strength of a CSPRNG.
(Aside: some day I want to move all that code from drivers/ to lib/
and teach it to be buildable in userspace, too, so it's easy to play
with it, feed it test vectors, confirm that it's equivalent to a
reference implementation, write up the actual design and try to get
real cryptographers to analyze it, etc.)
> For example, clearly stating the concern over starting new processes
> with predictable layout, and the limits on the fresh entropy supply,
> has made me realize that there *is* a possible source: each exec()
> is passed 128 bits from get_random_bytes in the AT_RANDOM element of
> its auxv. Since get_random_int() accesses "current" anyway, we could
> store some seed material there rather than using "pid". While this is
> not fresh for each call to get_random_int, it *is* fresh for each new
> address space whose layout is being randomized.
Hmm, interesting. Although, for ASLR, we could use get_random_bytes()
directly and be done with it. It won't be a bottleneck.
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Alexei Starovoitov @ 2016-12-22 19:34 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Hannes Frederic Sowa, Daniel Borkmann, Jason A. Donenfeld,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <CALCETrW_T1v4qKPJDs5dXwAnAit3M52AWMH-K+GJLb1WoLMuRQ@mail.gmail.com>
On Thu, Dec 22, 2016 at 9:25 AM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Thu, Dec 22, 2016 at 8:59 AM, Hannes Frederic Sowa
> <hannes@stressinduktion.org> wrote:
>> On Thu, 2016-12-22 at 08:07 -0800, Andy Lutomirski wrote:
>>
>> We don't prevent ebpf programs being loaded based on the digest but
>> just to uniquely identify loaded programs from user space and match up
>> with their source.
>
> The commit log talks about using the hash to see if the program has
> already been compiled and JITted. If that's done, then a collision
> will directly cause the kernel to malfunction.
Andy, please read the code.
we could have used jhash there just as well.
Collisions are fine.
^ permalink raw reply
* Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5
From: Theodore Ts'o @ 2016-12-22 19:50 UTC (permalink / raw)
To: Hannes Frederic Sowa
Cc: Jason A. Donenfeld, kernel-hardening, Andy Lutomirski, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <32db19ab-0c19-628c-3475-2ccb8050563a@stressinduktion.org>
On Thu, Dec 22, 2016 at 07:08:37PM +0100, Hannes Frederic Sowa wrote:
> I wasn't concerned about performance but more about DoS resilience. I
> wonder how safe half md4 actually is in terms of allowing users to
> generate long hash chains in the filesystem (in terms of length
> extension attacks against half_md4).
>
> In ext4, is it actually possible that a "disrupter" learns about the
> hashing secret in the way how the inodes are returned during getdents?
They'd have to be a local user, who can execute telldir(3) --- in
which case there are plenty of other denial of service attacks one
could carry out that would be far more devastating.
It might also be an issue if the file system is exposed via NFS, but
again, there are so many other ways an attacker could DoS a NFS server
that I don't think of it as a much of a concern.
Keep in mind that worst someone can do is cause directory inserts to
fail with an ENOSPC, and there are plenty of other ways of doing that
--- such as consuming all of the blocks and inodes in the file system,
for example.
So it's a threat, but not a high priority one as far as I'm concerned.
And if this was a problem in actual practice, users could switch to
the TEA based hash, which should be far harder to attack, and
available today.
- Ted
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Andy Lutomirski @ 2016-12-22 19:56 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Hannes Frederic Sowa, Daniel Borkmann, Jason A. Donenfeld,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <CAADnVQ+memUT2zcc-wunP0QgWSLWpmnSJNRJZmfDdc+FBb=gEg@mail.gmail.com>
On Thu, Dec 22, 2016 at 11:34 AM, Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
> On Thu, Dec 22, 2016 at 9:25 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>> On Thu, Dec 22, 2016 at 8:59 AM, Hannes Frederic Sowa
>> <hannes@stressinduktion.org> wrote:
>>> On Thu, 2016-12-22 at 08:07 -0800, Andy Lutomirski wrote:
>>>
>>> We don't prevent ebpf programs being loaded based on the digest but
>>> just to uniquely identify loaded programs from user space and match up
>>> with their source.
>>
>> The commit log talks about using the hash to see if the program has
>> already been compiled and JITted. If that's done, then a collision
>> will directly cause the kernel to malfunction.
>
> Andy, please read the code.
> we could have used jhash there just as well.
> Collisions are fine.
There's relevant in the code to read yet AFAICS. The code exports it
via fdinfo, and userspace is expected to do something with it. The
commit message says:
When programs are pinned and retrieved by an ELF loader, the loader
can check the program's digest through fdinfo and compare it against
one that was generated over the ELF file's program section to see
if the program needs to be reloaded.
I assume this means that a userspace component is expected to compare
the digest of a loaded program to a digest of a program it wants to
load and to use the result of the comparison to decide whether the
programs are the same. If that's indeed the case (and it sure sounds
like it, and I fully expect CRIU to do very similar things when
support is added), then malicious collisions do matter.
It's also not quite clear to me why userspace needs to be able to
calculate the digest on its own. A bpf(BPF_CALC_PROGRAM_DIGEST)
command that takes a BPF program as input and hashes it would seem to
serve the same purpose, and that would allow the kernel to key the
digest and change the algorithm down the road without breaking things.
Regardless, adding a new hash algorithm that is almost-but-not-quite
SHA-1 and making it a stable interface to userspace is not a good
thing.
--Andy
^ permalink raw reply
* Re: BPF hash algo (Re: [kernel-hardening] Re: [PATCH v7 3/6] random: use SipHash in place of MD5)
From: Hannes Frederic Sowa @ 2016-12-22 20:02 UTC (permalink / raw)
To: Andy Lutomirski, Alexei Starovoitov
Cc: Daniel Borkmann, Jason A. Donenfeld,
kernel-hardening@lists.openwall.com, Theodore Ts'o, Netdev,
LKML, Linux Crypto Mailing List, David Laight, Eric Dumazet,
Linus Torvalds, Eric Biggers, Tom Herbert, Andi Kleen,
David S. Miller, Jean-Philippe Aumasson
In-Reply-To: <CALCETrUWw2m8k3b8ibOeN-7o9b+8MrnX4btUWqS188WSsLzDjg@mail.gmail.com>
On 22.12.2016 20:56, Andy Lutomirski wrote:
> It's also not quite clear to me why userspace needs to be able to
> calculate the digest on its own. A bpf(BPF_CALC_PROGRAM_DIGEST)
> command that takes a BPF program as input and hashes it would seem to
> serve the same purpose, and that would allow the kernel to key the
> digest and change the algorithm down the road without breaking things.
I think that people expect digests of BPF programs to be stable over
time and reboots.
^ permalink raw reply
* Re: [PATCH v2 11/12] crypto: atmel-authenc: add support to authenc(hmac(shaX),Y(aes)) modes
From: kbuild test robot @ 2016-12-22 21:10 UTC (permalink / raw)
To: Cyrille Pitchen
Cc: kbuild-all, herbert, davem, nicolas.ferre, linux-crypto,
linux-kernel, linux-arm-kernel, Cyrille Pitchen
In-Reply-To: <2a6cc4637621d2ef0d84754817128c43795cb022.1482424395.git.cyrille.pitchen@atmel.com>
[-- Attachment #1: Type: text/plain, Size: 18106 bytes --]
Hi Cyrille,
[auto build test WARNING on cryptodev/master]
[also build test WARNING on next-20161222]
[cannot apply to v4.9]
[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/Cyrille-Pitchen/crypto-atmel-authenc-add-support-to-authenc-hmac-shaX-Y-aes-modes/20161223-015820
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: alpha-allyesconfig (attached as .config)
compiler: alpha-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
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=alpha
All warnings (new ones prefixed by >>):
In file included from include/linux/printk.h:305:0,
from include/linux/kernel.h:13,
from drivers/crypto/atmel-sha.c:17:
drivers/crypto/atmel-sha.c: In function 'atmel_sha_xmit_cpu':
>> drivers/crypto/atmel-sha.c:465:19: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
>> drivers/crypto/atmel-sha.c:465:2: note: in expansion of macro 'dev_dbg'
dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
^~~~~~~
drivers/crypto/atmel-sha.c: In function 'atmel_sha_xmit_pdc':
drivers/crypto/atmel-sha.c:494:19: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
drivers/crypto/atmel-sha.c:494:2: note: in expansion of macro 'dev_dbg'
dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
^~~~~~~
drivers/crypto/atmel-sha.c: In function 'atmel_sha_xmit_dma':
drivers/crypto/atmel-sha.c:541:19: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
drivers/crypto/atmel-sha.c:541:2: note: in expansion of macro 'dev_dbg'
dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
^~~~~~~
drivers/crypto/atmel-sha.c: In function 'atmel_sha_xmit_dma_map':
>> drivers/crypto/atmel-sha.c:620:26: warning: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
^
In file included from include/linux/printk.h:305:0,
from include/linux/kernel.h:13,
from drivers/crypto/atmel-sha.c:17:
drivers/crypto/atmel-sha.c: In function 'atmel_sha_update_dma_slow':
drivers/crypto/atmel-sha.c:641:19: warning: format '%u' expects argument of type 'unsigned int', but argument 4 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
drivers/crypto/atmel-sha.c:641:2: note: in expansion of macro 'dev_dbg'
dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n",
^~~~~~~
drivers/crypto/atmel-sha.c: In function 'atmel_sha_update_dma_start':
drivers/crypto/atmel-sha.c:669:19: warning: format '%u' expects argument of type 'unsigned int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
drivers/crypto/atmel-sha.c:669:2: note: in expansion of macro 'dev_dbg'
dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n",
^~~~~~~
drivers/crypto/atmel-sha.c:711:27: warning: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_err(dd->dev, "dma %u bytes error\n",
^
In file included from include/linux/printk.h:305:0,
from include/linux/kernel.h:13,
from drivers/crypto/atmel-sha.c:17:
drivers/crypto/atmel-sha.c: In function 'atmel_sha_finish':
drivers/crypto/atmel-sha.c:891:19: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1],
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
drivers/crypto/atmel-sha.c:891:2: note: in expansion of macro 'dev_dbg'
dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1],
^~~~~~~
vim +465 drivers/crypto/atmel-sha.c
ebc82efa Nicolas Royer 2012-07-01 459 size_t length, int final)
ebc82efa Nicolas Royer 2012-07-01 460 {
ebc82efa Nicolas Royer 2012-07-01 461 struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
ebc82efa Nicolas Royer 2012-07-01 462 int count, len32;
ebc82efa Nicolas Royer 2012-07-01 463 const u32 *buffer = (const u32 *)buf;
ebc82efa Nicolas Royer 2012-07-01 464
d4905b38 Nicolas Royer 2013-02-20 @465 dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
d4905b38 Nicolas Royer 2013-02-20 466 ctx->digcnt[1], ctx->digcnt[0], length, final);
ebc82efa Nicolas Royer 2012-07-01 467
ebc82efa Nicolas Royer 2012-07-01 468 atmel_sha_write_ctrl(dd, 0);
ebc82efa Nicolas Royer 2012-07-01 469
ebc82efa Nicolas Royer 2012-07-01 470 /* should be non-zero before next lines to disable clocks later */
d4905b38 Nicolas Royer 2013-02-20 471 ctx->digcnt[0] += length;
d4905b38 Nicolas Royer 2013-02-20 472 if (ctx->digcnt[0] < length)
d4905b38 Nicolas Royer 2013-02-20 473 ctx->digcnt[1]++;
ebc82efa Nicolas Royer 2012-07-01 474
ebc82efa Nicolas Royer 2012-07-01 475 if (final)
ebc82efa Nicolas Royer 2012-07-01 476 dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
ebc82efa Nicolas Royer 2012-07-01 477
ebc82efa Nicolas Royer 2012-07-01 478 len32 = DIV_ROUND_UP(length, sizeof(u32));
ebc82efa Nicolas Royer 2012-07-01 479
ebc82efa Nicolas Royer 2012-07-01 480 dd->flags |= SHA_FLAGS_CPU;
ebc82efa Nicolas Royer 2012-07-01 481
ebc82efa Nicolas Royer 2012-07-01 482 for (count = 0; count < len32; count++)
ebc82efa Nicolas Royer 2012-07-01 483 atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]);
ebc82efa Nicolas Royer 2012-07-01 484
ebc82efa Nicolas Royer 2012-07-01 485 return -EINPROGRESS;
ebc82efa Nicolas Royer 2012-07-01 486 }
ebc82efa Nicolas Royer 2012-07-01 487
ebc82efa Nicolas Royer 2012-07-01 488 static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
ebc82efa Nicolas Royer 2012-07-01 489 size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
ebc82efa Nicolas Royer 2012-07-01 490 {
ebc82efa Nicolas Royer 2012-07-01 491 struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
ebc82efa Nicolas Royer 2012-07-01 492 int len32;
ebc82efa Nicolas Royer 2012-07-01 493
d4905b38 Nicolas Royer 2013-02-20 494 dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
d4905b38 Nicolas Royer 2013-02-20 495 ctx->digcnt[1], ctx->digcnt[0], length1, final);
ebc82efa Nicolas Royer 2012-07-01 496
ebc82efa Nicolas Royer 2012-07-01 497 len32 = DIV_ROUND_UP(length1, sizeof(u32));
ebc82efa Nicolas Royer 2012-07-01 498 atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
ebc82efa Nicolas Royer 2012-07-01 499 atmel_sha_write(dd, SHA_TPR, dma_addr1);
ebc82efa Nicolas Royer 2012-07-01 500 atmel_sha_write(dd, SHA_TCR, len32);
ebc82efa Nicolas Royer 2012-07-01 501
ebc82efa Nicolas Royer 2012-07-01 502 len32 = DIV_ROUND_UP(length2, sizeof(u32));
ebc82efa Nicolas Royer 2012-07-01 503 atmel_sha_write(dd, SHA_TNPR, dma_addr2);
ebc82efa Nicolas Royer 2012-07-01 504 atmel_sha_write(dd, SHA_TNCR, len32);
ebc82efa Nicolas Royer 2012-07-01 505
ebc82efa Nicolas Royer 2012-07-01 506 atmel_sha_write_ctrl(dd, 1);
ebc82efa Nicolas Royer 2012-07-01 507
ebc82efa Nicolas Royer 2012-07-01 508 /* should be non-zero before next lines to disable clocks later */
d4905b38 Nicolas Royer 2013-02-20 509 ctx->digcnt[0] += length1;
d4905b38 Nicolas Royer 2013-02-20 510 if (ctx->digcnt[0] < length1)
d4905b38 Nicolas Royer 2013-02-20 511 ctx->digcnt[1]++;
ebc82efa Nicolas Royer 2012-07-01 512
ebc82efa Nicolas Royer 2012-07-01 513 if (final)
ebc82efa Nicolas Royer 2012-07-01 514 dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
ebc82efa Nicolas Royer 2012-07-01 515
ebc82efa Nicolas Royer 2012-07-01 516 dd->flags |= SHA_FLAGS_DMA_ACTIVE;
ebc82efa Nicolas Royer 2012-07-01 517
ebc82efa Nicolas Royer 2012-07-01 518 /* Start DMA transfer */
ebc82efa Nicolas Royer 2012-07-01 519 atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN);
ebc82efa Nicolas Royer 2012-07-01 520
ebc82efa Nicolas Royer 2012-07-01 521 return -EINPROGRESS;
ebc82efa Nicolas Royer 2012-07-01 522 }
ebc82efa Nicolas Royer 2012-07-01 523
d4905b38 Nicolas Royer 2013-02-20 524 static void atmel_sha_dma_callback(void *data)
d4905b38 Nicolas Royer 2013-02-20 525 {
d4905b38 Nicolas Royer 2013-02-20 526 struct atmel_sha_dev *dd = data;
d4905b38 Nicolas Royer 2013-02-20 527
b48b114c Cyrille Pitchen 2016-12-22 528 dd->is_async = true;
b48b114c Cyrille Pitchen 2016-12-22 529
d4905b38 Nicolas Royer 2013-02-20 530 /* dma_lch_in - completed - wait DATRDY */
d4905b38 Nicolas Royer 2013-02-20 531 atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
d4905b38 Nicolas Royer 2013-02-20 532 }
d4905b38 Nicolas Royer 2013-02-20 533
d4905b38 Nicolas Royer 2013-02-20 534 static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
d4905b38 Nicolas Royer 2013-02-20 535 size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
d4905b38 Nicolas Royer 2013-02-20 536 {
d4905b38 Nicolas Royer 2013-02-20 537 struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
d4905b38 Nicolas Royer 2013-02-20 538 struct dma_async_tx_descriptor *in_desc;
d4905b38 Nicolas Royer 2013-02-20 539 struct scatterlist sg[2];
d4905b38 Nicolas Royer 2013-02-20 540
d4905b38 Nicolas Royer 2013-02-20 @541 dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
d4905b38 Nicolas Royer 2013-02-20 542 ctx->digcnt[1], ctx->digcnt[0], length1, final);
d4905b38 Nicolas Royer 2013-02-20 543
d4905b38 Nicolas Royer 2013-02-20 544 dd->dma_lch_in.dma_conf.src_maxburst = 16;
d4905b38 Nicolas Royer 2013-02-20 545 dd->dma_lch_in.dma_conf.dst_maxburst = 16;
d4905b38 Nicolas Royer 2013-02-20 546
d4905b38 Nicolas Royer 2013-02-20 547 dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
d4905b38 Nicolas Royer 2013-02-20 548
d4905b38 Nicolas Royer 2013-02-20 549 if (length2) {
d4905b38 Nicolas Royer 2013-02-20 550 sg_init_table(sg, 2);
d4905b38 Nicolas Royer 2013-02-20 551 sg_dma_address(&sg[0]) = dma_addr1;
d4905b38 Nicolas Royer 2013-02-20 552 sg_dma_len(&sg[0]) = length1;
d4905b38 Nicolas Royer 2013-02-20 553 sg_dma_address(&sg[1]) = dma_addr2;
d4905b38 Nicolas Royer 2013-02-20 554 sg_dma_len(&sg[1]) = length2;
d4905b38 Nicolas Royer 2013-02-20 555 in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2,
d4905b38 Nicolas Royer 2013-02-20 556 DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
d4905b38 Nicolas Royer 2013-02-20 557 } else {
d4905b38 Nicolas Royer 2013-02-20 558 sg_init_table(sg, 1);
d4905b38 Nicolas Royer 2013-02-20 559 sg_dma_address(&sg[0]) = dma_addr1;
d4905b38 Nicolas Royer 2013-02-20 560 sg_dma_len(&sg[0]) = length1;
d4905b38 Nicolas Royer 2013-02-20 561 in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1,
d4905b38 Nicolas Royer 2013-02-20 562 DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
d4905b38 Nicolas Royer 2013-02-20 563 }
d4905b38 Nicolas Royer 2013-02-20 564 if (!in_desc)
b48b114c Cyrille Pitchen 2016-12-22 565 atmel_sha_complete(dd, -EINVAL);
d4905b38 Nicolas Royer 2013-02-20 566
d4905b38 Nicolas Royer 2013-02-20 567 in_desc->callback = atmel_sha_dma_callback;
d4905b38 Nicolas Royer 2013-02-20 568 in_desc->callback_param = dd;
d4905b38 Nicolas Royer 2013-02-20 569
d4905b38 Nicolas Royer 2013-02-20 570 atmel_sha_write_ctrl(dd, 1);
d4905b38 Nicolas Royer 2013-02-20 571
d4905b38 Nicolas Royer 2013-02-20 572 /* should be non-zero before next lines to disable clocks later */
d4905b38 Nicolas Royer 2013-02-20 573 ctx->digcnt[0] += length1;
d4905b38 Nicolas Royer 2013-02-20 574 if (ctx->digcnt[0] < length1)
d4905b38 Nicolas Royer 2013-02-20 575 ctx->digcnt[1]++;
d4905b38 Nicolas Royer 2013-02-20 576
d4905b38 Nicolas Royer 2013-02-20 577 if (final)
d4905b38 Nicolas Royer 2013-02-20 578 dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
d4905b38 Nicolas Royer 2013-02-20 579
d4905b38 Nicolas Royer 2013-02-20 580 dd->flags |= SHA_FLAGS_DMA_ACTIVE;
d4905b38 Nicolas Royer 2013-02-20 581
d4905b38 Nicolas Royer 2013-02-20 582 /* Start DMA transfer */
d4905b38 Nicolas Royer 2013-02-20 583 dmaengine_submit(in_desc);
d4905b38 Nicolas Royer 2013-02-20 584 dma_async_issue_pending(dd->dma_lch_in.chan);
d4905b38 Nicolas Royer 2013-02-20 585
d4905b38 Nicolas Royer 2013-02-20 586 return -EINPROGRESS;
d4905b38 Nicolas Royer 2013-02-20 587 }
d4905b38 Nicolas Royer 2013-02-20 588
d4905b38 Nicolas Royer 2013-02-20 589 static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
d4905b38 Nicolas Royer 2013-02-20 590 size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
d4905b38 Nicolas Royer 2013-02-20 591 {
d4905b38 Nicolas Royer 2013-02-20 592 if (dd->caps.has_dma)
d4905b38 Nicolas Royer 2013-02-20 593 return atmel_sha_xmit_dma(dd, dma_addr1, length1,
d4905b38 Nicolas Royer 2013-02-20 594 dma_addr2, length2, final);
d4905b38 Nicolas Royer 2013-02-20 595 else
d4905b38 Nicolas Royer 2013-02-20 596 return atmel_sha_xmit_pdc(dd, dma_addr1, length1,
d4905b38 Nicolas Royer 2013-02-20 597 dma_addr2, length2, final);
d4905b38 Nicolas Royer 2013-02-20 598 }
d4905b38 Nicolas Royer 2013-02-20 599
ebc82efa Nicolas Royer 2012-07-01 600 static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
ebc82efa Nicolas Royer 2012-07-01 601 {
ebc82efa Nicolas Royer 2012-07-01 602 struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
ebc82efa Nicolas Royer 2012-07-01 603 int bufcnt;
ebc82efa Nicolas Royer 2012-07-01 604
ebc82efa Nicolas Royer 2012-07-01 605 atmel_sha_append_sg(ctx);
ebc82efa Nicolas Royer 2012-07-01 606 atmel_sha_fill_padding(ctx, 0);
ebc82efa Nicolas Royer 2012-07-01 607 bufcnt = ctx->bufcnt;
ebc82efa Nicolas Royer 2012-07-01 608 ctx->bufcnt = 0;
ebc82efa Nicolas Royer 2012-07-01 609
ebc82efa Nicolas Royer 2012-07-01 610 return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
ebc82efa Nicolas Royer 2012-07-01 611 }
ebc82efa Nicolas Royer 2012-07-01 612
ebc82efa Nicolas Royer 2012-07-01 613 static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
ebc82efa Nicolas Royer 2012-07-01 614 struct atmel_sha_reqctx *ctx,
ebc82efa Nicolas Royer 2012-07-01 615 size_t length, int final)
ebc82efa Nicolas Royer 2012-07-01 616 {
ebc82efa Nicolas Royer 2012-07-01 617 ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
d4905b38 Nicolas Royer 2013-02-20 618 ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
ebc82efa Nicolas Royer 2012-07-01 619 if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
ebc82efa Nicolas Royer 2012-07-01 @620 dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
d4905b38 Nicolas Royer 2013-02-20 621 ctx->block_size);
b48b114c Cyrille Pitchen 2016-12-22 622 atmel_sha_complete(dd, -EINVAL);
ebc82efa Nicolas Royer 2012-07-01 623 }
:::::: The code at line 465 was first introduced by commit
:::::: d4905b38d1f6b60761a6fd16f45ebd1fac8b6e1f crypto: atmel-sha - add support for latest release of the IP (0x410)
:::::: TO: Nicolas Royer <nicolas@eukrea.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: 47848 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox