diff --git a/crypto/digest.c b/crypto/digest.c
index 0df7f392a56a8ee6274df177d2c1c277650cf0a8..19e75563776bbe7309801fe574a10bbb984bce0d 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -66,14 +66,18 @@ static void update(struct crypto_tfm *tfm,
 static void final(struct crypto_tfm *tfm, u8 *out)
 {
 	unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+	struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
+
 	if (unlikely((unsigned long)out & alignmask)) {
-		unsigned int size = crypto_tfm_alg_digestsize(tfm);
-		u8 buffer[size + alignmask];
-		u8 *dst = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
-		tfm->__crt_alg->cra_digest.dia_final(tfm, dst);
-		memcpy(out, dst, size);
+		unsigned long align = alignmask + 1;
+		unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
+		u8 *dst = (u8 *)ALIGN(addr, align) +
+			  ALIGN(tfm->__crt_alg->cra_ctxsize, align);
+
+		digest->dia_final(tfm, dst);
+		memcpy(out, dst, digest->dia_digestsize);
 	} else
-		tfm->__crt_alg->cra_digest.dia_final(tfm, out);
+		digest->dia_final(tfm, out);
 }
 
 static int nosetkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
diff --git a/crypto/internal.h b/crypto/internal.h
index 03c00b0e6b60c19d4d453cf32cf0ef9a60e3f275..b110b979b9888b38a00e7c2e3a53744fbe1a3458 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -99,7 +99,14 @@ static inline void crypto_exit_proc(void)
 static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
 						 int flags)
 {
-	return alg->cra_ctxsize;
+	unsigned int len = alg->cra_ctxsize;
+
+	if (alg->cra_alignmask) {
+		len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
+		len += alg->cra_digest.dia_digestsize;
+	}
+
+	return len;
 }
 
 static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg,