struct crypto_sync_skcipher *initiator_enc;
        struct crypto_sync_skcipher *acceptor_enc_aux;
        struct crypto_sync_skcipher *initiator_enc_aux;
+       struct crypto_ahash     *acceptor_sign;
+       struct crypto_ahash     *initiator_sign;
        u8                      Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */
        u8                      cksum[GSS_KRB5_MAX_KEYLEN];
        atomic_t                seq_send;
        atomic64_t              seq_send64;
        time64_t                endtime;
        struct xdr_netobj       mech_used;
-       u8                      initiator_sign[GSS_KRB5_MAX_KEYLEN];
-       u8                      acceptor_sign[GSS_KRB5_MAX_KEYLEN];
        u8                      initiator_integ[GSS_KRB5_MAX_KEYLEN];
        u8                      acceptor_integ[GSS_KRB5_MAX_KEYLEN];
 };
 gss_unwrap_kerberos(struct gss_ctx *ctx_id, int offset, int len,
                struct xdr_buf *buf);
 
-
 u32
 krb5_encrypt(struct crypto_sync_skcipher *key,
             void *iv, void *in, void *out, int length);
 
        return err ? GSS_S_FAILURE : 0;
 }
 
+/**
+ * gss_krb5_checksum - Compute the MAC for a GSS Wrap or MIC token
+ * @tfm: an initialized hash transform
+ * @header: pointer to a buffer containing the token header, or NULL
+ * @hdrlen: number of octets in @header
+ * @body: xdr_buf containing an RPC message (body.len is the message length)
+ * @body_offset: byte offset into @body to start checksumming
+ * @cksumout: OUT: a buffer to be filled in with the computed HMAC
+ *
+ * Usually expressed as H = HMAC(K, message)[1..h] .
+ *
+ * Caller provides the truncation length of the output token (h) in
+ * cksumout.len.
+ *
+ * Return values:
+ *   %GSS_S_COMPLETE: Digest computed, @cksumout filled in
+ *   %GSS_S_FAILURE: Call failed
+ */
+u32
+gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
+                 const struct xdr_buf *body, int body_offset,
+                 struct xdr_netobj *cksumout)
+{
+       struct ahash_request *req;
+       int err = -ENOMEM;
+       u8 *checksumdata;
+
+       checksumdata = kmalloc(crypto_ahash_digestsize(tfm), GFP_KERNEL);
+       if (!checksumdata)
+               return GSS_S_FAILURE;
+
+       req = ahash_request_alloc(tfm, GFP_KERNEL);
+       if (!req)
+               goto out_free_cksum;
+       ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
+       err = crypto_ahash_init(req);
+       if (err)
+               goto out_free_ahash;
+
+       /*
+        * Per RFC 4121 Section 4.2.4, the checksum is performed over the
+        * data body first, then over the octets in "header".
+        */
+       err = xdr_process_buf(body, body_offset, body->len - body_offset,
+                             checksummer, req);
+       if (err)
+               goto out_free_ahash;
+       if (header) {
+               struct scatterlist sg[1];
+
+               sg_init_one(sg, header, hdrlen);
+               ahash_request_set_crypt(req, sg, NULL, hdrlen);
+               err = crypto_ahash_update(req);
+               if (err)
+                       goto out_free_ahash;
+       }
+
+       ahash_request_set_crypt(req, NULL, checksumdata, 0);
+       err = crypto_ahash_final(req);
+       if (err)
+               goto out_free_ahash;
+       memcpy(cksumout->data, checksumdata, cksumout->len);
+
+out_free_ahash:
+       ahash_request_free(req);
+out_free_cksum:
+       kfree_sensitive(checksumdata);
+       return err ? GSS_S_FAILURE : GSS_S_COMPLETE;
+}
+
 struct encryptor_desc {
        u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
        struct skcipher_request *req;
 
 
 void krb5_make_confounder(u8 *p, int conflen);
 
+u32 gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
+                     const struct xdr_buf *body, int body_offset,
+                     struct xdr_netobj *cksumout);
+
 #endif /* _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H */
 
        return -EINVAL;
 }
 
+static struct crypto_ahash *
+gss_krb5_alloc_hash_v2(struct krb5_ctx *kctx, const struct xdr_netobj *key)
+{
+       struct crypto_ahash *tfm;
+
+       tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm))
+               return NULL;
+       if (crypto_ahash_setkey(tfm, key->data, key->len)) {
+               crypto_free_ahash(tfm);
+               return NULL;
+       }
+       return tfm;
+}
+
 static int
 context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask)
 {
 
        /* initiator sign checksum */
        set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
-       keyout.data = ctx->initiator_sign;
        err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask);
-       if (err) {
-               dprintk("%s: Error %d deriving initiator_sign key\n",
-                       __func__, err);
+       if (err)
+               goto out_free;
+       ctx->initiator_sign = gss_krb5_alloc_hash_v2(ctx, &keyout);
+       if (ctx->initiator_sign == NULL)
                goto out_free;
-       }
 
        /* acceptor sign checksum */
        set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
-       keyout.data = ctx->acceptor_sign;
        err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask);
-       if (err) {
-               dprintk("%s: Error %d deriving acceptor_sign key\n",
-                       __func__, err);
+       if (err)
+               goto out_free;
+       ctx->acceptor_sign = gss_krb5_alloc_hash_v2(ctx, &keyout);
+       if (ctx->acceptor_sign == NULL)
                goto out_free;
-       }
 
        /* initiator seal integrity */
        set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
        return ret;
 
 out_free:
+       crypto_free_ahash(ctx->acceptor_sign);
+       crypto_free_ahash(ctx->initiator_sign);
        crypto_free_sync_skcipher(ctx->acceptor_enc_aux);
        crypto_free_sync_skcipher(ctx->acceptor_enc);
        crypto_free_sync_skcipher(ctx->initiator_enc_aux);
        crypto_free_sync_skcipher(kctx->initiator_enc);
        crypto_free_sync_skcipher(kctx->acceptor_enc_aux);
        crypto_free_sync_skcipher(kctx->initiator_enc_aux);
+       crypto_free_ahash(kctx->acceptor_sign);
+       crypto_free_ahash(kctx->initiator_sign);
        kfree(kctx->mech_used.data);
        kfree(kctx);
 }
 
 #include <linux/crypto.h>
 #include <linux/atomic.h>
 
+#include "gss_krb5_internal.h"
+
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 # define RPCDBG_FACILITY        RPCDBG_AUTH
 #endif
 gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
                struct xdr_netobj *token)
 {
-       char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
-       struct xdr_netobj cksumobj = { .len = sizeof(cksumdata),
-                                      .data = cksumdata};
+       struct crypto_ahash *tfm = ctx->initiate ?
+                                  ctx->initiator_sign : ctx->acceptor_sign;
+       struct xdr_netobj cksumobj = {
+               .len =  ctx->gk5e->cksumlength,
+       };
+       __be64 seq_send_be64;
        void *krb5_hdr;
        time64_t now;
-       u8 *cksumkey;
-       unsigned int cksum_usage;
-       __be64 seq_send_be64;
 
        dprintk("RPC:       %s\n", __func__);
 
        seq_send_be64 = cpu_to_be64(atomic64_fetch_inc(&ctx->seq_send64));
        memcpy(krb5_hdr + 8, (char *) &seq_send_be64, 8);
 
-       if (ctx->initiate) {
-               cksumkey = ctx->initiator_sign;
-               cksum_usage = KG_USAGE_INITIATOR_SIGN;
-       } else {
-               cksumkey = ctx->acceptor_sign;
-               cksum_usage = KG_USAGE_ACCEPTOR_SIGN;
-       }
-
-       if (make_checksum_v2(ctx, krb5_hdr, GSS_KRB5_TOK_HDR_LEN,
-                            text, 0, cksumkey, cksum_usage, &cksumobj))
+       cksumobj.data = krb5_hdr + GSS_KRB5_TOK_HDR_LEN;
+       if (gss_krb5_checksum(tfm, krb5_hdr, GSS_KRB5_TOK_HDR_LEN,
+                             text, 0, &cksumobj))
                return GSS_S_FAILURE;
 
-       memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, cksumobj.data, cksumobj.len);
-
        now = ktime_get_real_seconds();
-
        return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
 }
 
 
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
+#include <crypto/algapi.h>
 #include <linux/types.h>
 #include <linux/jiffies.h>
 #include <linux/sunrpc/gss_krb5.h>
 #include <linux/crypto.h>
 
+#include "gss_krb5_internal.h"
+
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 # define RPCDBG_FACILITY        RPCDBG_AUTH
 #endif
 gss_verify_mic_v2(struct krb5_ctx *ctx,
                struct xdr_buf *message_buffer, struct xdr_netobj *read_token)
 {
+       struct crypto_ahash *tfm = ctx->initiate ?
+                                  ctx->acceptor_sign : ctx->initiator_sign;
        char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
-       struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
-                                     .data = cksumdata};
-       time64_t now;
+       struct xdr_netobj cksumobj = {
+               .len    = ctx->gk5e->cksumlength,
+               .data   = cksumdata,
+       };
        u8 *ptr = read_token->data;
-       u8 *cksumkey;
+       __be16 be16_ptr;
+       time64_t now;
        u8 flags;
        int i;
-       unsigned int cksum_usage;
-       __be16 be16_ptr;
 
        dprintk("RPC:       %s\n", __func__);
 
                if (ptr[i] != 0xff)
                        return GSS_S_DEFECTIVE_TOKEN;
 
-       if (ctx->initiate) {
-               cksumkey = ctx->acceptor_sign;
-               cksum_usage = KG_USAGE_ACCEPTOR_SIGN;
-       } else {
-               cksumkey = ctx->initiator_sign;
-               cksum_usage = KG_USAGE_INITIATOR_SIGN;
-       }
-
-       if (make_checksum_v2(ctx, ptr, GSS_KRB5_TOK_HDR_LEN, message_buffer, 0,
-                            cksumkey, cksum_usage, &cksumobj))
+       if (gss_krb5_checksum(tfm, ptr, GSS_KRB5_TOK_HDR_LEN,
+                             message_buffer, 0, &cksumobj))
                return GSS_S_FAILURE;
 
        if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN,