diff options
Diffstat (limited to 'drivers/crypto/qce/sha.c')
| -rw-r--r-- | drivers/crypto/qce/sha.c | 143 | 
1 files changed, 54 insertions, 89 deletions
| diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c index 61c418c12345..8e6fcf2c21cc 100644 --- a/drivers/crypto/qce/sha.c +++ b/drivers/crypto/qce/sha.c @@ -12,9 +12,15 @@  #include "core.h"  #include "sha.h" -/* crypto hw padding constant for first operation */ -#define SHA_PADDING		64 -#define SHA_PADDING_MASK	(SHA_PADDING - 1) +struct qce_sha_saved_state { +	u8 pending_buf[QCE_SHA_MAX_BLOCKSIZE]; +	u8 partial_digest[QCE_SHA_MAX_DIGESTSIZE]; +	__be32 byte_count[2]; +	unsigned int pending_buflen; +	unsigned int flags; +	u64 count; +	bool first_blk; +};  static LIST_HEAD(ahash_algs); @@ -107,7 +113,7 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)  	qce_dma_issue_pending(&qce->dma); -	ret = qce_start(async_req, tmpl->crypto_alg_type, 0, 0); +	ret = qce_start(async_req, tmpl->crypto_alg_type);  	if (ret)  		goto error_terminate; @@ -139,97 +145,37 @@ static int qce_ahash_init(struct ahash_request *req)  static int qce_ahash_export(struct ahash_request *req, void *out)  { -	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);  	struct qce_sha_reqctx *rctx = ahash_request_ctx(req); -	unsigned long flags = rctx->flags; -	unsigned int digestsize = crypto_ahash_digestsize(ahash); -	unsigned int blocksize = -			crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash)); - -	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) { -		struct sha1_state *out_state = out; - -		out_state->count = rctx->count; -		qce_cpu_to_be32p_array((__be32 *)out_state->state, -				       rctx->digest, digestsize); -		memcpy(out_state->buffer, rctx->buf, blocksize); -	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) { -		struct sha256_state *out_state = out; - -		out_state->count = rctx->count; -		qce_cpu_to_be32p_array((__be32 *)out_state->state, -				       rctx->digest, digestsize); -		memcpy(out_state->buf, rctx->buf, blocksize); -	} else { -		return -EINVAL; -	} +	struct qce_sha_saved_state *export_state = out; -	return 0; -} - -static int qce_import_common(struct ahash_request *req, u64 in_count, -			     const u32 *state, const u8 *buffer, bool hmac) -{ -	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); -	struct qce_sha_reqctx *rctx = ahash_request_ctx(req); -	unsigned int digestsize = crypto_ahash_digestsize(ahash); -	unsigned int blocksize; -	u64 count = in_count; - -	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(ahash)); -	rctx->count = in_count; -	memcpy(rctx->buf, buffer, blocksize); - -	if (in_count <= blocksize) { -		rctx->first_blk = 1; -	} else { -		rctx->first_blk = 0; -		/* -		 * For HMAC, there is a hardware padding done when first block -		 * is set. Therefore the byte_count must be incremened by 64 -		 * after the first block operation. -		 */ -		if (hmac) -			count += SHA_PADDING; -	} - -	rctx->byte_count[0] = (__force __be32)(count & ~SHA_PADDING_MASK); -	rctx->byte_count[1] = (__force __be32)(count >> 32); -	qce_cpu_to_be32p_array((__be32 *)rctx->digest, (const u8 *)state, -			       digestsize); -	rctx->buflen = (unsigned int)(in_count & (blocksize - 1)); +	memcpy(export_state->pending_buf, rctx->buf, rctx->buflen); +	memcpy(export_state->partial_digest, rctx->digest, sizeof(rctx->digest)); +	export_state->byte_count[0] = rctx->byte_count[0]; +	export_state->byte_count[1] = rctx->byte_count[1]; +	export_state->pending_buflen = rctx->buflen; +	export_state->count = rctx->count; +	export_state->first_blk = rctx->first_blk; +	export_state->flags = rctx->flags;  	return 0;  }  static int qce_ahash_import(struct ahash_request *req, const void *in)  { -	struct qce_sha_reqctx *rctx; -	unsigned long flags; -	bool hmac; -	int ret; - -	ret = qce_ahash_init(req); -	if (ret) -		return ret; - -	rctx = ahash_request_ctx(req); -	flags = rctx->flags; -	hmac = IS_SHA_HMAC(flags); - -	if (IS_SHA1(flags) || IS_SHA1_HMAC(flags)) { -		const struct sha1_state *state = in; - -		ret = qce_import_common(req, state->count, state->state, -					state->buffer, hmac); -	} else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags)) { -		const struct sha256_state *state = in; +	struct qce_sha_reqctx *rctx = ahash_request_ctx(req); +	const struct qce_sha_saved_state *import_state = in; -		ret = qce_import_common(req, state->count, state->state, -					state->buf, hmac); -	} +	memset(rctx, 0, sizeof(*rctx)); +	rctx->count = import_state->count; +	rctx->buflen = import_state->pending_buflen; +	rctx->first_blk = import_state->first_blk; +	rctx->flags = import_state->flags; +	rctx->byte_count[0] = import_state->byte_count[0]; +	rctx->byte_count[1] = import_state->byte_count[1]; +	memcpy(rctx->buf, import_state->pending_buf, rctx->buflen); +	memcpy(rctx->digest, import_state->partial_digest, sizeof(rctx->digest)); -	return ret; +	return 0;  }  static int qce_ahash_update(struct ahash_request *req) @@ -270,6 +216,25 @@ static int qce_ahash_update(struct ahash_request *req)  	/* calculate how many bytes will be hashed later */  	hash_later = total % blocksize; + +	/* +	 * At this point, there is more than one block size of data.  If +	 * the available data to transfer is exactly a multiple of block +	 * size, save the last block to be transferred in qce_ahash_final +	 * (with the last block bit set) if this is indeed the end of data +	 * stream. If not this saved block will be transferred as part of +	 * next update. If this block is not held back and if this is +	 * indeed the end of data stream, the digest obtained will be wrong +	 * since qce_ahash_final will see that rctx->buflen is 0 and return +	 * doing nothing which in turn means that a digest will not be +	 * copied to the destination result buffer.  qce_ahash_final cannot +	 * be made to alter this behavior and allowed to proceed if +	 * rctx->buflen is 0 because the crypto engine BAM does not allow +	 * for zero length transfers. +	 */ +	if (!hash_later) +		hash_later = blocksize; +  	if (hash_later) {  		unsigned int src_offset = req->nbytes - hash_later;  		scatterwalk_map_and_copy(rctx->buf, req->src, src_offset, @@ -450,7 +415,7 @@ static const struct qce_ahash_def ahash_def[] = {  		.drv_name	= "sha1-qce",  		.digestsize	= SHA1_DIGEST_SIZE,  		.blocksize	= SHA1_BLOCK_SIZE, -		.statesize	= sizeof(struct sha1_state), +		.statesize	= sizeof(struct qce_sha_saved_state),  		.std_iv		= std_iv_sha1,  	},  	{ @@ -459,7 +424,7 @@ static const struct qce_ahash_def ahash_def[] = {  		.drv_name	= "sha256-qce",  		.digestsize	= SHA256_DIGEST_SIZE,  		.blocksize	= SHA256_BLOCK_SIZE, -		.statesize	= sizeof(struct sha256_state), +		.statesize	= sizeof(struct qce_sha_saved_state),  		.std_iv		= std_iv_sha256,  	},  	{ @@ -468,7 +433,7 @@ static const struct qce_ahash_def ahash_def[] = {  		.drv_name	= "hmac-sha1-qce",  		.digestsize	= SHA1_DIGEST_SIZE,  		.blocksize	= SHA1_BLOCK_SIZE, -		.statesize	= sizeof(struct sha1_state), +		.statesize	= sizeof(struct qce_sha_saved_state),  		.std_iv		= std_iv_sha1,  	},  	{ @@ -477,7 +442,7 @@ static const struct qce_ahash_def ahash_def[] = {  		.drv_name	= "hmac-sha256-qce",  		.digestsize	= SHA256_DIGEST_SIZE,  		.blocksize	= SHA256_BLOCK_SIZE, -		.statesize	= sizeof(struct sha256_state), +		.statesize	= sizeof(struct qce_sha_saved_state),  		.std_iv		= std_iv_sha256,  	},  }; | 
