Skip to content

Commit

Permalink
crypto: qce - Restore/save ahash state with custom struct in export/i…
Browse files Browse the repository at this point in the history
…mport

Export and import interfaces save and restore partial transformation
states. The partial states were being stored and restored in struct
sha1_state for sha1/hmac(sha1) transformations and sha256_state for
sha256/hmac(sha256) transformations.This led to a bunch of corner cases
where improper state was being stored and restored. A few of the corner
cases that turned up during testing are:

- wrong byte_count restored if export/import is called twice without h/w
transaction in between
- wrong buflen restored back if the pending buffer
length is exactly the block size.
- wrong state restored if buffer length is 0.

To fix these issues, save and restore the partial transformation state
using the newly introduced qce_sha_saved_state struct. This ensures that
all the pieces required to properly restart the transformation is captured
and restored back

Signed-off-by: Thara Gopinath <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
tharagopinath authored and herbertx committed Mar 7, 2021
1 parent 2eee428 commit a01dc5c
Showing 1 changed file with 34 additions and 88 deletions.
122 changes: 34 additions & 88 deletions drivers/crypto/qce/sha.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}

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;
}
struct qce_sha_saved_state *export_state = out;

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)
Expand Down Expand Up @@ -450,7 +396,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,
},
{
Expand All @@ -459,7 +405,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,
},
{
Expand All @@ -468,7 +414,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,
},
{
Expand All @@ -477,7 +423,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,
},
};
Expand Down

0 comments on commit a01dc5c

Please sign in to comment.