summaryrefslogtreecommitdiff
path: root/arch/s390/crypto/sha_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/crypto/sha_common.c')
-rw-r--r--arch/s390/crypto/sha_common.c75
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));