diff options
Diffstat (limited to 'drivers/crypto/sunxi-ss')
-rw-r--r-- | drivers/crypto/sunxi-ss/sun4i-ss-cipher.c | 78 | ||||
-rw-r--r-- | drivers/crypto/sunxi-ss/sun4i-ss-core.c | 19 | ||||
-rw-r--r-- | drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 5 | ||||
-rw-r--r-- | drivers/crypto/sunxi-ss/sun4i-ss.h | 2 |
4 files changed, 76 insertions, 28 deletions
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c index 54fd714d53ca..b060a0810934 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c @@ -41,11 +41,6 @@ static int sun4i_ss_opti_poll(struct skcipher_request *areq) if (!areq->cryptlen) return 0; - if (!areq->iv) { - dev_err_ratelimited(ss->dev, "ERROR: Empty IV\n"); - return -EINVAL; - } - if (!areq->src || !areq->dst) { dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n"); return -EINVAL; @@ -134,6 +129,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) struct scatterlist *out_sg = areq->dst; unsigned int ivsize = crypto_skcipher_ivsize(tfm); struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + struct sun4i_ss_alg_template *algt; u32 mode = ctx->mode; /* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */ u32 rx_cnt = SS_RX_DEFAULT; @@ -153,20 +150,20 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) unsigned int obo = 0; /* offset in bufo*/ unsigned int obl = 0; /* length of data in bufo */ unsigned long flags; + bool need_fallback; if (!areq->cryptlen) return 0; - if (!areq->iv) { - dev_err_ratelimited(ss->dev, "ERROR: Empty IV\n"); - return -EINVAL; - } - if (!areq->src || !areq->dst) { dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n"); return -EINVAL; } + algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto); + if (areq->cryptlen % algt->alg.crypto.base.cra_blocksize) + need_fallback = true; + /* * if we have only SGs with size multiple of 4, * we can use the SS optimized function @@ -182,9 +179,24 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq) out_sg = sg_next(out_sg); } - if (no_chunk == 1) + if (no_chunk == 1 && !need_fallback) return sun4i_ss_opti_poll(areq); + if (need_fallback) { + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, op->fallback_tfm); + skcipher_request_set_sync_tfm(subreq, op->fallback_tfm); + skcipher_request_set_callback(subreq, areq->base.flags, NULL, + NULL); + skcipher_request_set_crypt(subreq, areq->src, areq->dst, + areq->cryptlen, areq->iv); + if (ctx->mode & SS_DECRYPTION) + err = crypto_skcipher_decrypt(subreq); + else + err = crypto_skcipher_encrypt(subreq); + skcipher_request_zero(subreq); + return err; + } + spin_lock_irqsave(&ss->slock, flags); for (i = 0; i < op->keylen; i += 4) @@ -458,6 +470,7 @@ int sun4i_ss_cipher_init(struct crypto_tfm *tfm) { struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm); struct sun4i_ss_alg_template *algt; + const char *name = crypto_tfm_alg_name(tfm); memset(op, 0, sizeof(struct sun4i_tfm_ctx)); @@ -468,9 +481,22 @@ int sun4i_ss_cipher_init(struct crypto_tfm *tfm) crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm), sizeof(struct sun4i_cipher_req_ctx)); + op->fallback_tfm = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(op->fallback_tfm)) { + dev_err(op->ss->dev, "ERROR: Cannot allocate fallback for %s %ld\n", + name, PTR_ERR(op->fallback_tfm)); + return PTR_ERR(op->fallback_tfm); + } + return 0; } +void sun4i_ss_cipher_exit(struct crypto_tfm *tfm) +{ + struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm); + crypto_free_sync_skcipher(op->fallback_tfm); +} + /* check and set the AES key, prepare the mode to be used */ int sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) @@ -495,7 +521,11 @@ int sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, } op->keylen = keylen; memcpy(op->key, key, keylen); - return 0; + + crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); + + return crypto_sync_skcipher_setkey(op->fallback_tfm, key, keylen); } /* check and set the DES key, prepare the mode to be used */ @@ -525,7 +555,11 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key, op->keylen = keylen; memcpy(op->key, key, keylen); - return 0; + + crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); + + return crypto_sync_skcipher_setkey(op->fallback_tfm, key, keylen); } /* check and set the 3DES key, prepare the mode to be used */ @@ -533,14 +567,18 @@ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); - struct sun4i_ss_ctx *ss = op->ss; + int err; + + err = des3_verify_key(tfm, key); + if (unlikely(err)) + return err; - if (unlikely(keylen != 3 * DES_KEY_SIZE)) { - dev_err(ss->dev, "Invalid keylen %u\n", keylen); - crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } op->keylen = keylen; memcpy(op->key, key, keylen); - return 0; + + crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); + + return crypto_sync_skcipher_setkey(op->fallback_tfm, key, keylen); + } diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c index 89adf9e0fed2..05b3d3c32f6d 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c @@ -92,11 +92,12 @@ static struct sun4i_ss_alg_template ss_algs[] = { .cra_driver_name = "cbc-aes-sun4i-ss", .cra_priority = 300, .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK, .cra_ctxsize = sizeof(struct sun4i_tfm_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, .cra_init = sun4i_ss_cipher_init, + .cra_exit = sun4i_ss_cipher_exit, } } }, @@ -107,17 +108,17 @@ static struct sun4i_ss_alg_template ss_algs[] = { .decrypt = sun4i_ss_ecb_aes_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, .base = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-sun4i-ss", .cra_priority = 300, .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK, .cra_ctxsize = sizeof(struct sun4i_tfm_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, .cra_init = sun4i_ss_cipher_init, + .cra_exit = sun4i_ss_cipher_exit, } } }, @@ -134,11 +135,12 @@ static struct sun4i_ss_alg_template ss_algs[] = { .cra_driver_name = "cbc-des-sun4i-ss", .cra_priority = 300, .cra_blocksize = DES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK, .cra_ctxsize = sizeof(struct sun4i_req_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, .cra_init = sun4i_ss_cipher_init, + .cra_exit = sun4i_ss_cipher_exit, } } }, @@ -154,11 +156,12 @@ static struct sun4i_ss_alg_template ss_algs[] = { .cra_driver_name = "ecb-des-sun4i-ss", .cra_priority = 300, .cra_blocksize = DES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK, .cra_ctxsize = sizeof(struct sun4i_req_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, .cra_init = sun4i_ss_cipher_init, + .cra_exit = sun4i_ss_cipher_exit, } } }, @@ -175,11 +178,12 @@ static struct sun4i_ss_alg_template ss_algs[] = { .cra_driver_name = "cbc-des3-sun4i-ss", .cra_priority = 300, .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK, .cra_ctxsize = sizeof(struct sun4i_req_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, .cra_init = sun4i_ss_cipher_init, + .cra_exit = sun4i_ss_cipher_exit, } } }, @@ -190,16 +194,17 @@ static struct sun4i_ss_alg_template ss_algs[] = { .decrypt = sun4i_ss_ecb_des3_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, .base = { .cra_name = "ecb(des3_ede)", .cra_driver_name = "ecb-des3-sun4i-ss", .cra_priority = 300, .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_NEED_FALLBACK, .cra_ctxsize = sizeof(struct sun4i_req_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, .cra_init = sun4i_ss_cipher_init, + .cra_exit = sun4i_ss_cipher_exit, } } }, diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c index a4b5ff2b72f8..f6936bb3b7be 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c @@ -240,7 +240,10 @@ static int sun4i_hash(struct ahash_request *areq) } } else { /* Since we have the flag final, we can go up to modulo 4 */ - end = ((areq->nbytes + op->len) / 4) * 4 - op->len; + if (areq->nbytes < 4) + end = 0; + else + end = ((areq->nbytes + op->len) / 4) * 4 - op->len; } /* TODO if SGlen % 4 and !op->len then DMA */ diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h index f3ac90692ac6..8c4ec9e93565 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss.h +++ b/drivers/crypto/sunxi-ss/sun4i-ss.h @@ -161,6 +161,7 @@ struct sun4i_tfm_ctx { u32 keylen; u32 keymode; struct sun4i_ss_ctx *ss; + struct crypto_sync_skcipher *fallback_tfm; }; struct sun4i_cipher_req_ctx { @@ -203,6 +204,7 @@ int sun4i_ss_ecb_des3_encrypt(struct skcipher_request *areq); int sun4i_ss_ecb_des3_decrypt(struct skcipher_request *areq); int sun4i_ss_cipher_init(struct crypto_tfm *tfm); +void sun4i_ss_cipher_exit(struct crypto_tfm *tfm); int sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen); int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key, |