Re: [PATCH v6 4/4] crypto: Add Allwinner Security System crypto accelerator

2015-04-02 Thread Corentin LABBE
Le 26/03/2015 19:31, Boris Brezillon a écrit :
> Hi Corentin,
> 
> Here is a quick review, there surely are a lot of other things I didn't
> spot.
> 
> On Mon, 16 Mar 2015 20:01:22 +0100
> LABBE Corentin  wrote:
> 
>> Add support for the Security System included in Allwinner SoC A20.
>> The Security System is a hardware cryptographic accelerator that support:
>> - MD5 and SHA1 hash algorithms
>> - AES block cipher in CBC mode with 128/196/256bits keys.
>> - DES and 3DES block cipher in CBC mode
>>
>> Signed-off-by: LABBE Corentin 
>> ---
> 
> [...]
> 
>> +static int sunxi_ss_cipher(struct ablkcipher_request *areq, u32 mode)
>> +{
>> +struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
>> +struct sunxi_tfm_ctx *op = crypto_ablkcipher_ctx(tfm);
>> +const char *cipher_type;
>> +struct sunxi_ss_ctx *ss = op->ss;
>> +
>> +if (areq->nbytes == 0)
>> +return 0;
>> +
>> +if (areq->info == NULL) {
>> +dev_err(ss->dev, "ERROR: Empty IV\n");
>> +return -EINVAL;
>> +}
>> +
>> +if (areq->src == NULL || areq->dst == NULL) {
>> +dev_err(ss->dev, "ERROR: Some SGs are NULL\n");
>> +return -EINVAL;
>> +}
>> +
>> +cipher_type = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
>> +
>> +if (strcmp("cbc(aes)", cipher_type) == 0) {
>> +mode |= SS_OP_AES | SS_CBC | SS_ENABLED | op->keymode;
>> +return sunxi_ss_aes_poll(areq, mode);
>> +}
>> +
>> +if (strcmp("cbc(des)", cipher_type) == 0) {
>> +mode |= SS_OP_DES | SS_CBC | SS_ENABLED | op->keymode;
>> +return sunxi_ss_des_poll(areq, mode);
>> +}
>> +
>> +if (strcmp("cbc(des3_ede)", cipher_type) == 0) {
>> +mode |= SS_OP_3DES | SS_CBC | SS_ENABLED | op->keymode;
>> +return sunxi_ss_des_poll(areq, mode);
>> +}
> 
> Hm, I'm not sure doing these string comparisons in the crypto operation
> path is a good idea.
> Moreover, you're doing 3 string comparisons, even though only one can
> be valid at a time (using 'else if' would have been a bit better).
> 
> Anyway, IMHO this function should be split into 3 functions, and
> referenced by your alg template definitions.
> Something like:
> 
> int sunxi_ss_xxx_encrypt(struct ablkcipher_request *areq)
> {
>   /* put your cipher specific intialization here */
> 
>   return sunxi_ss_xxx_poll(areq, SS_ENCRYPTION);
> }
> 
> int sunxi_ss_xxx_decrypt(struct ablkcipher_request *areq)
> {
>   /* put your cipher specific intialization here */
> 
>   return sunxi_ss_xxx_poll(areq, SS_DECRYPTION);
> }
> 

You are right, I have added more block mode, and that was added too much strcmp.
So splitting in simplier functions is good.

> 
>> +
>> +int sunxi_ss_cipher_init(struct crypto_tfm *tfm)
>> +{
>> +const char *name = crypto_tfm_alg_name(tfm);
>> +struct sunxi_tfm_ctx *op = crypto_tfm_ctx(tfm);
>> +struct crypto_alg *alg = tfm->__crt_alg;
>> +struct sunxi_ss_alg_template *algt;
>> +struct sunxi_ss_ctx *ss;
>> +
>> +memset(op, 0, sizeof(struct sunxi_tfm_ctx));
>> +
>> +algt = container_of(alg, struct sunxi_ss_alg_template, alg.crypto);
>> +ss = algt->ss;
>> +op->ss = algt->ss;
>> +
>> +/* fallback is needed only for DES/3DES */
>> +if (strcmp("cbc(des)", name) == 0 ||
>> +strcmp("cbc(des3_ede)", name) == 0) {
>> +op->fallback = crypto_alloc_ablkcipher(name, 0,
>> +CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
>> +if (IS_ERR(op->fallback)) {
>> +dev_err(ss->dev, "ERROR: allocating fallback algo %s\n",
>> +name);
>> +return PTR_ERR(op->fallback);
>> +}
>> +}
> 
> Ditto: just create a specific init function for the des case:
> 
> int sunxi_ss_cbc_des_init(struct crypto_tfm *tfm)
> {
>   sunxi_ss_cipher_init(tfm);
> 
>   op->fallback = crypto_alloc_ablkcipher(name, 0,
>   CRYPTO_ALG_ASYNC |
>   CRYPTO_ALG_NEED_FALLBACK);
>   if (IS_ERR(op->fallback)) {
>   dev_err(ss->dev, "ERROR: allocating fallback algo %s\n",
>   name);
>   return PTR_ERR(op->fallback);
>   }
> 
>   return 0;
> }
> 

Ok

> 
> [..]
> 
>> +/*
>> + * Optimized function for the case where we have only one SG,
>> + * so we can use kmap_atomic
>> + */
>> +static int sunxi_ss_aes_poll_atomic(struct ablkcipher_request *areq)
>> +{
>> +u32 spaces;
>> +struct scatterlist *in_sg = areq->src;
>> +struct scatterlist *out_sg = areq->dst;
>> +void *src_addr;
>> +void *dst_addr;
>> +unsigned int ileft = areq->nbytes;
>> +unsigned int oleft = areq->nbytes;
>> +unsigned int todo;
>> +u32 *src32;
>> +u32 *dst32;
>> +u32 rx_cnt = 32;
>> +u32 tx_cnt = 0;
>> +int i;
>> +struct crypto_ablkcipher *tfm = crypto_ablkciph

Re: [PATCH v6 4/4] crypto: Add Allwinner Security System crypto accelerator

2015-03-26 Thread Boris Brezillon
Hi Corentin,

Here is a quick review, there surely are a lot of other things I didn't
spot.

On Mon, 16 Mar 2015 20:01:22 +0100
LABBE Corentin  wrote:

> Add support for the Security System included in Allwinner SoC A20.
> The Security System is a hardware cryptographic accelerator that support:
> - MD5 and SHA1 hash algorithms
> - AES block cipher in CBC mode with 128/196/256bits keys.
> - DES and 3DES block cipher in CBC mode
> 
> Signed-off-by: LABBE Corentin 
> ---

[...]

> +static int sunxi_ss_cipher(struct ablkcipher_request *areq, u32 mode)
> +{
> + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
> + struct sunxi_tfm_ctx *op = crypto_ablkcipher_ctx(tfm);
> + const char *cipher_type;
> + struct sunxi_ss_ctx *ss = op->ss;
> +
> + if (areq->nbytes == 0)
> + return 0;
> +
> + if (areq->info == NULL) {
> + dev_err(ss->dev, "ERROR: Empty IV\n");
> + return -EINVAL;
> + }
> +
> + if (areq->src == NULL || areq->dst == NULL) {
> + dev_err(ss->dev, "ERROR: Some SGs are NULL\n");
> + return -EINVAL;
> + }
> +
> + cipher_type = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
> +
> + if (strcmp("cbc(aes)", cipher_type) == 0) {
> + mode |= SS_OP_AES | SS_CBC | SS_ENABLED | op->keymode;
> + return sunxi_ss_aes_poll(areq, mode);
> + }
> +
> + if (strcmp("cbc(des)", cipher_type) == 0) {
> + mode |= SS_OP_DES | SS_CBC | SS_ENABLED | op->keymode;
> + return sunxi_ss_des_poll(areq, mode);
> + }
> +
> + if (strcmp("cbc(des3_ede)", cipher_type) == 0) {
> + mode |= SS_OP_3DES | SS_CBC | SS_ENABLED | op->keymode;
> + return sunxi_ss_des_poll(areq, mode);
> + }

Hm, I'm not sure doing these string comparisons in the crypto operation
path is a good idea.
Moreover, you're doing 3 string comparisons, even though only one can
be valid at a time (using 'else if' would have been a bit better).

Anyway, IMHO this function should be split into 3 functions, and
referenced by your alg template definitions.
Something like:

int sunxi_ss_xxx_encrypt(struct ablkcipher_request *areq)
{
/* put your cipher specific intialization here */

return sunxi_ss_xxx_poll(areq, SS_ENCRYPTION);
}

int sunxi_ss_xxx_decrypt(struct ablkcipher_request *areq)
{
/* put your cipher specific intialization here */

return sunxi_ss_xxx_poll(areq, SS_DECRYPTION);
}


> +
> +int sunxi_ss_cipher_init(struct crypto_tfm *tfm)
> +{
> + const char *name = crypto_tfm_alg_name(tfm);
> + struct sunxi_tfm_ctx *op = crypto_tfm_ctx(tfm);
> + struct crypto_alg *alg = tfm->__crt_alg;
> + struct sunxi_ss_alg_template *algt;
> + struct sunxi_ss_ctx *ss;
> +
> + memset(op, 0, sizeof(struct sunxi_tfm_ctx));
> +
> + algt = container_of(alg, struct sunxi_ss_alg_template, alg.crypto);
> + ss = algt->ss;
> + op->ss = algt->ss;
> +
> + /* fallback is needed only for DES/3DES */
> + if (strcmp("cbc(des)", name) == 0 ||
> + strcmp("cbc(des3_ede)", name) == 0) {
> + op->fallback = crypto_alloc_ablkcipher(name, 0,
> + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
> + if (IS_ERR(op->fallback)) {
> + dev_err(ss->dev, "ERROR: allocating fallback algo %s\n",
> + name);
> + return PTR_ERR(op->fallback);
> + }
> + }

Ditto: just create a specific init function for the des case:

int sunxi_ss_cbc_des_init(struct crypto_tfm *tfm)
{
sunxi_ss_cipher_init(tfm);

op->fallback = crypto_alloc_ablkcipher(name, 0,
CRYPTO_ALG_ASYNC |
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(op->fallback)) {
dev_err(ss->dev, "ERROR: allocating fallback algo %s\n",
name);
return PTR_ERR(op->fallback);
}

return 0;
}


[..]

> +/*
> + * Optimized function for the case where we have only one SG,
> + * so we can use kmap_atomic
> + */
> +static int sunxi_ss_aes_poll_atomic(struct ablkcipher_request *areq)
> +{
> + u32 spaces;
> + struct scatterlist *in_sg = areq->src;
> + struct scatterlist *out_sg = areq->dst;
> + void *src_addr;
> + void *dst_addr;
> + unsigned int ileft = areq->nbytes;
> + unsigned int oleft = areq->nbytes;
> + unsigned int todo;
> + u32 *src32;
> + u32 *dst32;
> + u32 rx_cnt = 32;
> + u32 tx_cnt = 0;
> + int i;
> + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
> + struct sunxi_tfm_ctx *op = crypto_ablkcipher_ctx(tfm);
> + struct sunxi_ss_ctx *ss = op->ss;
> +
> + src_addr = kmap_atomic(sg_page(in_sg)) + in_sg->offset;
> + if (src_addr == NULL) {
> + dev_err(ss->dev, "kmap_atomic error for src SG\n");
> +  

[PATCH v6 4/4] crypto: Add Allwinner Security System crypto accelerator

2015-03-16 Thread LABBE Corentin
Add support for the Security System included in Allwinner SoC A20.
The Security System is a hardware cryptographic accelerator that support:
- MD5 and SHA1 hash algorithms
- AES block cipher in CBC mode with 128/196/256bits keys.
- DES and 3DES block cipher in CBC mode

Signed-off-by: LABBE Corentin 
---
 drivers/crypto/Kconfig|  17 ++
 drivers/crypto/Makefile   |   1 +
 drivers/crypto/sunxi-ss/Makefile  |   2 +
 drivers/crypto/sunxi-ss/sunxi-ss-cipher.c | 408 +
 drivers/crypto/sunxi-ss/sunxi-ss-core.c   | 339 +
 drivers/crypto/sunxi-ss/sunxi-ss-hash.c   | 475 ++
 drivers/crypto/sunxi-ss/sunxi-ss.h| 200 +
 7 files changed, 1442 insertions(+)
 create mode 100644 drivers/crypto/sunxi-ss/Makefile
 create mode 100644 drivers/crypto/sunxi-ss/sunxi-ss-cipher.c
 create mode 100644 drivers/crypto/sunxi-ss/sunxi-ss-core.c
 create mode 100644 drivers/crypto/sunxi-ss/sunxi-ss-hash.c
 create mode 100644 drivers/crypto/sunxi-ss/sunxi-ss.h

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 2fb0fdf..9ba9759 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -436,4 +436,21 @@ config CRYPTO_DEV_QCE
  hardware. To compile this driver as a module, choose M here. The
  module will be called qcrypto.
 
+config CRYPTO_DEV_SUNXI_SS
+   tristate "Support for Allwinner Security System cryptographic 
accelerator"
+   depends on ARCH_SUNXI
+   select CRYPTO_MD5
+   select CRYPTO_SHA1
+   select CRYPTO_AES
+   select CRYPTO_DES
+   select CRYPTO_BLKCIPHER
+   help
+ Some Allwinner SoC have a crypto accelerator named
+ Security System. Select this if you want to use it.
+ The Security System handle AES/DES/3DES ciphers in CBC mode
+ and SHA1 and MD5 hash algorithms.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunxi-ss.
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 3924f93..856545c 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
 obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/
 obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
+obj-$(CONFIG_CRYPTO_DEV_SUNXI_SS) += sunxi-ss/
diff --git a/drivers/crypto/sunxi-ss/Makefile b/drivers/crypto/sunxi-ss/Makefile
new file mode 100644
index 000..8bb287d
--- /dev/null
+++ b/drivers/crypto/sunxi-ss/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_SUNXI_SS) += sunxi-ss.o
+sunxi-ss-y += sunxi-ss-core.o sunxi-ss-hash.o sunxi-ss-cipher.o
diff --git a/drivers/crypto/sunxi-ss/sunxi-ss-cipher.c 
b/drivers/crypto/sunxi-ss/sunxi-ss-cipher.c
new file mode 100644
index 000..3ed0ad0
--- /dev/null
+++ b/drivers/crypto/sunxi-ss/sunxi-ss-cipher.c
@@ -0,0 +1,408 @@
+/*
+ * sunxi-ss-cipher.c - hardware cryptographic accelerator for Allwinner A20 SoC
+ *
+ * Copyright (C) 2013-2015 Corentin LABBE 
+ *
+ * This file add support for AES cipher with 128,192,256 bits
+ * keysize in CBC mode.
+ * Add support also for DES and 3DES in CBC mode.
+ *
+ * You could find the datasheet in Documentation/arm/sunxi/README
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "sunxi-ss.h"
+
+static int sunxi_ss_cipher(struct ablkcipher_request *areq, u32 mode)
+{
+   struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
+   struct sunxi_tfm_ctx *op = crypto_ablkcipher_ctx(tfm);
+   const char *cipher_type;
+   struct sunxi_ss_ctx *ss = op->ss;
+
+   if (areq->nbytes == 0)
+   return 0;
+
+   if (areq->info == NULL) {
+   dev_err(ss->dev, "ERROR: Empty IV\n");
+   return -EINVAL;
+   }
+
+   if (areq->src == NULL || areq->dst == NULL) {
+   dev_err(ss->dev, "ERROR: Some SGs are NULL\n");
+   return -EINVAL;
+   }
+
+   cipher_type = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
+
+   if (strcmp("cbc(aes)", cipher_type) == 0) {
+   mode |= SS_OP_AES | SS_CBC | SS_ENABLED | op->keymode;
+   return sunxi_ss_aes_poll(areq, mode);
+   }
+
+   if (strcmp("cbc(des)", cipher_type) == 0) {
+   mode |= SS_OP_DES | SS_CBC | SS_ENABLED | op->keymode;
+   return sunxi_ss_des_poll(areq, mode);
+   }
+
+   if (strcmp("cbc(des3_ede)", cipher_type) == 0) {
+   mode |= SS_OP_3DES | SS_CBC | SS_ENABLED | op->keymode;
+   return sunxi_ss_des_poll(areq, mode);
+   }
+
+   dev_err(ss->dev, "ERROR: Cipher %s not handled\n", cipher_type);
+   return -EINVAL;
+}
+
+int sunxi_ss