diff options
author | Kasoju Mallikarjun <mkasoju@nvidia.com> | 2011-08-09 18:02:28 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:10 -0800 |
commit | 26bbc5c58481c3854a9fcd9f96165f08a15f3dba (patch) | |
tree | 9a9db0f5a90a57df74fc2506472d8e2479b30d02 /drivers/crypto | |
parent | dd314ff51c70b038107202a4030621114283fa60 (diff) |
crypto: tegra-se: RNG support for more than 16 bytes
Added support for generating RNG for more than 16 bytes.
Bug 861777
Original-Change-Id: I414063378c1b7c31c9ef2ade950adcaa4e7db388
Reviewed-on: http://git-master/r/46066
Tested-by: Mallikarjun Kasoju <mkasoju@nvidia.com>
Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com>
Rebase-Id: Ra4ff01903b00f98b317606be3ffdfef58668aa92
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/tegra-se.c | 67 |
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/crypto/tegra-se.c b/drivers/crypto/tegra-se.c index d4df3569f87c..658b89cd5bd6 100644 --- a/drivers/crypto/tegra-se.c +++ b/drivers/crypto/tegra-se.c @@ -82,6 +82,7 @@ struct tegra_se_dev { struct clk *pclk; /* Security Engine clock */ struct crypto_queue queue; /* Security Engine crypto queue */ struct tegra_se_slot *slot_list; /* pointer to key slots */ + u64 ctr; u32 *src_ll_buf; /* pointer to source linked list buffer */ dma_addr_t src_ll_buf_adr; /* Source linked list buffer dma address */ u32 src_ll_size; /* Size of source linked list buffer */ @@ -184,6 +185,8 @@ static void tegra_se_leftshift_onebit(u8 *in_buf, u32 size, u8 *org_msb) } } +extern unsigned long long tegra_chip_uid(void); + static inline void se_writel(struct tegra_se_dev *se_dev, unsigned int val, unsigned int reg_offset) { @@ -1049,10 +1052,12 @@ static int tegra_se_rng_get_random(struct crypto_rng *tfm, u8 *rdata, u32 dlen) struct tegra_se_dev *se_dev = rng_ctx->se_dev; struct tegra_se_ll *src_ll, *dst_ll; unsigned char *dt_buf = (unsigned char *)rng_ctx->dt_buf; - int ret = 0, i; + u8 *rdata_addr; + int ret = 0, i, j, num_blocks; - if (dlen > TEGRA_SE_RNG_DT_SIZE) + if (dlen < TEGRA_SE_RNG_DT_SIZE) return -EINVAL; + num_blocks = (dlen / TEGRA_SE_RNG_DT_SIZE); /* take access to the hw */ mutex_lock(&se_hw_lock); @@ -1063,28 +1068,39 @@ static int tegra_se_rng_get_random(struct crypto_rng *tfm, u8 *rdata, u32 dlen) src_ll = (struct tegra_se_ll *)(se_dev->src_ll_buf + 1); dst_ll = (struct tegra_se_ll *)(se_dev->dst_ll_buf + 1); src_ll->addr = rng_ctx->dt_buf_adr; - src_ll->data_len = dlen; + src_ll->data_len = TEGRA_SE_RNG_DT_SIZE; dst_ll->addr = rng_ctx->rng_buf_adr; - dst_ll->data_len = dlen; + dst_ll->data_len = TEGRA_SE_RNG_DT_SIZE; tegra_se_config_algo(se_dev, SE_AES_OP_MODE_RNG_X931, true, TEGRA_SE_KEY_128_SIZE); tegra_se_config_crypto(se_dev, SE_AES_OP_MODE_RNG_X931, true, rng_ctx->slot->slot_num, rng_ctx->use_org_iv); - ret = tegra_se_start_operation(se_dev, dlen, false); - - if (!ret) { - memcpy(rdata, rng_ctx->rng_buf, dlen); - /* update DT vector */ - for (i = TEGRA_SE_RNG_DT_SIZE - 1; i >= 0; i--) { - dt_buf[i] += 1; - if (dt_buf[i] != 0) - break; + for (j = 0; j < num_blocks; j++) { + ret = tegra_se_start_operation(se_dev, + TEGRA_SE_RNG_DT_SIZE, false); + + if (!ret) { + rdata_addr = (rdata + (j * TEGRA_SE_RNG_DT_SIZE)); + memcpy(rdata_addr, + rng_ctx->rng_buf, TEGRA_SE_RNG_DT_SIZE); + + /* update DT vector */ + for (i = TEGRA_SE_RNG_DT_SIZE - 1; i >= 0; i--) { + dt_buf[i] += 1; + if (dt_buf[i] != 0) + break; + } + } else { + dlen = 0; + } + if (rng_ctx->use_org_iv) { + rng_ctx->use_org_iv = false; + tegra_se_config_crypto(se_dev, + SE_AES_OP_MODE_RNG_X931, true, + rng_ctx->slot->slot_num, rng_ctx->use_org_iv); } - } else { - dlen = 0; } - rng_ctx->use_org_iv = false; tegra_se_clk_disable(se_dev->pclk); mutex_unlock(&se_hw_lock); @@ -1099,12 +1115,11 @@ static int tegra_se_rng_reset(struct crypto_rng *tfm, u8 *seed, u32 slen) u8 *iv = seed; u8 *key = (u8 *)(seed + TEGRA_SE_RNG_IV_SIZE); u8 *dt = key + TEGRA_SE_RNG_KEY_SIZE; + struct timespec ts; + u64 nsec, tmp[2]; BUG_ON(!seed); - if (slen < TEGRA_SE_RNG_SEED_SIZE) - return -EINVAL; - /* take access to the hw */ mutex_lock(&se_hw_lock); tegra_se_clk_enable(se_dev->pclk); @@ -1118,7 +1133,19 @@ static int tegra_se_rng_reset(struct crypto_rng *tfm, u8 *seed, u32 slen) tegra_se_clk_disable(se_dev->pclk); mutex_unlock(&se_hw_lock); - memcpy(rng_ctx->dt_buf, dt, TEGRA_SE_RNG_DT_SIZE); + if (slen < TEGRA_SE_RNG_SEED_SIZE) { + getnstimeofday(&ts); + nsec = timespec_to_ns(&ts); + do_div(nsec, 1000); + nsec ^= se_dev->ctr << 56; + se_dev->ctr++; + tmp[0] = nsec; + tmp[1] = tegra_chip_uid(); + memcpy(rng_ctx->dt_buf, (u8 *)tmp, TEGRA_SE_RNG_DT_SIZE); + } else { + memcpy(rng_ctx->dt_buf, dt, TEGRA_SE_RNG_DT_SIZE); + } + rng_ctx->use_org_iv = true; return 0; |