crypto: ti - Add support for AES-CCM in DTHEv2 driver
AES-CCM is an AEAD algorithm supporting both encryption and authentication of data. This patch introduces support for AES-CCM AEAD algorithm in the DTHEv2 driver. Signed-off-by: T Pratham <t-pratham@ti.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>master
parent
37b902c603
commit
a09c5e0649
|
|
@ -9,6 +9,7 @@ config CRYPTO_DEV_TI_DTHEV2
|
|||
select CRYPTO_CTR
|
||||
select CRYPTO_XTS
|
||||
select CRYPTO_GCM
|
||||
select CRYPTO_CCM
|
||||
select SG_SPLIT
|
||||
help
|
||||
This enables support for the TI DTHE V2 hw cryptography engine
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "dthev2-common.h"
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
|
@ -69,6 +70,7 @@ enum aes_ctrl_mode_masks {
|
|||
AES_CTRL_CTR_MASK = BIT(6),
|
||||
AES_CTRL_XTS_MASK = BIT(12) | BIT(11),
|
||||
AES_CTRL_GCM_MASK = BIT(17) | BIT(16) | BIT(6),
|
||||
AES_CTRL_CCM_MASK = BIT(18) | BIT(6),
|
||||
};
|
||||
|
||||
#define DTHE_AES_CTRL_MODE_CLEAR_MASK ~GENMASK(28, 5)
|
||||
|
|
@ -81,6 +83,11 @@ enum aes_ctrl_mode_masks {
|
|||
|
||||
#define DTHE_AES_CTRL_CTR_WIDTH_128B (BIT(7) | BIT(8))
|
||||
|
||||
#define DTHE_AES_CCM_L_FROM_IV_MASK GENMASK(2, 0)
|
||||
#define DTHE_AES_CCM_M_BITS GENMASK(2, 0)
|
||||
#define DTHE_AES_CTRL_CCM_L_FIELD_MASK GENMASK(21, 19)
|
||||
#define DTHE_AES_CTRL_CCM_M_FIELD_MASK GENMASK(24, 22)
|
||||
|
||||
#define DTHE_AES_CTRL_SAVE_CTX_SET BIT(29)
|
||||
|
||||
#define DTHE_AES_CTRL_OUTPUT_READY BIT_MASK(0)
|
||||
|
|
@ -96,6 +103,8 @@ enum aes_ctrl_mode_masks {
|
|||
#define AES_BLOCK_WORDS (AES_BLOCK_SIZE / sizeof(u32))
|
||||
#define AES_IV_WORDS AES_BLOCK_WORDS
|
||||
#define DTHE_AES_GCM_AAD_MAXLEN (BIT_ULL(32) - 1)
|
||||
#define DTHE_AES_CCM_AAD_MAXLEN (BIT(16) - BIT(8))
|
||||
#define DTHE_AES_CCM_CRYPT_MAXLEN (BIT_ULL(61) - 1)
|
||||
#define POLL_TIMEOUT_INTERVAL HZ
|
||||
|
||||
static int dthe_cipher_init_tfm(struct crypto_skcipher *tfm)
|
||||
|
|
@ -275,6 +284,13 @@ static void dthe_aes_set_ctrl_key(struct dthe_tfm_ctx *ctx,
|
|||
case DTHE_AES_GCM:
|
||||
ctrl_val |= AES_CTRL_GCM_MASK;
|
||||
break;
|
||||
case DTHE_AES_CCM:
|
||||
ctrl_val |= AES_CTRL_CCM_MASK;
|
||||
ctrl_val |= FIELD_PREP(DTHE_AES_CTRL_CCM_L_FIELD_MASK,
|
||||
(iv_in[0] & DTHE_AES_CCM_L_FROM_IV_MASK));
|
||||
ctrl_val |= FIELD_PREP(DTHE_AES_CTRL_CCM_M_FIELD_MASK,
|
||||
((ctx->authsize - 2) >> 1) & DTHE_AES_CCM_M_BITS);
|
||||
break;
|
||||
}
|
||||
|
||||
if (iv_in) {
|
||||
|
|
@ -756,10 +772,6 @@ static int dthe_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int
|
|||
if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_256)
|
||||
return -EINVAL;
|
||||
|
||||
ctx->aes_mode = DTHE_AES_GCM;
|
||||
ctx->keylen = keylen;
|
||||
memcpy(ctx->key, key, keylen);
|
||||
|
||||
crypto_sync_aead_clear_flags(ctx->aead_fb, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_sync_aead_set_flags(ctx->aead_fb,
|
||||
crypto_aead_get_flags(tfm) &
|
||||
|
|
@ -768,6 +780,38 @@ static int dthe_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int
|
|||
return crypto_sync_aead_setkey(ctx->aead_fb, key, keylen);
|
||||
}
|
||||
|
||||
static int dthe_gcm_aes_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
|
||||
{
|
||||
struct dthe_tfm_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
int ret;
|
||||
|
||||
ret = dthe_aead_setkey(tfm, key, keylen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->aes_mode = DTHE_AES_GCM;
|
||||
ctx->keylen = keylen;
|
||||
memcpy(ctx->key, key, keylen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dthe_ccm_aes_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
|
||||
{
|
||||
struct dthe_tfm_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
int ret;
|
||||
|
||||
ret = dthe_aead_setkey(tfm, key, keylen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->aes_mode = DTHE_AES_CCM;
|
||||
ctx->keylen = keylen;
|
||||
memcpy(ctx->key, key, keylen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dthe_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
|
||||
{
|
||||
struct dthe_tfm_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
|
|
@ -990,14 +1034,18 @@ static int dthe_aead_run(struct crypto_engine *engine, void *areq)
|
|||
writel_relaxed(1, aes_base_reg + DTHE_P_AES_AUTH_LENGTH);
|
||||
}
|
||||
|
||||
if (req->iv) {
|
||||
memcpy(iv_in, req->iv, GCM_AES_IV_SIZE);
|
||||
if (ctx->aes_mode == DTHE_AES_GCM) {
|
||||
if (req->iv) {
|
||||
memcpy(iv_in, req->iv, GCM_AES_IV_SIZE);
|
||||
} else {
|
||||
iv_in[0] = 0;
|
||||
iv_in[1] = 0;
|
||||
iv_in[2] = 0;
|
||||
}
|
||||
iv_in[3] = 0x01000000;
|
||||
} else {
|
||||
iv_in[0] = 0;
|
||||
iv_in[1] = 0;
|
||||
iv_in[2] = 0;
|
||||
memcpy(iv_in, req->iv, AES_IV_SIZE);
|
||||
}
|
||||
iv_in[3] = 0x01000000;
|
||||
|
||||
/* Clear key2 to reset previous GHASH intermediate data */
|
||||
for (int i = 0; i < AES_KEYSIZE_256 / sizeof(u32); ++i)
|
||||
|
|
@ -1084,20 +1132,55 @@ static int dthe_aead_crypt(struct aead_request *req)
|
|||
struct dthe_data *dev_data = dthe_get_dev(ctx);
|
||||
struct crypto_engine *engine;
|
||||
unsigned int cryptlen = req->cryptlen;
|
||||
bool is_zero_ctr = true;
|
||||
|
||||
/* In decryption, last authsize bytes are the TAG */
|
||||
if (!rctx->enc)
|
||||
cryptlen -= ctx->authsize;
|
||||
|
||||
if (ctx->aes_mode == DTHE_AES_CCM) {
|
||||
/*
|
||||
* For CCM Mode, the 128-bit IV contains the following:
|
||||
* | 0 .. 2 | 3 .. 7 | 8 .. (127-8*L) | (128-8*L) .. 127 |
|
||||
* | L-1 | Zero | Nonce | Counter |
|
||||
* L needs to be between 2-8 (inclusive), i.e. 1 <= (L-1) <= 7
|
||||
* and the next 5 bits need to be zeroes. Else return -EINVAL
|
||||
*/
|
||||
u8 *iv = req->iv;
|
||||
u8 L = iv[0];
|
||||
|
||||
/* variable L stores L-1 here */
|
||||
if (L < 1 || L > 7)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* DTHEv2 HW can only work with zero initial counter in CCM mode.
|
||||
* Check if the initial counter value is zero or not
|
||||
*/
|
||||
for (int i = 0; i < L + 1; ++i) {
|
||||
if (iv[AES_IV_SIZE - 1 - i] != 0) {
|
||||
is_zero_ctr = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to fallback to software in the following cases due to HW restrictions:
|
||||
* - Both AAD and plaintext/ciphertext are zero length
|
||||
* - AAD length is more than 2^32 - 1 bytes
|
||||
* PS: req->cryptlen is currently unsigned int type, which causes the above condition
|
||||
* tautologically false. If req->cryptlen were to be changed to a 64-bit type,
|
||||
* the check for this would need to be added below.
|
||||
* - For AES-GCM, AAD length is more than 2^32 - 1 bytes
|
||||
* - For AES-CCM, AAD length is more than 2^16 - 2^8 bytes
|
||||
* - For AES-CCM, plaintext/ciphertext length is more than 2^61 - 1 bytes
|
||||
* - For AES-CCM, AAD length is non-zero but plaintext/ciphertext length is zero
|
||||
* - For AES-CCM, the initial counter (last L+1 bytes of IV) is not all zeroes
|
||||
*
|
||||
* PS: req->cryptlen is currently unsigned int type, which causes the second and fourth
|
||||
* cases above tautologically false. If req->cryptlen is to be changed to a 64-bit
|
||||
* type, the check for these would also need to be added below.
|
||||
*/
|
||||
if (req->assoclen == 0 && cryptlen == 0)
|
||||
if ((req->assoclen == 0 && cryptlen == 0) ||
|
||||
(ctx->aes_mode == DTHE_AES_CCM && req->assoclen > DTHE_AES_CCM_AAD_MAXLEN) ||
|
||||
(ctx->aes_mode == DTHE_AES_CCM && cryptlen == 0) ||
|
||||
(ctx->aes_mode == DTHE_AES_CCM && !is_zero_ctr))
|
||||
return dthe_aead_do_fallback(req);
|
||||
|
||||
engine = dev_data->engine;
|
||||
|
|
@ -1222,7 +1305,7 @@ static struct aead_engine_alg aead_algs[] = {
|
|||
{
|
||||
.base.init = dthe_aead_init_tfm,
|
||||
.base.exit = dthe_aead_exit_tfm,
|
||||
.base.setkey = dthe_aead_setkey,
|
||||
.base.setkey = dthe_gcm_aes_setkey,
|
||||
.base.setauthsize = dthe_aead_setauthsize,
|
||||
.base.maxauthsize = AES_BLOCK_SIZE,
|
||||
.base.encrypt = dthe_aead_encrypt,
|
||||
|
|
@ -1244,6 +1327,31 @@ static struct aead_engine_alg aead_algs[] = {
|
|||
},
|
||||
.op.do_one_request = dthe_aead_run,
|
||||
}, /* GCM AES */
|
||||
{
|
||||
.base.init = dthe_aead_init_tfm,
|
||||
.base.exit = dthe_aead_exit_tfm,
|
||||
.base.setkey = dthe_ccm_aes_setkey,
|
||||
.base.setauthsize = dthe_aead_setauthsize,
|
||||
.base.maxauthsize = AES_BLOCK_SIZE,
|
||||
.base.encrypt = dthe_aead_encrypt,
|
||||
.base.decrypt = dthe_aead_decrypt,
|
||||
.base.chunksize = AES_BLOCK_SIZE,
|
||||
.base.ivsize = AES_IV_SIZE,
|
||||
.base.base = {
|
||||
.cra_name = "ccm(aes)",
|
||||
.cra_driver_name = "ccm-aes-dthev2",
|
||||
.cra_priority = 299,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_AEAD |
|
||||
CRYPTO_ALG_KERN_DRIVER_ONLY |
|
||||
CRYPTO_ALG_ASYNC |
|
||||
CRYPTO_ALG_NEED_FALLBACK,
|
||||
.cra_blocksize = 1,
|
||||
.cra_ctxsize = sizeof(struct dthe_tfm_ctx),
|
||||
.cra_reqsize = sizeof(struct dthe_aes_req_ctx),
|
||||
.cra_module = THIS_MODULE,
|
||||
},
|
||||
.op.do_one_request = dthe_aead_run,
|
||||
}, /* CCM AES */
|
||||
};
|
||||
|
||||
int dthe_register_aes_algs(void)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ enum dthe_aes_mode {
|
|||
DTHE_AES_CTR,
|
||||
DTHE_AES_XTS,
|
||||
DTHE_AES_GCM,
|
||||
DTHE_AES_CCM,
|
||||
};
|
||||
|
||||
/* Driver specific struct definitions */
|
||||
|
|
|
|||
Loading…
Reference in New Issue