mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
crypto: rockchip - add HMAC(md5/sha1/sha256/sha512/sm3) for crypto v2
Change-Id: I28fd8f262fba7f96ca61ce2edc55517a6522b7ab Signed-off-by: Lin Jinhan <troy.lin@rock-chips.com>
This commit is contained in:
@@ -303,7 +303,7 @@ static int rk_crypto_register(struct rk_crypto_info *crypto_info)
|
||||
|
||||
if (tmp_algs->type == ALG_TYPE_CIPHER)
|
||||
err = crypto_register_alg(&tmp_algs->alg.crypto);
|
||||
else if (tmp_algs->type == ALG_TYPE_HASH)
|
||||
else if (tmp_algs->type == ALG_TYPE_HASH || tmp_algs->type == ALG_TYPE_HMAC)
|
||||
err = crypto_register_ahash(&tmp_algs->alg.hash);
|
||||
else
|
||||
continue;
|
||||
@@ -321,7 +321,7 @@ err_cipher_algs:
|
||||
tmp_algs = rk_crypto_find_algs(crypto_info, *algs_name);
|
||||
if (tmp_algs->type == ALG_TYPE_CIPHER)
|
||||
crypto_unregister_alg(&tmp_algs->alg.crypto);
|
||||
else if (tmp_algs->type == ALG_TYPE_HASH)
|
||||
else if (tmp_algs->type == ALG_TYPE_HASH || tmp_algs->type == ALG_TYPE_HMAC)
|
||||
crypto_unregister_ahash(&tmp_algs->alg.hash);
|
||||
}
|
||||
return err;
|
||||
@@ -339,7 +339,7 @@ static void rk_crypto_unregister(struct rk_crypto_info *crypto_info)
|
||||
tmp_algs = rk_crypto_find_algs(crypto_info, *algs_name);
|
||||
if (tmp_algs->type == ALG_TYPE_CIPHER)
|
||||
crypto_unregister_alg(&tmp_algs->alg.crypto);
|
||||
else if (tmp_algs->type == ALG_TYPE_HASH)
|
||||
else if (tmp_algs->type == ALG_TYPE_HASH || tmp_algs->type == ALG_TYPE_HMAC)
|
||||
crypto_unregister_ahash(&tmp_algs->alg.hash);
|
||||
}
|
||||
}
|
||||
@@ -383,6 +383,12 @@ static struct rk_crypto_tmp *crypto_v2_algs[] = {
|
||||
&rk_v2_ahash_sha512, /* sha512 */
|
||||
&rk_v2_ahash_md5, /* md5 */
|
||||
&rk_v2_ahash_sm3, /* sm3 */
|
||||
|
||||
&rk_v2_ahash_hmac_sha1, /* hmac(sha1) */
|
||||
&rk_v2_ahash_hmac_sha256, /* hmac(sha256) */
|
||||
&rk_v2_ahash_hmac_sha512, /* hmac(sha512) */
|
||||
&rk_v2_ahash_hmac_md5, /* hmac(md5) */
|
||||
&rk_v2_ahash_hmac_sm3, /* hmac(sm3) */
|
||||
};
|
||||
|
||||
static char *px30_algs_name[] = {
|
||||
@@ -397,6 +403,7 @@ static char *rv1126_algs_name[] = {
|
||||
"ecb(des)", "cbc(des)",
|
||||
"ecb(des3_ede)", "cbc(des3_ede)",
|
||||
"sha1", "sha256", "sha512", "md5", "sm3",
|
||||
"hmac(sha1)", "hmac(sha256)", "hmac(sha512)", "hmac(md5)", "hmac(sm3)",
|
||||
};
|
||||
|
||||
static const struct rk_crypto_soc_data px30_soc_data =
|
||||
|
||||
@@ -82,6 +82,8 @@ struct rk_crypto_info {
|
||||
/* the private variable of hash */
|
||||
struct rk_ahash_ctx {
|
||||
struct rk_crypto_info *dev;
|
||||
u8 authkey[SHA512_BLOCK_SIZE];
|
||||
|
||||
/* for fallback */
|
||||
struct crypto_ahash *fallback_tfm;
|
||||
};
|
||||
@@ -103,6 +105,7 @@ struct rk_cipher_ctx {
|
||||
|
||||
enum alg_type {
|
||||
ALG_TYPE_HASH,
|
||||
ALG_TYPE_HMAC,
|
||||
ALG_TYPE_CIPHER,
|
||||
};
|
||||
|
||||
@@ -238,6 +241,41 @@ enum rk_cipher_mode {
|
||||
} \
|
||||
}
|
||||
|
||||
#define RK_HMAC_ALGO_INIT(hash_algo, algo_name) {\
|
||||
.name = "hmac(" #algo_name ")",\
|
||||
.type = ALG_TYPE_HMAC,\
|
||||
.algo = HASH_ALGO_##hash_algo,\
|
||||
.alg.hash = {\
|
||||
.init = rk_ahash_init,\
|
||||
.update = rk_ahash_update,\
|
||||
.final = rk_ahash_final,\
|
||||
.finup = rk_ahash_finup,\
|
||||
.export = rk_ahash_export,\
|
||||
.import = rk_ahash_import,\
|
||||
.digest = rk_ahash_digest,\
|
||||
.setkey = rk_ahash_hmac_setkey,\
|
||||
.halg = {\
|
||||
.digestsize = hash_algo##_DIGEST_SIZE,\
|
||||
.statesize = sizeof(struct algo_name##_state),\
|
||||
.base = {\
|
||||
.cra_name = "hmac(" #algo_name ")",\
|
||||
.cra_driver_name = "hmac-" #algo_name "-rk",\
|
||||
.cra_priority = RK_CRYPTO_PRIORITY,\
|
||||
.cra_flags = CRYPTO_ALG_ASYNC |\
|
||||
CRYPTO_ALG_NEED_FALLBACK,\
|
||||
.cra_blocksize = hash_algo##_BLOCK_SIZE,\
|
||||
.cra_ctxsize = sizeof(struct rk_ahash_ctx),\
|
||||
.cra_alignmask = 3,\
|
||||
.cra_init = rk_cra_hash_init,\
|
||||
.cra_exit = rk_cra_hash_exit,\
|
||||
.cra_module = THIS_MODULE,\
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define IS_TYPE_HMAC(type) ((type) == ALG_TYPE_HMAC)
|
||||
|
||||
#define CRYPTO_READ(dev, offset) \
|
||||
readl_relaxed(((dev)->reg + (offset)))
|
||||
#define CRYPTO_WRITE(dev, offset, val) \
|
||||
|
||||
@@ -42,6 +42,12 @@ extern struct rk_crypto_tmp rk_v2_ahash_sha512;
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_md5;
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_sm3;
|
||||
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_hmac_md5;
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_hmac_sha1;
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_hmac_sha256;
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_hmac_sha512;
|
||||
extern struct rk_crypto_tmp rk_v2_ahash_hmac_sm3;
|
||||
|
||||
int rk_hw_crypto_v2_init(struct device *dev, void *hw_info);
|
||||
void rk_hw_crypto_v2_deinit(struct device *dev, void *hw_info);
|
||||
#endif
|
||||
|
||||
@@ -69,6 +69,14 @@ static const u32 hash_algo2bc[] = {
|
||||
[HASH_ALGO_SM3] = CRYPTO_SM3,
|
||||
};
|
||||
|
||||
const char *hash_algo2name[] = {
|
||||
[HASH_ALGO_MD5] = "md5",
|
||||
[HASH_ALGO_SHA1] = "sha1",
|
||||
[HASH_ALGO_SHA256] = "sha256",
|
||||
[HASH_ALGO_SHA512] = "sha512",
|
||||
[HASH_ALGO_SM3] = "sm3",
|
||||
};
|
||||
|
||||
static void word2byte(u32 word, u8 *ch, u32 endian)
|
||||
{
|
||||
/* 0: Big-Endian 1: Little-Endian */
|
||||
@@ -90,6 +98,20 @@ static void word2byte(u32 word, u8 *ch, u32 endian)
|
||||
}
|
||||
}
|
||||
|
||||
static u32 byte2word(const u8 *ch, u32 endian)
|
||||
{
|
||||
u32 w = 0;
|
||||
|
||||
/* 0: Big-Endian 1: Little-Endian */
|
||||
if (endian == BIG_ENDIAN)
|
||||
w = (*ch << 24) + (*(ch + 1) << 16) +
|
||||
(*(ch + 2) << 8) + *(ch + 3);
|
||||
else if (endian == LITTLE_ENDIAN)
|
||||
w = (*(ch + 3) << 24) + (*(ch + 2) << 16) +
|
||||
(*(ch + 1) << 8) + *ch;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static struct rk_crypto_tmp *rk_ahash_get_algt(struct crypto_ahash *tfm)
|
||||
{
|
||||
@@ -181,6 +203,19 @@ static inline void clear_hash_out_reg(struct rk_crypto_info *dev)
|
||||
CRYPTO_WRITE(dev, CRYPTO_HASH_DOUT_0 + 4 * i, 0);
|
||||
}
|
||||
|
||||
static void write_key_reg(struct rk_crypto_info *dev, const u8 *key,
|
||||
u32 key_len)
|
||||
{
|
||||
u32 i;
|
||||
u32 chn_base_addr;
|
||||
|
||||
chn_base_addr = CRYPTO_CH0_KEY_0;
|
||||
|
||||
for (i = 0; i < key_len / 4; i++, chn_base_addr += 4)
|
||||
CRYPTO_WRITE(dev, chn_base_addr,
|
||||
byte2word(key + i * 4, BIG_ENDIAN));
|
||||
}
|
||||
|
||||
static int rk_ahash_init(struct ahash_request *req)
|
||||
{
|
||||
struct rk_ahash_rctx *rctx = ahash_request_ctx(req);
|
||||
@@ -281,16 +316,108 @@ static int rk_ahash_export(struct ahash_request *req, void *out)
|
||||
static int rk_ahash_digest(struct ahash_request *req)
|
||||
{
|
||||
struct rk_ahash_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct rk_crypto_tmp *algt = rk_ahash_get_algt(tfm);
|
||||
struct rk_crypto_info *dev = tctx->dev;
|
||||
|
||||
CRYPTO_TRACE("calc data %u bytes.", req->nbytes);
|
||||
|
||||
if (!req->nbytes)
|
||||
return zero_message_process(req);
|
||||
return IS_TYPE_HMAC(algt->type) ?
|
||||
crypto_ahash_digest(req) :
|
||||
zero_message_process(req);
|
||||
else
|
||||
return dev->enqueue(dev, &req->base);
|
||||
}
|
||||
|
||||
static int rk_ahash_calc_digest(const char *alg_name, const u8 *key, u32 keylen,
|
||||
u8 *digest, u32 digest_len)
|
||||
{
|
||||
struct crypto_ahash *ahash_tfm;
|
||||
struct ahash_request *req;
|
||||
struct crypto_wait wait;
|
||||
struct scatterlist sg;
|
||||
int ret;
|
||||
|
||||
CRYPTO_TRACE();
|
||||
|
||||
ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_NEED_FALLBACK);
|
||||
if (IS_ERR(ahash_tfm))
|
||||
return PTR_ERR(ahash_tfm);
|
||||
|
||||
req = ahash_request_alloc(ahash_tfm, GFP_KERNEL);
|
||||
if (!req) {
|
||||
crypto_free_ahash(ahash_tfm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
init_completion(&wait.completion);
|
||||
|
||||
crypto_ahash_clear_flags(ahash_tfm, ~0);
|
||||
|
||||
sg_init_one(&sg, key, keylen);
|
||||
ahash_request_set_crypt(req, &sg, digest, keylen);
|
||||
|
||||
ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
|
||||
if (ret) {
|
||||
CRYPTO_MSG("digest failed, ret = %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
ahash_request_free(req);
|
||||
crypto_free_ahash(ahash_tfm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
unsigned int blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
|
||||
unsigned int digestsize = crypto_ahash_digestsize(tfm);
|
||||
struct rk_crypto_tmp *algt = rk_ahash_get_algt(tfm);
|
||||
struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
|
||||
const char *alg_name;
|
||||
int ret;
|
||||
|
||||
CRYPTO_MSG();
|
||||
|
||||
crypto_ahash_clear_flags(ctx->fallback_tfm, ~0);
|
||||
ret = crypto_ahash_setkey(ctx->fallback_tfm, key, keylen);
|
||||
if (ret) {
|
||||
CRYPTO_MSG("setkey failed, ret = %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(ctx->authkey, 0, sizeof(ctx->authkey));
|
||||
|
||||
if (keylen <= blocksize) {
|
||||
memcpy(ctx->authkey, key, keylen);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (algt->algo >= ARRAY_SIZE(hash_algo2name)) {
|
||||
CRYPTO_MSG("hash algo %d invalid\n", algt->algo);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
alg_name = hash_algo2name[algt->algo];
|
||||
|
||||
CRYPTO_TRACE("calc key digest %s", alg_name);
|
||||
|
||||
ret = rk_ahash_calc_digest(alg_name, key, keylen, ctx->authkey, digestsize);
|
||||
if (ret) {
|
||||
CRYPTO_MSG("rk_ahash_calc_digest error ret = %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret)
|
||||
crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rk_ahash_dma_start(struct rk_crypto_info *dev)
|
||||
{
|
||||
struct rk_hw_crypto_v2_info *hw_info =
|
||||
@@ -334,6 +461,7 @@ static int rk_ahash_start(struct rk_crypto_info *dev)
|
||||
struct ahash_request *req = ahash_request_cast(dev->async_req);
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct rk_crypto_tmp *algt = rk_ahash_get_algt(tfm);
|
||||
struct rk_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
|
||||
u32 reg_ctrl = 0;
|
||||
|
||||
CRYPTO_TRACE();
|
||||
@@ -354,6 +482,13 @@ static int rk_ahash_start(struct rk_crypto_info *dev)
|
||||
clear_hash_out_reg(dev);
|
||||
|
||||
reg_ctrl |= CRYPTO_HW_PAD_ENABLE;
|
||||
|
||||
if (IS_TYPE_HMAC(algt->type)) {
|
||||
CRYPTO_TRACE("this is hmac");
|
||||
reg_ctrl |= CRYPTO_HMAC_ENABLE;
|
||||
write_key_reg(dev, ctx->authkey, sizeof(ctx->authkey));
|
||||
}
|
||||
|
||||
CRYPTO_WRITE(dev, CRYPTO_HASH_CTL, reg_ctrl | CRYPTO_WRITE_MASK_ALL);
|
||||
|
||||
CRYPTO_WRITE(dev, CRYPTO_FIFO_CTL, 0x00030003);
|
||||
@@ -490,3 +625,9 @@ struct rk_crypto_tmp rk_v2_ahash_sha256 = RK_HASH_ALGO_INIT(SHA256, sha256);
|
||||
struct rk_crypto_tmp rk_v2_ahash_sha512 = RK_HASH_ALGO_INIT(SHA512, sha512);
|
||||
struct rk_crypto_tmp rk_v2_ahash_sm3 = RK_HASH_ALGO_INIT(SM3, sm3);
|
||||
|
||||
struct rk_crypto_tmp rk_v2_ahash_hmac_md5 = RK_HMAC_ALGO_INIT(MD5, md5);
|
||||
struct rk_crypto_tmp rk_v2_ahash_hmac_sha1 = RK_HMAC_ALGO_INIT(SHA1, sha1);
|
||||
struct rk_crypto_tmp rk_v2_ahash_hmac_sha256 = RK_HMAC_ALGO_INIT(SHA256, sha256);
|
||||
struct rk_crypto_tmp rk_v2_ahash_hmac_sha512 = RK_HMAC_ALGO_INIT(SHA512, sha512);
|
||||
struct rk_crypto_tmp rk_v2_ahash_hmac_sm3 = RK_HMAC_ALGO_INIT(SM3, sm3);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user