diff options
-rw-r--r-- | drivers/misc/tegra-cryptodev.c | 99 | ||||
-rw-r--r-- | drivers/misc/tegra-cryptodev.h | 14 |
2 files changed, 113 insertions, 0 deletions
diff --git a/drivers/misc/tegra-cryptodev.c b/drivers/misc/tegra-cryptodev.c index 0d4a08941201..06e227cbd07c 100644 --- a/drivers/misc/tegra-cryptodev.c +++ b/drivers/misc/tegra-cryptodev.c @@ -133,6 +133,7 @@ static int tegra_crypto_dev_open(struct inode *inode, struct file *filp) goto fail_ctr; } } + if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA11) { ctx->rng_drbg = crypto_alloc_rng("rng_drbg-aes-tegra", CRYPTO_ALG_TYPE_RNG, 0); @@ -336,6 +337,95 @@ static int sha_async_hash_op(struct ahash_request *req, return ret; } +static int tegra_crypt_rsa(struct tegra_rsa_req *rsa_req) +{ + struct crypto_ahash *tfm; + struct ahash_request *req; + struct scatterlist sg[1]; + char *result = NULL; + void *hash_buff; + int ret = 0; + unsigned long *xbuf[XBUFSIZE]; + struct tegra_crypto_completion rsa_complete; + + tfm = crypto_alloc_ahash(rsa_req->algo, 0, 0); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: hash: Failed to load transform for %s: %ld\n", + rsa_req->algo, PTR_ERR(tfm)); + goto alloc_fail; + } + + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) { + printk(KERN_ERR "alg: hash: Failed to allocate request for %s\n", + rsa_req->algo); + goto req_fail; + } + + ret = alloc_bufs(xbuf); + if (ret < 0) { + pr_err("alloc_bufs failed"); + goto buf_fail; + } + + init_completion(&rsa_complete.restart); + + result = kzalloc(rsa_req->keylen >> 16 , GFP_KERNEL); + if (!result) { + pr_err("\nresult alloc fail\n"); + goto result_fail; + } + + hash_buff = xbuf[0]; + + memcpy(hash_buff, rsa_req->message, rsa_req->msg_len); + + sg_init_one(&sg[0], hash_buff, rsa_req->msg_len); + + if (!(rsa_req->keylen)) + goto rsa_fail; + + ret = crypto_ahash_setkey(tfm, rsa_req->key, rsa_req->keylen); + + if (ret) { + printk(KERN_ERR "alg: hash: setkey failed on: %s\n", + rsa_req->algo); + goto rsa_fail; + } + + ahash_request_set_crypt(req, sg, result, rsa_req->msg_len); + + ret = crypto_ahash_digest(req); + + if (ret == -EINPROGRESS || ret == -EBUSY) { + ret = wait_for_completion_interruptible(&rsa_complete.restart); + if (!ret) + ret = rsa_complete.req_err; + INIT_COMPLETION(rsa_complete.restart); + } + + if (ret) { + pr_err("alg: hash: digest failed for %s\n", rsa_req->algo); + goto rsa_fail; + } + + ret = copy_to_user((void __user *)rsa_req->result, (const void *)result, + crypto_ahash_digestsize(tfm)); + if (ret < 0) + goto rsa_fail; + +rsa_fail: + kfree(result); +result_fail: + free_bufs(xbuf); +buf_fail: + ahash_request_free(req); +req_fail: + crypto_free_ahash(tfm); +alloc_fail: + return ret; +} + static int tegra_crypto_sha(struct tegra_sha_req *sha_req) { @@ -438,6 +528,7 @@ static long tegra_crypto_dev_ioctl(struct file *filp, struct tegra_crypt_req crypt_req; struct tegra_rng_req rng_req; struct tegra_sha_req sha_req; + struct tegra_rsa_req rsa_req; char *rng; int ret = 0; @@ -521,6 +612,14 @@ rng_out: } break; + case TEGRA_CRYPTO_IOCTL_RSA_REQ: + if (copy_from_user(&rsa_req, (void __user *)arg, + sizeof(rsa_req))) + return -EFAULT; + + ret = tegra_crypt_rsa(&rsa_req); + break; + default: pr_debug("invalid ioctl code(%d)", ioctl_num); ret = -EINVAL; diff --git a/drivers/misc/tegra-cryptodev.h b/drivers/misc/tegra-cryptodev.h index df4a15e91f4c..e6b19b234e26 100644 --- a/drivers/misc/tegra-cryptodev.h +++ b/drivers/misc/tegra-cryptodev.h @@ -29,8 +29,10 @@ #define TEGRA_CRYPTO_IOCTL_SET_SEED _IOWR(0x98, 102, int*) #define TEGRA_CRYPTO_IOCTL_GET_RANDOM _IOWR(0x98, 103, int*) #define TEGRA_CRYPTO_IOCTL_GET_SHA _IOWR(0x98, 104, int*) +#define TEGRA_CRYPTO_IOCTL_RSA_REQ _IOWR(0x98, 105, int*) #define TEGRA_CRYPTO_MAX_KEY_SIZE AES_MAX_KEY_SIZE +#define RSA_KEY_SIZE 512 #define TEGRA_CRYPTO_IV_SIZE AES_BLOCK_SIZE #define DEFAULT_RNG_BLK_SZ 16 @@ -72,6 +74,18 @@ struct tegra_rng_req { int type; }; +struct tegra_rsa_req { + char *key; + int keylen; + char *algo; + char *message; + int msg_len; + int modlen; + int pub_explen; + int prv_explen; + char *result; +}; + struct tegra_sha_req { char key[TEGRA_CRYPTO_MAX_KEY_SIZE]; int keylen; |