mirror of
				https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
				synced 2025-10-31 08:08:51 +01:00 
			
		
		
		
	Fixed MTP to work with TWRP
This commit is contained in:
		
						commit
						f6dfaef42e
					
				
					 50820 changed files with 20846062 additions and 0 deletions
				
			
		
							
								
								
									
										782
									
								
								drivers/crypto/fmp/fmplib.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										782
									
								
								drivers/crypto/fmp/fmplib.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,782 @@ | |||
| /*
 | ||||
|  * Exynos FMP libary for FIPS | ||||
|  * | ||||
|  * Copyright (C) 2015 Samsung Electronics Co., Ltd. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_address.h> | ||||
| #include <linux/of_platform.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/smc.h> | ||||
| 
 | ||||
| #include <crypto/hash.h> | ||||
| #include <crypto/sha.h> | ||||
| 
 | ||||
| #include <asm/cacheflush.h> | ||||
| 
 | ||||
| #include "fmpdev_int.h" | ||||
| #include "fmpdev.h" | ||||
| 
 | ||||
| #define BYPASS_MODE	0 | ||||
| #define CBC_MODE	1 | ||||
| #define XTS_MODE	2 | ||||
| 
 | ||||
| #define INIT		0 | ||||
| #define UPDATE		1 | ||||
| #define FINAL		2 | ||||
| 
 | ||||
| static void fmpdev_complete(struct crypto_async_request *req, int err) | ||||
| { | ||||
| 	struct fmpdev_result *res = req->data; | ||||
| 
 | ||||
| 	if (err == -EINPROGRESS) | ||||
| 		return; | ||||
| 
 | ||||
| 	res->err = err; | ||||
| 	complete(&res->completion); | ||||
| } | ||||
| 
 | ||||
| static inline int waitfor(struct fmp_info *info, struct fmpdev_result *cr, | ||||
| 			ssize_t ret) | ||||
| { | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	switch (ret) { | ||||
| 	case 0: | ||||
| 		break; | ||||
| 	case -EINPROGRESS: | ||||
| 	case -EBUSY: | ||||
| 		wait_for_completion(&cr->completion); | ||||
| 		/* At this point we known for sure the request has finished,
 | ||||
| 		 * because wait_for_completion above was not interruptible. | ||||
| 		 * This is important because otherwise hardware or driver | ||||
| 		 * might try to access memory which will be freed or reused for | ||||
| 		 * another request. */ | ||||
| 
 | ||||
| 		if (unlikely(cr->err)) { | ||||
| 			dev_err(dev, "error from async request: %d\n", cr->err); | ||||
| 			return cr->err; | ||||
| 		} | ||||
| 
 | ||||
| 		break; | ||||
| 	default: | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * FMP library to call FMP driver | ||||
|  * | ||||
|  * This file is part of linux fmpdev | ||||
|  */ | ||||
| 
 | ||||
| int fmpdev_cipher_init(struct fmp_info *info, struct cipher_data *out, | ||||
| 			const char *alg_name, | ||||
| 			uint8_t *enckey, uint8_t *twkey, size_t keylen) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	memset(out, 0, sizeof(*out)); | ||||
| 
 | ||||
| 	if (!strcmp(alg_name, "cbc(aes-fmp)")) | ||||
| 		out->mode = CBC_MODE; | ||||
| 	else if (!strcmp(alg_name, "xts(aes-fmp)")) | ||||
| 		out->mode = XTS_MODE; | ||||
| 	else { | ||||
| 		dev_err(dev, "Invalid mode\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	out->blocksize = 16; | ||||
| 	out->ivsize = 16; | ||||
| 	ret = fips_fmp_cipher_init(dev, enckey, twkey, keylen, out->mode); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Fail to initialize fmp cipher\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	out->init = 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void fmpdev_cipher_deinit(struct cipher_data *cdata) | ||||
| { | ||||
| 	if (cdata->init) | ||||
| 		cdata->init = 0; | ||||
| } | ||||
| 
 | ||||
| int fmpdev_cipher_set_iv(struct fmp_info *info, struct cipher_data *cdata, | ||||
| 			uint8_t *iv, size_t iv_size) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	ret = fips_fmp_cipher_set_iv(dev, iv, cdata->mode); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Fail to set fmp iv\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int fmpdev_cipher_exit(struct fmp_info *info) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	ret = fips_fmp_cipher_exit(dev); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Fail to exit fmp\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int fmpdev_cipher_encrypt(struct fmp_info *info, | ||||
| 		struct cipher_data *cdata, | ||||
| 		struct scatterlist *src, | ||||
| 		struct scatterlist *dst, size_t len) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	ret = fips_fmp_cipher_run(dev, sg_virt(src), sg_virt(dst), | ||||
| 				len, cdata->mode, ENCRYPT); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Fail to encrypt using fmp\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int fmpdev_cipher_decrypt(struct fmp_info *info, | ||||
| 		struct cipher_data *cdata, | ||||
| 		struct scatterlist *src, | ||||
| 		struct scatterlist *dst, size_t len) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	ret = fips_fmp_cipher_run(dev, sg_virt(src), sg_virt(dst), | ||||
| 				len, cdata->mode, DECRYPT); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Fail to encrypt using fmp\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Hash functions */ | ||||
| int fmpfw_hash_init(struct fmp_info *info, struct hash_data *hdata, | ||||
| 			const char *alg_name, int hmac_mode, | ||||
| 			void *mackey, size_t mackeylen) | ||||
| { | ||||
| 	int ret; | ||||
| 	unsigned long addr; | ||||
| 	struct device *dev = info->dev; | ||||
| 	struct hmac_sha256_fmpfw_info *fmpfw_info; | ||||
| 
 | ||||
| 	fmpfw_info = (struct hmac_sha256_fmpfw_info *)kzalloc(sizeof(*fmpfw_info), GFP_KERNEL); | ||||
| 	if (unlikely(!fmpfw_info)) { | ||||
| 		dev_err(dev, "Fail to alloc fmpfw info\n"); | ||||
| 		ret = ENOMEM; | ||||
| 		goto error_alloc_info; | ||||
| 	} | ||||
| 
 | ||||
| 	if (hmac_mode != 0) { | ||||
| 		fmpfw_info->s.step = INIT; | ||||
| 		fmpfw_info->hmac_mode = 1; | ||||
| 		fmpfw_info->key = (uint32_t)virt_to_phys(mackey); | ||||
| 		__flush_dcache_area(mackey, mackeylen); | ||||
| 		fmpfw_info->key_len = mackeylen; | ||||
| 		__flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); | ||||
| 		addr = virt_to_phys(fmpfw_info); | ||||
| 		ret = exynos_smc(SMC_CMD_FMP, FMP_FW_HMAC_SHA2_TEST, (uint32_t)addr, 0); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Fail to smc call for FMPFW HMAC SHA256 init. ret = 0x%x\n", ret); | ||||
| 			ret = -EFAULT; | ||||
| 			goto error_hmac_smc; | ||||
| 		} | ||||
| 	} else { | ||||
| 		fmpfw_info->s.step = INIT; | ||||
| 		fmpfw_info->hmac_mode = 0; | ||||
| 		fmpfw_info->key = 0; | ||||
| 		fmpfw_info->key_len = 0; | ||||
| 		__flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); | ||||
| 		addr = virt_to_phys(fmpfw_info); | ||||
| 
 | ||||
| 		ret = exynos_smc(SMC_CMD_FMP, FMP_FW_SHA2_TEST, (uint32_t)addr, 0); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Fail to smc call for FMPFW SHA256 init. ret = 0x%x\n", ret); | ||||
| 			ret = -EFAULT; | ||||
| 			goto error_sha_smc; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	hdata->digestsize = SHA256_DIGEST_SIZE; | ||||
| 	hdata->alignmask = 0x0; | ||||
| 	hdata->fmpfw_info = fmpfw_info; | ||||
| 
 | ||||
| 	hdata->async.result = kzalloc(sizeof(*hdata->async.result), GFP_KERNEL); | ||||
| 	if (unlikely(!hdata->async.result)) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	init_completion(&hdata->async.result->completion); | ||||
| 
 | ||||
| 	hdata->init = 1; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| error_hmac_smc: | ||||
| error_sha_smc: | ||||
| 	kfree(fmpfw_info); | ||||
| error_alloc_info: | ||||
| 	hdata->fmpfw_info = NULL; | ||||
| error: | ||||
| 	kfree(hdata->async.result); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void fmpfw_hash_deinit(struct hash_data *hdata) | ||||
| { | ||||
| 	if (hdata->init) { | ||||
| 		kfree(hdata->async.result); | ||||
| 		hdata->init = 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ssize_t fmpfw_hash_update(struct fmp_info *info, struct hash_data *hdata, | ||||
| 				struct scatterlist *sg, size_t len) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	unsigned long addr; | ||||
| 	struct device *dev = info->dev; | ||||
| 	struct hmac_sha256_fmpfw_info *fmpfw_info = hdata->fmpfw_info; | ||||
| 
 | ||||
| 	fmpfw_info->s.step = UPDATE; | ||||
| 	fmpfw_info->s.input = (uint32_t)sg_phys(sg); | ||||
| 	__flush_dcache_area(sg_virt(sg), len); | ||||
| 	fmpfw_info->s.input_len = len; | ||||
| 	__flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); | ||||
| 	addr = virt_to_phys(fmpfw_info); | ||||
| 
 | ||||
| 	reinit_completion(&hdata->async.result->completion); | ||||
| 	if (fmpfw_info->hmac_mode) { | ||||
| 		ret = exynos_smc(SMC_CMD_FMP, FMP_FW_HMAC_SHA2_TEST, addr, 0); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Fail to smc call for FMPFW HMAC SHA256 update. ret = 0x%x\n", ret); | ||||
| 			ret = -EFAULT; | ||||
| 		} | ||||
| 	} else { | ||||
| 		ret = exynos_smc(SMC_CMD_FMP, FMP_FW_SHA2_TEST, addr, 0); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Fail to smc call for FMPFW SHA256 update. ret = 0x%x\n", ret); | ||||
| 			ret = -EFAULT; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return waitfor(info, hdata->async.result, ret); | ||||
| } | ||||
| 
 | ||||
| int fmpfw_hash_final(struct fmp_info *info, struct hash_data *hdata, void *output) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	unsigned long addr; | ||||
| 	struct device *dev = info->dev; | ||||
| 	struct hmac_sha256_fmpfw_info *fmpfw_info = hdata->fmpfw_info; | ||||
| 
 | ||||
| 	memset(output, 0, hdata->digestsize); | ||||
| 	fmpfw_info->s.step = FINAL; | ||||
| 	fmpfw_info->s.output = (uint32_t)virt_to_phys(output); | ||||
| 	__flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); | ||||
| 	addr = virt_to_phys(fmpfw_info); | ||||
| 
 | ||||
| 	reinit_completion(&hdata->async.result->completion); | ||||
| 	__dma_unmap_area((void *)output, hdata->digestsize, DMA_FROM_DEVICE); | ||||
| 	if (fmpfw_info->hmac_mode) { | ||||
| 		ret = exynos_smc(SMC_CMD_FMP, FMP_FW_HMAC_SHA2_TEST, addr, 0); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Fail to smc call for FMPFW HMAC SHA256 final. ret = 0x%x\n", ret); | ||||
| 			ret = -EFAULT; | ||||
| 		} | ||||
| 	} else { | ||||
| 		ret = exynos_smc(SMC_CMD_FMP, FMP_FW_SHA2_TEST, addr, 0); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Fail to smc call for FMPFW SHA256 final. ret = 0x%x\n", ret); | ||||
| 			ret = -EFAULT; | ||||
| 		} | ||||
| 	} | ||||
| 	__dma_unmap_area((void *)output, hdata->digestsize, DMA_FROM_DEVICE); | ||||
| 
 | ||||
| 	if (fmpfw_info->hmac_mode) | ||||
| 		dev_info(dev, "fmp fw hmac sha256 F/W final is done\n"); | ||||
| 	else | ||||
| 		dev_info(dev, "fmp fw sha256 F/W final is done\n"); | ||||
| 
 | ||||
| 	kfree(fmpfw_info); | ||||
| 	return waitfor(info, hdata->async.result, ret); | ||||
| } | ||||
| 
 | ||||
| int fmpdev_hash_init(struct fmp_info *info, struct hash_data *hdata, | ||||
| 			const char *alg_name, | ||||
| 			int hmac_mode, void *mackey, size_t mackeylen) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	hdata->fmpfw_info = NULL; | ||||
| 	hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0); | ||||
| 	if (unlikely(IS_ERR(hdata->async.s))) { | ||||
| 		dev_err(dev, "Failed to load transform for %s\n", alg_name); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Copy the key from user and set to TFM. */ | ||||
| 	if (hmac_mode != 0) { | ||||
| 		ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "Setting hmac key failed for %s-%zu.\n", | ||||
| 					alg_name, mackeylen*8); | ||||
| 			ret = -EINVAL; | ||||
| 			goto error; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); | ||||
| 	hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); | ||||
| 
 | ||||
| 	hdata->async.result = kzalloc(sizeof(*hdata->async.result), GFP_KERNEL); | ||||
| 	if (unlikely(!hdata->async.result)) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	init_completion(&hdata->async.result->completion); | ||||
| 
 | ||||
| 	hdata->async.request = ahash_request_alloc(hdata->async.s, GFP_KERNEL); | ||||
| 	if (unlikely(!hdata->async.request)) { | ||||
| 		dev_err(dev, "error allocating async crypto request\n"); | ||||
| 		ret = -ENOMEM; | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	ahash_request_set_callback(hdata->async.request, | ||||
| 			CRYPTO_TFM_REQ_MAY_BACKLOG, | ||||
| 			fmpdev_complete, hdata->async.result); | ||||
| 
 | ||||
| 	ret = crypto_ahash_init(hdata->async.request); | ||||
| 	if (unlikely(ret)) { | ||||
| 		dev_err(dev, "error in fmpdev_hash_init()\n"); | ||||
| 		goto error_request; | ||||
| 	} | ||||
| 
 | ||||
| 	hdata->init = 1; | ||||
| 	return 0; | ||||
| 
 | ||||
| error_request: | ||||
| 	ahash_request_free(hdata->async.request); | ||||
| error: | ||||
| 	kfree(hdata->async.result); | ||||
| 	crypto_free_ahash(hdata->async.s); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void fmpdev_hash_deinit(struct hash_data *hdata) | ||||
| { | ||||
| 	if (hdata->init) { | ||||
| 		if (hdata->async.request) | ||||
| 			ahash_request_free(hdata->async.request); | ||||
| 		kfree(hdata->async.result); | ||||
| 		if (hdata->async.s) | ||||
| 			crypto_free_ahash(hdata->async.s); | ||||
| 		hdata->init = 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int fmpdev_hash_reset(struct fmp_info *info, struct hash_data *hdata) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	ret = crypto_ahash_init(hdata->async.request); | ||||
| 	if (unlikely(ret)) { | ||||
| 		dev_err(dev, "error in crypto_hash_init()\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ssize_t fmpdev_hash_update(struct fmp_info *info, struct hash_data *hdata, | ||||
| 				struct scatterlist *sg, size_t len) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	reinit_completion(&hdata->async.result->completion); | ||||
| 	ahash_request_set_crypt(hdata->async.request, sg, NULL, len); | ||||
| 
 | ||||
| 	ret = crypto_ahash_update(hdata->async.request); | ||||
| 
 | ||||
| 	return waitfor(info, hdata->async.result, ret); | ||||
| } | ||||
| 
 | ||||
| int fmpdev_hash_final(struct fmp_info *info, struct hash_data *hdata, void *output) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	reinit_completion(&hdata->async.result->completion); | ||||
| 	ahash_request_set_crypt(hdata->async.request, NULL, output, 0); | ||||
| 
 | ||||
| 	ret = crypto_ahash_final(hdata->async.request); | ||||
| 
 | ||||
| 	return waitfor(info, hdata->async.result, ret); | ||||
| } | ||||
| 
 | ||||
| static int fmp_n_crypt(struct fmp_info *info, struct csession *ses_ptr, | ||||
| 		struct crypt_op *cop, | ||||
| 		struct scatterlist *src_sg, struct scatterlist *dst_sg, | ||||
| 		uint32_t len) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct device *dev = info->dev; | ||||
| 
 | ||||
| 	if (cop->op == COP_ENCRYPT) { | ||||
| 		if (ses_ptr->hdata.init != 0) { | ||||
| 			if (!ses_ptr->hdata.fmpfw_info) | ||||
| 				ret = fmpdev_hash_update(info, &ses_ptr->hdata, | ||||
| 								src_sg, len); | ||||
| 			else | ||||
| 				ret = fmpfw_hash_update(info, &ses_ptr->hdata, | ||||
| 								src_sg, len); | ||||
| 			if (unlikely(ret)) | ||||
| 				goto out_err; | ||||
| 		} | ||||
| 
 | ||||
| 		if (ses_ptr->cdata.init != 0) { | ||||
| 			ret = fmpdev_cipher_encrypt(info, &ses_ptr->cdata, | ||||
| 						src_sg, dst_sg, len); | ||||
| 			if (unlikely(ret)) | ||||
| 				goto out_err; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (ses_ptr->cdata.init != 0) { | ||||
| 			ret = fmpdev_cipher_decrypt(info, &ses_ptr->cdata, | ||||
| 						src_sg, dst_sg, len); | ||||
| 			if (unlikely(ret)) | ||||
| 				goto out_err; | ||||
| 		} | ||||
| 
 | ||||
| 		if (ses_ptr->hdata.init != 0) { | ||||
| 			if (!ses_ptr->hdata.fmpfw_info) | ||||
| 				ret = fmpdev_hash_update(info, &ses_ptr->hdata, | ||||
| 								dst_sg, len); | ||||
| 			else | ||||
| 				ret = fmpfw_hash_update(info, &ses_ptr->hdata, | ||||
| 								dst_sg, len); | ||||
| 			if (unlikely(ret)) | ||||
| 				goto out_err; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| out_err: | ||||
| 	dev_err(dev, "FMP crypt failure: %d\n", ret); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int __fmp_run_std(struct fmp_info *info, | ||||
| 		struct csession *ses_ptr, struct crypt_op *cop) | ||||
| { | ||||
| 	char *data; | ||||
| 	struct device *dev = info->dev; | ||||
| 	char __user *src, *dst; | ||||
| 	size_t nbytes, bufsize; | ||||
| 	struct scatterlist sg; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	nbytes = cop->len; | ||||
| 	data = (char *)__get_free_page(GFP_KERNEL); | ||||
| 	if (unlikely(!data)) { | ||||
| 		dev_err(dev, "Error getting free page.\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; | ||||
| 
 | ||||
| 	src = cop->src; | ||||
| 	dst = cop->dst; | ||||
| 
 | ||||
| 	while (nbytes > 0) { | ||||
| 		size_t current_len = nbytes > bufsize ? bufsize : nbytes; | ||||
| 
 | ||||
| 		if (unlikely(copy_from_user(data, src, current_len))) { | ||||
| 			dev_err(dev, "Error copying %d bytes from user address %p\n", | ||||
| 						(int)current_len, src); | ||||
| 			ret = -EFAULT; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		sg_init_one(&sg, data, current_len); | ||||
| 		ret = fmp_n_crypt(info, ses_ptr, cop, &sg, &sg, current_len); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "fmp_n_crypt failed\n"); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (ses_ptr->cdata.init != 0) { | ||||
| 			if (unlikely(copy_to_user(dst, data, current_len))) { | ||||
| 				dev_err(dev, "could not copy to user\n"); | ||||
| 				ret = -EFAULT; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		dst += current_len; | ||||
| 		nbytes -= current_len; | ||||
| 		src += current_len; | ||||
| 	} | ||||
| 	free_page((unsigned long)data); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int fmp_run(struct fmp_info *info, struct fcrypt *fcr, struct kernel_crypt_op *kcop) | ||||
| { | ||||
| 	struct device *dev = info->dev; | ||||
| 	struct csession *ses_ptr; | ||||
| 	struct crypt_op *cop = &kcop->cop; | ||||
| 	int ret = -EINVAL; | ||||
| 
 | ||||
| 	if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { | ||||
| 		dev_err(dev, "invalid operation op=%u\n", cop->op); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* this also enters ses_ptr->sem */ | ||||
| 	ses_ptr = fmp_get_session_by_sid(fcr, cop->ses); | ||||
| 	if (unlikely(!ses_ptr)) { | ||||
| 		dev_err(dev, "invalid session ID=0x%08X\n", cop->ses); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((ses_ptr->cdata.init != 0) && (cop->len > PAGE_SIZE)) { | ||||
| 		dev_err(dev, "Invalid input length. len = %d\n", cop->len); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET) && \ | ||||
| 				!ses_ptr->hdata.fmpfw_info) { | ||||
| 		ret = fmpdev_hash_reset(info, &ses_ptr->hdata); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "error in fmpdev_hash_reset()"); | ||||
| 			goto out_unlock; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ses_ptr->cdata.init != 0) { | ||||
| 		int blocksize = ses_ptr->cdata.blocksize; | ||||
| 
 | ||||
| 		if (unlikely(cop->len % blocksize)) { | ||||
| 			dev_err(dev, | ||||
| 				"data size (%u) isn't a multiple " | ||||
| 				"of block size (%u)\n", | ||||
| 				cop->len, blocksize); | ||||
| 			ret = -EINVAL; | ||||
| 			goto out_unlock; | ||||
| 		} | ||||
| 
 | ||||
| 		if (cop->flags == COP_FLAG_AES_CBC) | ||||
| 			fmpdev_cipher_set_iv(info, &ses_ptr->cdata, kcop->iv, 16); | ||||
| 		else if (cop->flags == COP_FLAG_AES_XTS) | ||||
| 			fmpdev_cipher_set_iv(info, &ses_ptr->cdata, (uint8_t *)&cop->data_unit_seqnumber, 16); | ||||
| 		else { | ||||
| 			ret = -EINVAL; | ||||
| 			goto out_unlock; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (likely(cop->len)) { | ||||
| 		ret = __fmp_run_std(info, ses_ptr, &kcop->cop); | ||||
| 		if (unlikely(ret)) | ||||
| 			goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ses_ptr->hdata.init != 0 && | ||||
| 		((cop->flags & COP_FLAG_FINAL) || | ||||
| 		   (!(cop->flags & COP_FLAG_UPDATE) || cop->len == 0))) { | ||||
| 		if (!ses_ptr->hdata.fmpfw_info) | ||||
| 			ret = fmpdev_hash_final(info, &ses_ptr->hdata, kcop->hash_output); | ||||
| 		else | ||||
| 			ret = fmpfw_hash_final(info, &ses_ptr->hdata, kcop->hash_output); | ||||
| 		if (unlikely(ret)) { | ||||
| 			dev_err(dev, "CryptoAPI failure: %d\n", ret); | ||||
| 			goto out_unlock; | ||||
| 		} | ||||
| 		kcop->digestsize = ses_ptr->hdata.digestsize; | ||||
| 	} | ||||
| 
 | ||||
| out_unlock: | ||||
| 	fmp_put_session(ses_ptr); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int fmp_run_AES_CBC_MCT(struct fmp_info *info, struct fcrypt *fcr, | ||||
| 			struct kernel_crypt_op *kcop) | ||||
| { | ||||
| 	struct device *dev = info->dev; | ||||
| 	struct csession *ses_ptr; | ||||
| 	struct crypt_op *cop = &kcop->cop; | ||||
| 	char **Ct = 0; | ||||
| 	char **Pt = 0; | ||||
| 	int ret = 0, k = 0; | ||||
| 
 | ||||
| 	if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { | ||||
| 		dev_err(dev, "invalid operation op=%u\n", cop->op); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* this also enters ses_ptr->sem */ | ||||
| 	ses_ptr = fmp_get_session_by_sid(fcr, cop->ses); | ||||
| 	if (unlikely(!ses_ptr)) { | ||||
| 		dev_err(dev, "invalid session ID=0x%08X\n", cop->ses); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cop->len > PAGE_SIZE) { | ||||
| 		dev_err(dev, "Invalid input length. len = %d\n", cop->len); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ses_ptr->cdata.init != 0) { | ||||
| 		int blocksize = ses_ptr->cdata.blocksize; | ||||
| 
 | ||||
| 		if (unlikely(cop->len % blocksize)) { | ||||
| 			dev_err(dev, | ||||
| 				"data size (%u) isn't a multiple " | ||||
| 				"of block size (%u)\n", | ||||
| 				cop->len, blocksize); | ||||
| 			ret = -EINVAL; | ||||
| 			goto out_unlock; | ||||
| 		} | ||||
| 
 | ||||
| 		fmpdev_cipher_set_iv(info, &ses_ptr->cdata, kcop->iv, 16); | ||||
| 	} | ||||
| 
 | ||||
| 	if (likely(cop->len)) { | ||||
| 		if (cop->flags & COP_FLAG_AES_CBC_MCT) { | ||||
| 		// do MCT here
 | ||||
| 		char *data; | ||||
| 	        char __user *src, *dst, *secondLast; | ||||
| 	        struct scatterlist sg; | ||||
| 	        size_t nbytes, bufsize; | ||||
| 	        int ret = 0; | ||||
| 	        int y = 0; | ||||
| 
 | ||||
| 	        nbytes = cop->len; | ||||
| 	        data = (char *)__get_free_page(GFP_KERNEL); | ||||
| 		if (unlikely(!data)) { | ||||
| 			dev_err(dev, "Error getting free page.\n"); | ||||
| 			return -ENOMEM; | ||||
| 		} | ||||
| 
 | ||||
| 		Pt = (char**)kmalloc(1000 * sizeof(char*), GFP_KERNEL); | ||||
| 		for (k=0; k<1000; k++) | ||||
| 		       Pt[k]= (char*)kmalloc(nbytes, GFP_KERNEL); | ||||
| 
 | ||||
| 		Ct = (char**)kmalloc(1000 * sizeof(char*), GFP_KERNEL); | ||||
| 		for (k=0; k<1000; k++) | ||||
| 		       Ct[k]= (char*)kmalloc(nbytes, GFP_KERNEL); | ||||
| 
 | ||||
| 	        bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; | ||||
| 
 | ||||
| 	        src = cop->src; | ||||
| 	        dst = cop->dst; | ||||
| 	        secondLast = cop->secondLastEncodedData; | ||||
| 
 | ||||
| 		if (unlikely(copy_from_user(data, src, nbytes))) { | ||||
| 			printk(KERN_ERR "Error copying %d bytes from user address %p.\n", (int)nbytes, src); | ||||
| 		        ret = -EFAULT; | ||||
| 		        goto out_err; | ||||
| 	        } | ||||
| 
 | ||||
| 	        sg_init_one(&sg, data, nbytes); | ||||
| 		for (y = 0; y < 1000; y++) { | ||||
| 			memcpy(Pt[y], data, nbytes); | ||||
| 			ret = fmp_n_crypt(info, ses_ptr, cop, &sg, &sg, nbytes); | ||||
| 			memcpy(Ct[y], data, nbytes); | ||||
| 
 | ||||
| 			if (y == 998) { | ||||
| 				if (unlikely(copy_to_user(secondLast, data, nbytes))) | ||||
| 					printk(KERN_ERR "unable to copy second last data for AES_CBC_MCT\n"); | ||||
| 				else | ||||
| 					printk(KERN_ERR "KAMAL copied secondlast data\n"); | ||||
| 			} | ||||
| 
 | ||||
| 			if( y == 0) { | ||||
| 				memcpy(data, kcop->iv, kcop->ivlen); | ||||
| 			} else { | ||||
| 				if(y != 999) | ||||
| 					memcpy(data, Ct[y-1], nbytes); | ||||
| 			} | ||||
| 
 | ||||
| 			if (unlikely(ret)) { | ||||
| 				printk(KERN_ERR "fmp_n_crypt failed.\n"); | ||||
| 				goto out_err; | ||||
| 			} | ||||
| 
 | ||||
| 			if (cop->op == COP_ENCRYPT) | ||||
| 				fmpdev_cipher_set_iv(info, &ses_ptr->cdata, Ct[y], 16); | ||||
| 			else if (cop->op == COP_DECRYPT) | ||||
| 				fmpdev_cipher_set_iv(info, &ses_ptr->cdata, Pt[y], 16); | ||||
| 		} // for loop
 | ||||
| 
 | ||||
| 		if (ses_ptr->cdata.init != 0) { | ||||
| 			if (unlikely(copy_to_user(dst, data, nbytes))) { | ||||
| 				printk(KERN_ERR "could not copy to user.\n"); | ||||
| 				ret = -EFAULT; | ||||
| 				goto out_err; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (k=0; k<1000; k++) { | ||||
| 			kfree(Ct[k]); | ||||
| 			kfree(Pt[k]); | ||||
| 		} | ||||
| 
 | ||||
| 		kfree(Ct); | ||||
| 		kfree(Pt); | ||||
| 		free_page((unsigned long)data); | ||||
| 		} else | ||||
| 			goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| out_unlock: | ||||
| 	fmp_put_session(ses_ptr); | ||||
| 	return ret; | ||||
| 
 | ||||
| out_err: | ||||
| 	fmp_put_session(ses_ptr); | ||||
| 	dev_info(dev, "CryptoAPI failure: %d\n", ret); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 awab228
						awab228