diff options
Diffstat (limited to 'arch/s390/crypto/sha_common.c')
-rw-r--r-- | arch/s390/crypto/sha_common.c | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/arch/s390/crypto/sha_common.c b/arch/s390/crypto/sha_common.c index cf0718d121bc..d39e0f079217 100644 --- a/arch/s390/crypto/sha_common.c +++ b/arch/s390/crypto/sha_common.c @@ -20,7 +20,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) unsigned int index, n; /* how much is already in the buffer? */ - index = ctx->count & (bsize - 1); + index = ctx->count % bsize; ctx->count += len; if ((index + len) < bsize) @@ -37,7 +37,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) /* process as many blocks as possible */ if (len >= bsize) { - n = len & ~(bsize - 1); + n = (len / bsize) * bsize; cpacf_kimd(ctx->func, ctx->state, data, n); data += n; len -= n; @@ -50,34 +50,63 @@ store: } EXPORT_SYMBOL_GPL(s390_sha_update); +static int s390_crypto_shash_parmsize(int func) +{ + switch (func) { + case CPACF_KLMD_SHA_1: + return 20; + case CPACF_KLMD_SHA_256: + return 32; + case CPACF_KLMD_SHA_512: + return 64; + case CPACF_KLMD_SHA3_224: + case CPACF_KLMD_SHA3_256: + case CPACF_KLMD_SHA3_384: + case CPACF_KLMD_SHA3_512: + return 200; + default: + return -EINVAL; + } +} + int s390_sha_final(struct shash_desc *desc, u8 *out) { struct s390_sha_ctx *ctx = shash_desc_ctx(desc); unsigned int bsize = crypto_shash_blocksize(desc->tfm); u64 bits; - unsigned int index, end, plen; - - /* SHA-512 uses 128 bit padding length */ - plen = (bsize > SHA256_BLOCK_SIZE) ? 16 : 8; + unsigned int n, mbl_offset; - /* must perform manual padding */ - index = ctx->count & (bsize - 1); - end = (index < bsize - plen) ? bsize : (2 * bsize); - - /* start pad with 1 */ - ctx->buf[index] = 0x80; - index++; - - /* pad with zeros */ - memset(ctx->buf + index, 0x00, end - index - 8); - - /* - * Append message length. Well, SHA-512 wants a 128 bit length value, - * nevertheless we use u64, should be enough for now... - */ + n = ctx->count % bsize; bits = ctx->count * 8; - memcpy(ctx->buf + end - 8, &bits, sizeof(bits)); - cpacf_kimd(ctx->func, ctx->state, ctx->buf, end); + mbl_offset = s390_crypto_shash_parmsize(ctx->func) / sizeof(u32); + if (mbl_offset < 0) + return -EINVAL; + + /* set total msg bit length (mbl) in CPACF parmblock */ + switch (ctx->func) { + case CPACF_KLMD_SHA_1: + case CPACF_KLMD_SHA_256: + memcpy(ctx->state + mbl_offset, &bits, sizeof(bits)); + break; + case CPACF_KLMD_SHA_512: + /* + * the SHA512 parmblock has a 128-bit mbl field, clear + * high-order u64 field, copy bits to low-order u64 field + */ + memset(ctx->state + mbl_offset, 0x00, sizeof(bits)); + mbl_offset += sizeof(u64) / sizeof(u32); + memcpy(ctx->state + mbl_offset, &bits, sizeof(bits)); + break; + case CPACF_KLMD_SHA3_224: + case CPACF_KLMD_SHA3_256: + case CPACF_KLMD_SHA3_384: + case CPACF_KLMD_SHA3_512: + break; + default: + return -EINVAL; + } + + cpacf_klmd(ctx->func, ctx->state, ctx->buf, n); /* copy digest to out */ memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm)); |