Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c71fc9d authored by William Clark's avatar William Clark Committed by Gerrit - the friendly Code Review server
Browse files

msm: crypto: Remove FIPS software implementation code



Remove FIPS software implementation code, since the hardware
crypto engine in 8996 is FIPS140-2 certified.

Change-Id: Ia8ad296ce1d71537492588399dc1d16d085d8e65
Signed-off-by: default avatarWilliam Clark <wclark@codeaurora.org>
parent 783bbd7d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -30,4 +30,4 @@ obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
obj-$(CONFIG_HW_RANDOM_MSM_LEGACY) += msm_rng.o fips_drbg.o ctr_drbg.o msm_fips_selftest.o
obj-$(CONFIG_HW_RANDOM_MSM_LEGACY) += msm_rng.o

drivers/char/hw_random/ctr_drbg.c

deleted100644 → 0
+0 −940
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/msm-bus.h>
#include <linux/qrng.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#include <linux/errno.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <linux/string.h>
#include <linux/platform_data/qcom_crypto_device.h>

#include "ctr_drbg.h"
#include "fips_drbg.h"

#define E_FAILURE 0Xffff
#define E_SUCCESS 0

#define AES128_KEY_SIZE   (16)
#define AES128_BLOCK_SIZE (16)

#define AES_TEXT_LENGTH (64)
#define MAX_TEXT_LENGTH (2048)

uint8_t df_initial_k[16] = "\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf";

static void _crypto_cipher_test_complete(struct crypto_async_request *req,
				int err)
{
	struct msm_ctr_tcrypt_result_s *res = NULL;

	if (!req)
		return;

	res = req->data;
	if (!res)
		return;

	if (err == -EINPROGRESS)
		return;
	res->err = err;
	complete(&res->completion);
}

static int ctr_aes_init(struct ctr_drbg_ctx_s *ctx)
{
	int status = 0;

	ctx->aes_ctx.tfm = crypto_alloc_ablkcipher("qcom-ecb(aes)", 0, 0);
	if (IS_ERR(ctx->aes_ctx.tfm) || (NULL == ctx->aes_ctx.tfm)) {
		pr_info("%s: qcom-ecb(aes) failed", __func__);
		ctx->aes_ctx.tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, 0);
		pr_info("ctx->aes_ctx.tfm = %p\n", ctx->aes_ctx.tfm);
		if (IS_ERR(ctx->aes_ctx.tfm) || (NULL == ctx->aes_ctx.tfm)) {
			pr_err("%s: qcom-ecb(aes) failed\n", __func__);
			status = -E_FAILURE;
			goto out;
		}
	}

	ctx->aes_ctx.req = ablkcipher_request_alloc(ctx->aes_ctx.tfm,
							GFP_KERNEL);
	if (IS_ERR(ctx->aes_ctx.req) || (NULL == ctx->aes_ctx.req)) {
		pr_info("%s: Failed to allocate request.\n", __func__);
		status = -E_FAILURE;
		goto clr_tfm;
	}

	ablkcipher_request_set_callback(ctx->aes_ctx.req,
				CRYPTO_TFM_REQ_MAY_BACKLOG,
				_crypto_cipher_test_complete,
				&ctx->aes_ctx.result);

	memset(&ctx->aes_ctx.input, 0, sizeof(struct msm_ctr_buffer_s));
	memset(&ctx->aes_ctx.output, 0, sizeof(struct msm_ctr_buffer_s));

	/* Allocate memory. */
	ctx->aes_ctx.input.virt_addr  = kmalloc(AES128_BLOCK_SIZE,
						GFP_KERNEL | __GFP_DMA);
	if (NULL == ctx->aes_ctx.input.virt_addr) {
		pr_debug("%s: Failed to input memory.\n", __func__);
		status = -E_FAILURE;
		goto clr_req;
	}
	ctx->aes_ctx.output.virt_addr = kmalloc(AES128_BLOCK_SIZE,
						GFP_KERNEL | __GFP_DMA);
	if (NULL == ctx->aes_ctx.output.virt_addr) {
		pr_debug("%s: Failed to output memory.\n", __func__);
		status = -E_FAILURE;
		goto clr_input;
	}

	/*--------------------------------------------------------------------
	Set DF AES mode
	----------------------------------------------------------------------*/
	ctx->df_aes_ctx.tfm = crypto_alloc_ablkcipher("qcom-ecb(aes)", 0, 0);
	if ((NULL == ctx->df_aes_ctx.tfm) || IS_ERR(ctx->df_aes_ctx.tfm)) {
		pr_info("%s: qcom-ecb(aes) failed", __func__);
		ctx->df_aes_ctx.tfm = crypto_alloc_ablkcipher("ecb(aes)", 0, 0);
		if (IS_ERR(ctx->df_aes_ctx.tfm) ||
			(NULL == ctx->df_aes_ctx.tfm)) {
			pr_err("%s: ecb(aes) failed", __func__);
			status = -E_FAILURE;
			goto clr_output;
		}
	}

	ctx->df_aes_ctx.req = ablkcipher_request_alloc(ctx->df_aes_ctx.tfm,
							GFP_KERNEL);
	if (IS_ERR(ctx->df_aes_ctx.req) || (NULL == ctx->df_aes_ctx.req)) {
		pr_debug(": Failed to allocate request.\n");
		status = -E_FAILURE;
		goto clr_df_tfm;
	}

	ablkcipher_request_set_callback(ctx->df_aes_ctx.req,
				CRYPTO_TFM_REQ_MAY_BACKLOG,
				_crypto_cipher_test_complete,
				&ctx->df_aes_ctx.result);

	memset(&ctx->df_aes_ctx.input, 0, sizeof(struct msm_ctr_buffer_s));
	memset(&ctx->df_aes_ctx.output, 0, sizeof(struct msm_ctr_buffer_s));

	ctx->df_aes_ctx.input.virt_addr  = kmalloc(AES128_BLOCK_SIZE,
						GFP_KERNEL | __GFP_DMA);
	if (NULL == ctx->df_aes_ctx.input.virt_addr) {
		pr_debug(": Failed to input memory.\n");
		status = -E_FAILURE;
		goto clr_df_req;
	}

	ctx->df_aes_ctx.output.virt_addr = kmalloc(AES128_BLOCK_SIZE,
						GFP_KERNEL | __GFP_DMA);
	if (NULL == ctx->df_aes_ctx.output.virt_addr) {
		pr_debug(": Failed to output memory.\n");
		status = -E_FAILURE;
		goto clr_df_input;
	}

	goto out;

clr_df_input:
	if (ctx->df_aes_ctx.input.virt_addr) {
		kzfree(ctx->df_aes_ctx.input.virt_addr);
		ctx->df_aes_ctx.input.virt_addr = NULL;
	}
clr_df_req:
	if (ctx->df_aes_ctx.req) {
		ablkcipher_request_free(ctx->df_aes_ctx.req);
		ctx->df_aes_ctx.req = NULL;
	}
clr_df_tfm:
	if (ctx->df_aes_ctx.tfm) {
			crypto_free_ablkcipher(ctx->df_aes_ctx.tfm);
			ctx->df_aes_ctx.tfm = NULL;
		}
clr_output:
	if (ctx->aes_ctx.output.virt_addr) {
		kzfree(ctx->aes_ctx.output.virt_addr);
		ctx->aes_ctx.output.virt_addr = NULL;
	}
clr_input:
	if (ctx->aes_ctx.input.virt_addr) {
		kzfree(ctx->aes_ctx.input.virt_addr);
		ctx->aes_ctx.input.virt_addr = NULL;
	}
clr_req:
	if (ctx->aes_ctx.req) {
		ablkcipher_request_free(ctx->aes_ctx.req);
		ctx->aes_ctx.req = NULL;
	}
clr_tfm:
	if (ctx->aes_ctx.tfm) {
		crypto_free_ablkcipher(ctx->aes_ctx.tfm);
		ctx->aes_ctx.tfm = NULL;
	}
out:
	return status;
}

/*
 * Increments the V field in *ctx
 */
static void increment_V(struct ctr_drbg_ctx_s *ctx)
{
	unsigned sum = 1;
	int i;
	uint8_t *p = &ctx->seed.key_V.V[0];

	/*
	 * To make known answer tests work, this has to be done big_endian.
	 * So we just do it by bytes.
	 * since we are using AES-128, the key size is 16 bytes.
	 */
	for (i = 15; sum != 0 && i >= 0; --i) {
		sum += p[i];
		p[i] = (sum & 0xff);
		sum >>= 8;
	}

	return;
}

/*
 * The NIST update function.  It updates the key and V to new values
 * (to prevent backtracking) and optionally stirs in data.  data may
 * be null, otherwise *data is from 0 to 256 bits long.
 * keysched is an optional keyschedule to use as an optimization.  It
 * must be consistent with the key in *ctx.  No changes are made to
 * *ctx until it is assured that there will be no failures.  Note that
 * data_len is in bytes.  (That may not be offical NIST
 * recommendation, but I do it anyway; they say "or equivalent" and
 * this is equivalent enough.)
 */
static enum ctr_drbg_status_t
update(struct ctr_drbg_ctx_s *ctx, const uint8_t *data, size_t data_len)
{
	uint8_t temp[32];
	unsigned int i;
	int rc;
	struct scatterlist sg_in, sg_out;

	for (i = 0; i < 2; ++i) {
		increment_V(ctx);
		init_completion(&ctx->aes_ctx.result.completion);

		/*
		 * Note: personalize these called routines for
		 * specific testing.
		 */
		memcpy(ctx->aes_ctx.input.virt_addr,
			ctx->seed.key_V.V,
			CTR_DRBG_BLOCK_LEN_BYTES);

		crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);

		/* Encrypt some clear text! */

		sg_init_one(&sg_in,
			ctx->aes_ctx.input.virt_addr,
			AES128_BLOCK_SIZE);
		sg_init_one(&sg_out,
			ctx->aes_ctx.output.virt_addr,
			AES128_BLOCK_SIZE);
		ablkcipher_request_set_crypt(ctx->aes_ctx.req,
						&sg_in,
						&sg_out,
						CTR_DRBG_BLOCK_LEN_BYTES,
						NULL);

		rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);

		switch (rc) {
		case 0:
			break;
		case -EINPROGRESS:
		case -EBUSY:
			rc = wait_for_completion_interruptible(
				&ctx->aes_ctx.result.completion);
			if (!rc && !ctx->aes_ctx.result.err) {
				reinit_completion(
					&ctx->aes_ctx.result.completion);
				break;
			}
		/* fall through */
		default:
			pr_debug("crypto_ablkcipher_encrypt returned");
			pr_debug(" with %d result %d on iteration\n",
				rc,
				ctx->aes_ctx.result.err);
			break;
		}

		init_completion(&ctx->aes_ctx.result.completion);

		memcpy(temp + AES128_BLOCK_SIZE * i,
			ctx->aes_ctx.output.virt_addr,
			AES128_BLOCK_SIZE);
	}

	if (data_len > 0)
		pr_debug("in upadte, data_len = %zu\n", data_len);

	for (i = 0; i < data_len; ++i)
		ctx->seed.as_bytes[i] = temp[i] ^ data[i];

	/* now copy the rest of temp to key and V */
	if (32 > data_len) {
		memcpy(ctx->seed.as_bytes + data_len,
			temp + data_len,
			32 - data_len);
	}

	memset(temp, 0, 32);
	return CTR_DRBG_SUCCESS;
}

/*
 * Reseeds the CTR_DRBG instance with entropy.  entropy_len_bits must
 * be exactly 256.
 */
enum ctr_drbg_status_t ctr_drbg_reseed(struct ctr_drbg_ctx_s *ctx,
					const void     *entropy,
					size_t         entropy_len_bits)
{
	enum ctr_drbg_status_t update_rv;
	uint8_t           seed_material[32];
	int               rc;

	if (ctx == NULL || entropy == NULL)
		return CTR_DRBG_INVALID_ARG;

	update_rv = block_cipher_df(ctx,
				(uint8_t *)entropy,
				(entropy_len_bits / 8),
				seed_material,
				32
				);
	if (CTR_DRBG_SUCCESS != update_rv) {
		memset(seed_material, 0, 32);
		return CTR_DRBG_GENERAL_ERROR;
	}

	rc = crypto_ablkcipher_setkey(ctx->aes_ctx.tfm,
				ctx->seed.key_V.key,
				AES128_KEY_SIZE
				);
	if (rc) {
		memset(seed_material, 0, 32);
		pr_debug("set-key in Instantiate failed, returns with %d", rc);
		return CTR_DRBG_GENERAL_ERROR;
	}

	pr_debug("ctr_drbg_reseed, to call update\n");
	update_rv = update(ctx, (const uint8_t *)seed_material, 32);
	pr_debug("ctr_drbg_reseed, after called update\n");
	if (update_rv != CTR_DRBG_SUCCESS) {
		memset(seed_material, 0, 32);
		return update_rv;
	}
	ctx->reseed_counter = 1;  /* think 0 but SP 800-90 says 1 */

	memset(seed_material, 0, 32);

	return CTR_DRBG_SUCCESS;

}

/*
 * The NIST instantiate function.  entropy_len_bits must be exactly
 * 256.  After reseed_interval generate requests, generated requests
 * will fail  until the CTR_DRBG instance is reseeded. As per NIST SP
 * 800-90, an error is returned if reseed_interval > 2^48.
 */

enum ctr_drbg_status_t
ctr_drbg_instantiate(struct ctr_drbg_ctx_s *ctx,
			const uint8_t *entropy,
			size_t entropy_len_bits,
			const uint8_t *nonce,
			size_t nonce_len_bits,
			unsigned long long reseed_interval)
{

	enum ctr_drbg_status_t update_rv;
	uint8_t           seed_material[32];
	uint8_t           df_input[32];
	int               rc;

	if (ctx == NULL || entropy == NULL || nonce == NULL)
		return CTR_DRBG_INVALID_ARG;
	if (((nonce_len_bits / 8) + (entropy_len_bits / 8)) > 32) {
		pr_info("\nentropy_len_bits + nonce_len_bits is too long!");
		pr_info("\nnonce len: %zu, entropy: %zu\n",
			nonce_len_bits, entropy_len_bits);
		return CTR_DRBG_INVALID_ARG + 1;
	}

	if (reseed_interval > (1ULL << 48))
		return CTR_DRBG_INVALID_ARG + 2;

	ctr_aes_init(ctx);

	memset(ctx->seed.as_bytes, 0, sizeof(ctx->seed.as_bytes));
	memcpy(df_input, (uint8_t *)entropy, entropy_len_bits / 8);
	memcpy(df_input + (entropy_len_bits / 8), nonce, nonce_len_bits / 8);

	update_rv = block_cipher_df(ctx, df_input, 24, seed_material, 32);
	memset(df_input, 0, 32);

	if (CTR_DRBG_SUCCESS != update_rv) {
		pr_debug("block_cipher_df failed, returns %d", update_rv);
		memset(seed_material, 0, 32);
		return CTR_DRBG_GENERAL_ERROR;
	}

	rc = crypto_ablkcipher_setkey(ctx->aes_ctx.tfm,
				ctx->seed.key_V.key,
				AES128_KEY_SIZE);
	if (rc) {
		pr_debug("crypto_ablkcipher_setkey API failed: %d", rc);
		memset(seed_material, 0, 32);
		return CTR_DRBG_GENERAL_ERROR;
	}
	update_rv = update(ctx, (const uint8_t *)seed_material, 32);
	if (update_rv != CTR_DRBG_SUCCESS) {
		memset(seed_material, 0, 32);
		return update_rv;
	}

	ctx->reseed_counter = 1;  /* think 0 but SP 800-90 says 1 */
	ctx->reseed_interval = reseed_interval;

	memset(seed_material, 0, 32);

	pr_debug(" return from ctr_drbg_instantiate\n");

	return CTR_DRBG_SUCCESS;
}

/*
 * Generate random bits. len_bits is specified in bits, as required by
 * NIST SP800-90.  It fails with CTR_DRBG_NEEDS_RESEED if the number
 * of generates since instantiation or the last reseed >= the
 * reseed_interval supplied at instantiation.  len_bits must be a
 * multiple of 8.  len_bits must not exceed 2^19, as per NIST SP
 * 800-90. Optionally stirs in additional_input which is
 * additional_input_len_bits long, and is silently rounded up to a
 * multiple of 8.  CTR_DRBG_INVALID_ARG is returned if any pointer arg
 * is null and the corresponding length is non-zero or if
 * additioanl_input_len_bits > 256.
 */
enum ctr_drbg_status_t
ctr_drbg_generate_w_data(struct ctr_drbg_ctx_s *ctx,
			void   *additional_input,
			size_t additional_input_len_bits,
			void   *buffer,
			size_t len_bits)
{
	size_t total_blocks = (len_bits + 127) / 128;
	enum ctr_drbg_status_t update_rv;
	int rv = 0;
	size_t i;
	int rc;
	struct scatterlist sg_in, sg_out;

	if (ctx == NULL)
		return CTR_DRBG_INVALID_ARG;
	if (buffer == NULL && len_bits > 0)
		return CTR_DRBG_INVALID_ARG;
	if (len_bits % 8 != 0)
		return CTR_DRBG_INVALID_ARG;
	if (len_bits > (1<<19))
		return CTR_DRBG_INVALID_ARG;

	if ((additional_input == NULL && additional_input_len_bits > 0) ||
		additional_input_len_bits > CTR_DRBG_SEED_LEN_BITS)
		return CTR_DRBG_INVALID_ARG;
	if (ctx->reseed_counter > ctx->reseed_interval)
		return CTR_DRBG_NEEDS_RESEED;

	rc = crypto_ablkcipher_setkey(ctx->aes_ctx.tfm,
				ctx->seed.key_V.key,
				AES128_KEY_SIZE);
	if (rc) {
		pr_debug("crypto_ablkcipher_setkey API failed: %d", rc);
		return CTR_DRBG_GENERAL_ERROR;
	}
	if (rv < 0)
		return CTR_DRBG_GENERAL_ERROR;

	if (!ctx->continuous_test_started) {
		increment_V(ctx);
		init_completion(&ctx->aes_ctx.result.completion);
		crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);
		memcpy(ctx->aes_ctx.input.virt_addr, ctx->seed.key_V.V, 16);
		sg_init_one(&sg_in, ctx->aes_ctx.input.virt_addr, 16);
		sg_init_one(&sg_out, ctx->aes_ctx.output.virt_addr, 16);
		ablkcipher_request_set_crypt(ctx->aes_ctx.req, &sg_in, &sg_out,
					CTR_DRBG_BLOCK_LEN_BYTES, NULL);
		rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);
		switch (rc) {
		case 0:
			break;
		case -EINPROGRESS:
		case -EBUSY:
			rc = wait_for_completion_interruptible(
				&ctx->aes_ctx.result.completion);
			if (!rc && !ctx->aes_ctx.result.err) {
				reinit_completion(
					&ctx->aes_ctx.result.completion);
				break;
			}
			/* fall through */
		default:
			pr_debug(":crypto_ablkcipher_encrypt returned with %d result %d on iteration\n",
				rc,
				ctx->aes_ctx.result.err);
			break;
		}
		init_completion(&ctx->aes_ctx.result.completion);

		memcpy(ctx->prev_drn, ctx->aes_ctx.output.virt_addr, 16);
		ctx->continuous_test_started = 1;
	}

	/* Generate the output */
	for (i = 0; i < total_blocks; ++i) {
		/* Increment the counter */
		increment_V(ctx);
		if (((len_bits % 128) != 0) && (i == (total_blocks - 1))) {
			/* last block and it's a fragment */
			init_completion(&ctx->aes_ctx.result.completion);

			/*
			 * Note: personalize these called routines for
			 * specific testing.
			 */

			crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);

			/* Encrypt some clear text! */

			memcpy(ctx->aes_ctx.input.virt_addr,
				ctx->seed.key_V.V,
				16);
			sg_init_one(&sg_in,
				ctx->aes_ctx.input.virt_addr,
				16);
			sg_init_one(&sg_out,
				ctx->aes_ctx.output.virt_addr,
				16);
			ablkcipher_request_set_crypt(ctx->aes_ctx.req,
				&sg_in,
				&sg_out,
				CTR_DRBG_BLOCK_LEN_BYTES,
				NULL);

			rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);

			switch (rc) {
			case 0:
				break;
			case -EINPROGRESS:
			case -EBUSY:
				rc = wait_for_completion_interruptible(
					&ctx->aes_ctx.result.completion);
				if (!rc && !ctx->aes_ctx.result.err) {
					reinit_completion(
						&ctx->aes_ctx.result.completion);
					break;
				}
				/* fall through */
			default:
				break;
			}

			init_completion(&ctx->aes_ctx.result.completion);

			if (!memcmp(ctx->prev_drn,
					ctx->aes_ctx.output.virt_addr,
					16))
				return CTR_DRBG_GENERAL_ERROR;
			else
				memcpy(ctx->prev_drn,
					ctx->aes_ctx.output.virt_addr,
					16);
			rv = 0;
			memcpy((uint8_t *)buffer + 16*i,
				ctx->aes_ctx.output.virt_addr,
				(len_bits % 128)/8);
		} else {
			/* normal case: encrypt direct to target buffer */

			init_completion(&ctx->aes_ctx.result.completion);

			/*
			 * Note: personalize these called routines for
			 * specific testing.
			 */

			crypto_ablkcipher_clear_flags(ctx->aes_ctx.tfm, ~0);

			/* Encrypt some clear text! */

			memcpy(ctx->aes_ctx.input.virt_addr,
				ctx->seed.key_V.V,
				16);
			sg_init_one(&sg_in,
				ctx->aes_ctx.input.virt_addr,
				16);
			sg_init_one(&sg_out,
				ctx->aes_ctx.output.virt_addr,
				16);
			ablkcipher_request_set_crypt(ctx->aes_ctx.req,
						&sg_in,
						&sg_out,
						CTR_DRBG_BLOCK_LEN_BYTES,
						NULL);

			rc = crypto_ablkcipher_encrypt(ctx->aes_ctx.req);

			switch (rc) {
			case 0:
				break;
			case -EINPROGRESS:
			case -EBUSY:
				rc = wait_for_completion_interruptible(
					&ctx->aes_ctx.result.completion);
				if (!rc && !ctx->aes_ctx.result.err) {
					reinit_completion(
					&ctx->aes_ctx.result.completion);
					break;
				}
				/* fall through */
			default:
				break;
			}

			if (!memcmp(ctx->prev_drn,
				ctx->aes_ctx.output.virt_addr,
				16))
				return CTR_DRBG_GENERAL_ERROR;
			else
				memcpy(ctx->prev_drn,
					ctx->aes_ctx.output.virt_addr,
					16);

			memcpy((uint8_t *)buffer + 16*i,
				ctx->aes_ctx.output.virt_addr,
				16);
			rv = 0;
		}
	}

	update_rv = update(ctx,
			additional_input,
			(additional_input_len_bits + 7) / 8); /* round up */
	if (update_rv != CTR_DRBG_SUCCESS)
		return update_rv;

	ctx->reseed_counter += 1;

	return CTR_DRBG_SUCCESS;
}

/*
 * Generate random bits, but with no provided data. See notes on
 * ctr_drbg_generate_w_data()
 */
enum ctr_drbg_status_t
ctr_drbg_generate(struct ctr_drbg_ctx_s *ctx,
		void *buffer,
		size_t len_bits)

{
	return ctr_drbg_generate_w_data(ctx, NULL, 0, buffer, len_bits);
}

void ctr_aes_deinit(struct ctr_drbg_ctx_s *ctx)
{
	if (ctx->aes_ctx.req) {
		ablkcipher_request_free(ctx->aes_ctx.req);
		ctx->aes_ctx.req = NULL;
	}
	if (ctx->aes_ctx.tfm) {
		crypto_free_ablkcipher(ctx->aes_ctx.tfm);
		ctx->aes_ctx.tfm = NULL;
	}
	if (ctx->aes_ctx.input.virt_addr) {
		kzfree(ctx->aes_ctx.input.virt_addr);
		ctx->aes_ctx.input.virt_addr = NULL;
	}
	if (ctx->aes_ctx.output.virt_addr) {
		kzfree(ctx->aes_ctx.output.virt_addr);
		ctx->aes_ctx.output.virt_addr = NULL;
	}
	if (ctx->df_aes_ctx.req) {
		ablkcipher_request_free(ctx->df_aes_ctx.req);
		ctx->df_aes_ctx.req = NULL;
	}
	if (ctx->df_aes_ctx.tfm) {
		crypto_free_ablkcipher(ctx->df_aes_ctx.tfm);
		ctx->df_aes_ctx.tfm = NULL;
	}
	if (ctx->df_aes_ctx.input.virt_addr) {
		kzfree(ctx->df_aes_ctx.input.virt_addr);
		ctx->df_aes_ctx.input.virt_addr = NULL;
	}
	if (ctx->df_aes_ctx.output.virt_addr) {
		kzfree(ctx->df_aes_ctx.output.virt_addr);
		ctx->df_aes_ctx.output.virt_addr = NULL;
	}

}

/*
 * Zeroizes the context structure. In some future implemenation it
 * could also free resources.  So do call it.
 */
void
ctr_drbg_uninstantiate(struct ctr_drbg_ctx_s *ctx)
{
	ctr_aes_deinit(ctx);
	memset(ctx, 0, sizeof(*ctx));
}

/*
 * the derivation functions to handle biased entropy input.
 */
enum ctr_drbg_status_t df_bcc_func(struct ctr_drbg_ctx_s *ctx,
		uint8_t *key,
		uint8_t *input,
		uint32_t input_size,
		uint8_t *output)
{
	enum ctr_drbg_status_t ret_val = CTR_DRBG_SUCCESS;
	uint8_t *p;
	int rc;
	int i;
	int n;
	struct scatterlist sg_in, sg_out;

	if (0 != (input_size % CTR_DRBG_BLOCK_LEN_BYTES))
		return CTR_DRBG_INVALID_ARG;

	n = input_size / CTR_DRBG_BLOCK_LEN_BYTES;

	for (i = 0; i < CTR_DRBG_BLOCK_LEN_BYTES; i++)
		ctx->df_aes_ctx.output.virt_addr[i] = 0;

	rc = crypto_ablkcipher_setkey(ctx->df_aes_ctx.tfm,
					key,
					AES128_KEY_SIZE);
	if (rc) {
		pr_debug("crypto_ablkcipher_setkey API failed: %d\n", rc);
		return CTR_DRBG_GENERAL_ERROR;
	}

	p = input;
	while (n > 0) {
		for (i = 0; i < CTR_DRBG_BLOCK_LEN_BYTES; i++, p++)
			ctx->df_aes_ctx.input.virt_addr[i] =
				ctx->df_aes_ctx.output.virt_addr[i] ^ (*p);

		init_completion(&ctx->df_aes_ctx.result.completion);

		/*
		 * Note: personalize these called routines for
		 * specific testing.
		 */

		crypto_ablkcipher_clear_flags(ctx->df_aes_ctx.tfm, ~0);

		/* Encrypt some clear text! */

		sg_init_one(&sg_in, ctx->df_aes_ctx.input.virt_addr, 16);
		sg_init_one(&sg_out, ctx->df_aes_ctx.output.virt_addr, 16);

		ablkcipher_request_set_crypt(ctx->df_aes_ctx.req,
					&sg_in,
					&sg_out,
					CTR_DRBG_BLOCK_LEN_BYTES,
					NULL);

		rc = crypto_ablkcipher_encrypt(ctx->df_aes_ctx.req);

		switch (rc) {
		case 0:
			break;
		case -EINPROGRESS:
		case -EBUSY:
			rc = wait_for_completion_interruptible(
				&ctx->df_aes_ctx.result.completion);
			if (!rc && !ctx->df_aes_ctx.result.err) {
				reinit_completion(
				&ctx->df_aes_ctx.result.completion);
				break;
			}
			/* fall through */
		default:
			break;
		}

		init_completion(&ctx->df_aes_ctx.result.completion);
		n--;
	}

	for (i = 0; i < CTR_DRBG_BLOCK_LEN_BYTES; i++)
		output[i] = ctx->df_aes_ctx.output.virt_addr[i];

	return ret_val;
}

/* output_size must <= 512 bits (<= 64) */
enum ctr_drbg_status_t
block_cipher_df(struct ctr_drbg_ctx_s *ctx,
		const uint8_t *input,
		uint32_t input_size,
		uint8_t *output,
		uint32_t output_size)
{
	enum ctr_drbg_status_t ret_val = CTR_DRBG_SUCCESS;
	uint32_t          s_len = 0;
	uint32_t          s_pad_len = 0;
	uint8_t           temp[32];
	uint32_t          out_len = 0;
	uint8_t           siv_string[64];
	uint8_t          *p_s_string = NULL;
	int               rc;
	struct scatterlist sg_in, sg_out;

	if (output_size > 64)
		return CTR_DRBG_INVALID_ARG;

	s_len = input_size + 9;

	s_pad_len = s_len % 16;

	if (0 != s_pad_len)
		s_len += (16 - s_pad_len);

	/* add the length of IV */
	s_len += 16;

	if (s_len > 64)
		pr_debug("error! s_len is too big!!!!!!!!!!!!\n");

	memset(siv_string, 0, 64);

	p_s_string = siv_string + 16;

	p_s_string[3] = input_size;
	p_s_string[7] = output_size;
	memcpy(p_s_string + 8, input, input_size);
	p_s_string[8 + input_size] = 0x80;
	if (0 < s_pad_len)
		memset(p_s_string + 9 + input_size, '\0', s_pad_len);

	ret_val = df_bcc_func(ctx, df_initial_k, siv_string, s_len, temp);

	if (CTR_DRBG_SUCCESS != ret_val) {
		pr_debug("df_bcc_func failed, returned %d", ret_val);
		goto out;
	}

	siv_string[3] = 0x1;
	ret_val = df_bcc_func(ctx, df_initial_k, siv_string, s_len, temp + 16);

	if (CTR_DRBG_SUCCESS != ret_val)
		goto out;

	out_len = 0;
	rc = crypto_ablkcipher_setkey(ctx->df_aes_ctx.tfm,
				temp,
				AES128_KEY_SIZE);
	if (rc) {
		pr_debug("crypto_ablkcipher_setkey API failed: %d", rc);
		goto out;
	}
	memcpy(ctx->df_aes_ctx.input.virt_addr, temp + 16, 16);

	while (out_len < output_size) {

		init_completion(&ctx->df_aes_ctx.result.completion);

		/*
		 * Note: personalize these called routines for
		 * specific testing.
		 */

		crypto_ablkcipher_clear_flags(ctx->df_aes_ctx.tfm, ~0);

		/* Encrypt some clear text! */

		sg_init_one(&sg_in, ctx->df_aes_ctx.input.virt_addr, 16);
		sg_init_one(&sg_out, ctx->df_aes_ctx.output.virt_addr, 16);
		ablkcipher_request_set_crypt(ctx->df_aes_ctx.req,
					&sg_in,
					&sg_out,
					CTR_DRBG_BLOCK_LEN_BYTES,
					NULL);

		rc = crypto_ablkcipher_encrypt(ctx->df_aes_ctx.req);

		switch (rc) {
		case 0:
			break;
		case -EINPROGRESS:
		case -EBUSY:
			rc = wait_for_completion_interruptible(
				&ctx->df_aes_ctx.result.completion);
			if (!rc && !ctx->df_aes_ctx.result.err) {
				reinit_completion(
					&ctx->df_aes_ctx.result.completion);
				break;
			}
			/* fall through */
		default:
			break;
		}


		init_completion(&ctx->df_aes_ctx.result.completion);

		memcpy(output + out_len, ctx->df_aes_ctx.output.virt_addr, 16);
		memcpy(ctx->df_aes_ctx.input.virt_addr, output + out_len, 16);
		out_len += 16;
	}

out:
	memset(siv_string, 0, 64);
	memset(temp, 0, 32);
	return ret_val;
}
Loading