]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net/rxrpc: Use local FCrypt-PCBC implementation
authorEric Biggers <ebiggers@kernel.org>
Fri, 22 May 2026 05:07:33 +0000 (00:07 -0500)
committerJakub Kicinski <kuba@kernel.org>
Wed, 10 Jun 2026 00:03:03 +0000 (17:03 -0700)
Use the local implementation of FCrypt-PCBC instead of the crypto API
one.  This will allow the crypto API one to be removed.  It also
simplifies the code quite a bit.

The local FCrypt-PCBC implementation is also significantly faster than
the crypto API one, since the crypto API one had a lot of overhead.  For
example, benchmarking on an x86_64 CPU, I see that FCrypt-PCBC
decryption throughput improved from 83 MB/s to 157 MB/s.

(Meanwhile, AES-256-GCM decryption is 8064 MB/s on the same CPU.
Clearly, anyone looking for good performance, or anything that is
actually secure for that matter, needs to look elsewhere anyway.)

Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Tested-by: Marc Dionne <marc.dionne@auristor.com>
Link: https://patch.msgid.link/20260522050740.84561-3-ebiggers@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/rxrpc/Kconfig
net/rxrpc/ar-internal.h
net/rxrpc/rxkad.c

index e2bb795cdf0cc8ec5af49e14a364414a5ae4d38e..de19c67dc9652130f11a63bbb95c91044b9d55b3 100644 (file)
@@ -60,7 +60,6 @@ config RXKAD
        select CRYPTO_MANAGER
        select CRYPTO_SKCIPHER
        select CRYPTO_PCBC
-       select CRYPTO_FCRYPT
        help
          Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC
          through the use of the key retention service.
index 30aaf69b4c7cb350f6eb04c80f50b20a4f9b8ff2..29d32aa4ecc7794f4b956c7cbcb825ddc77b3888 100644 (file)
@@ -577,7 +577,7 @@ struct rxrpc_connection {
        const struct rxrpc_security *security;  /* applied security module */
        union {
                struct {
-                       struct crypto_sync_skcipher *cipher;    /* encryption handle */
+                       struct fcrypt_key *cipher; /* encryption key */
                        struct rxrpc_crypt csum_iv;     /* packet checksum base */
                        u32     nonce;          /* response re-use preventer */
                } rxkad;
index 6fbd883401acdfa7e8fd0a50799b4b5a90d572fc..d8bc5ecbfc3d05f39fca448f10738409be2f3878 100644 (file)
@@ -8,6 +8,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <crypto/skcipher.h>
+#include <linux/fips.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/skbuff.h>
@@ -30,6 +31,8 @@
 #define SNAME_SZ                       40      /* size of service name */
 #define RXKAD_ALIGN                    8
 
+static const u8 zero_iv[FCRYPT_BSIZE];
+
 struct rxkad_level1_hdr {
        __be32  data_size;      /* true data size (excluding padding) */
 };
@@ -39,17 +42,8 @@ struct rxkad_level2_hdr {
        __be32  checksum;       /* decrypted data checksum */
 };
 
-static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
-                                      struct crypto_sync_skcipher *ci);
-
-/*
- * this holds a pinned cipher so that keventd doesn't get called by the cipher
- * alloc routine, but since we have it to hand, we use it to decrypt RESPONSE
- * packets
- */
-static struct crypto_sync_skcipher *rxkad_ci;
-static struct skcipher_request *rxkad_ci_req;
-static DEFINE_MUTEX(rxkad_ci_mutex);
+static void rxkad_prime_packet_security(struct rxrpc_connection *conn,
+                                       const struct fcrypt_key *cipher);
 
 /*
  * Parse the information from a server key
@@ -100,23 +94,19 @@ static void rxkad_destroy_server_key(struct key *key)
 static int rxkad_init_connection_security(struct rxrpc_connection *conn,
                                          struct rxrpc_key_token *token)
 {
-       struct crypto_sync_skcipher *ci;
+       struct fcrypt_key *ci;
        int ret;
 
        _enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
 
        conn->security_ix = token->security_index;
 
-       ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
-       if (IS_ERR(ci)) {
-               _debug("no cipher");
-               ret = PTR_ERR(ci);
+       ci = kmalloc_obj(*ci);
+       if (!ci) {
+               ret = -ENOMEM;
                goto error;
        }
-
-       if (crypto_sync_skcipher_setkey(ci, token->kad->session_key,
-                                  sizeof(token->kad->session_key)) < 0)
-               BUG();
+       fcrypt_preparekey(ci, token->kad->session_key);
 
        switch (conn->security_level) {
        case RXRPC_SECURITY_PLAIN:
@@ -125,18 +115,16 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn,
                break;
        default:
                ret = -EKEYREJECTED;
-               goto error;
+               goto error_ci;
        }
 
-       ret = rxkad_prime_packet_security(conn, ci);
-       if (ret < 0)
-               goto error_ci;
+       rxkad_prime_packet_security(conn, ci);
 
        conn->rxkad.cipher = ci;
        return 0;
 
 error_ci:
-       crypto_free_sync_skcipher(ci);
+       kfree_sensitive(ci);
 error:
        _leave(" = %d", ret);
        return ret;
@@ -188,62 +176,28 @@ static struct rxrpc_txbuf *rxkad_alloc_txbuf(struct rxrpc_call *call, size_t rem
  * prime the encryption state with the invariant parts of a connection's
  * description
  */
-static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
-                                      struct crypto_sync_skcipher *ci)
+static void rxkad_prime_packet_security(struct rxrpc_connection *conn,
+                                       const struct fcrypt_key *cipher)
 {
-       struct skcipher_request *req;
        struct rxrpc_key_token *token;
-       struct scatterlist sg;
-       struct rxrpc_crypt iv;
-       __be32 *tmpbuf;
-       size_t tmpsize = 4 * sizeof(__be32);
-       int ret;
+       __be32 tmpbuf[4];
 
        _enter("");
 
        if (!conn->key)
-               return 0;
-
-       tmpbuf = kmalloc(tmpsize, GFP_KERNEL);
-       if (!tmpbuf)
-               return -ENOMEM;
-
-       req = skcipher_request_alloc(&ci->base, GFP_NOFS);
-       if (!req) {
-               kfree(tmpbuf);
-               return -ENOMEM;
-       }
-
+               return;
        token = conn->key->payload.data[0];
-       memcpy(&iv, token->kad->session_key, sizeof(iv));
 
        tmpbuf[0] = htonl(conn->proto.epoch);
        tmpbuf[1] = htonl(conn->proto.cid);
        tmpbuf[2] = 0;
        tmpbuf[3] = htonl(conn->security_ix);
 
-       sg_init_one(&sg, tmpbuf, tmpsize);
-       skcipher_request_set_sync_tfm(req, ci);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
-       ret = crypto_skcipher_encrypt(req);
-       skcipher_request_free(req);
-
-       memcpy(&conn->rxkad.csum_iv, tmpbuf + 2, sizeof(conn->rxkad.csum_iv));
-       kfree(tmpbuf);
-       _leave(" = %d", ret);
-       return ret;
-}
-
-/*
- * Allocate and prepare the crypto request on a call.  For any particular call,
- * this is called serially for the packets, so no lock should be necessary.
- */
-static struct skcipher_request *rxkad_get_call_crypto(struct rxrpc_call *call)
-{
-       struct crypto_skcipher *tfm = &call->conn->rxkad.cipher->base;
-
-       return skcipher_request_alloc(tfm, GFP_NOFS);
+       static_assert(sizeof(tmpbuf) % FCRYPT_BSIZE == 0);
+       fcrypt_pcbc_encrypt(cipher, /* iv= */ token->kad->session_key, tmpbuf,
+                           tmpbuf, sizeof(tmpbuf) / FCRYPT_BSIZE);
+       memcpy(&conn->rxkad.csum_iv, &tmpbuf[2], sizeof(conn->rxkad.csum_iv));
+       _leave("");
 }
 
 /*
@@ -256,16 +210,12 @@ static void rxkad_free_call_crypto(struct rxrpc_call *call)
 /*
  * partially encrypt a packet (level 1 security)
  */
-static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
-                                   struct rxrpc_txbuf *txb,
-                                   struct skcipher_request *req)
+static void rxkad_secure_packet_auth(const struct rxrpc_call *call,
+                                    struct rxrpc_txbuf *txb)
 {
        struct rxkad_level1_hdr *hdr = txb->data;
-       struct rxrpc_crypt iv;
-       struct scatterlist sg;
        size_t pad;
        u16 check;
-       int ret;
 
        _enter("");
 
@@ -282,33 +232,20 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
        }
 
        /* start the encryption afresh */
-       memset(&iv, 0, sizeof(iv));
-
-       sg_init_one(&sg, hdr, 8);
-       skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
-       ret = crypto_skcipher_encrypt(req);
-       skcipher_request_zero(req);
-
-       _leave(" = %d", ret);
-       return ret;
+       fcrypt_pcbc_encrypt(call->conn->rxkad.cipher, zero_iv, hdr, hdr, 1);
+       _leave("");
 }
 
 /*
  * wholly encrypt a packet (level 2 security)
  */
-static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
-                                      struct rxrpc_txbuf *txb,
-                                      struct skcipher_request *req)
+static void rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
+                                       struct rxrpc_txbuf *txb)
 {
        const struct rxrpc_key_token *token;
        struct rxkad_level2_hdr *rxkhdr = txb->data;
-       struct rxrpc_crypt iv;
-       struct scatterlist sg;
        size_t content, pad;
        u16 check;
-       int ret;
 
        _enter("");
 
@@ -318,22 +255,18 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
        rxkhdr->checksum = 0;
 
        content = sizeof(struct rxkad_level2_hdr) + txb->len;
+       static_assert(RXKAD_ALIGN == FCRYPT_BSIZE);
        txb->pkt_len = round_up(content, RXKAD_ALIGN);
        pad = txb->pkt_len - content;
        if (pad)
                memset(txb->data + txb->offset, 0, pad);
+       /* Now txb->pkt_len % FCRYPT_BSIZE == 0. */
 
        /* encrypt from the session key */
        token = call->conn->key->payload.data[0];
-       memcpy(&iv, token->kad->session_key, sizeof(iv));
-
-       sg_init_one(&sg, rxkhdr, txb->pkt_len);
-       skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, &sg, &sg, txb->pkt_len, iv.x);
-       ret = crypto_skcipher_encrypt(req);
-       skcipher_request_zero(req);
-       return ret;
+       fcrypt_pcbc_encrypt(call->conn->rxkad.cipher, token->kad->session_key,
+                           rxkhdr, rxkhdr, txb->pkt_len / FCRYPT_BSIZE);
+       _leave("");
 }
 
 /*
@@ -341,9 +274,6 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
  */
 static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
 {
-       struct skcipher_request *req;
-       struct rxrpc_crypt iv;
-       struct scatterlist sg;
        union {
                __be32 buf[2];
        } crypto __aligned(8);
@@ -361,27 +291,16 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
        if (ret < 0)
                return ret;
 
-       req = rxkad_get_call_crypto(call);
-       if (!req)
-               return -ENOMEM;
-
-       /* continue encrypting from where we left off */
-       memcpy(&iv, call->conn->rxkad.csum_iv.x, sizeof(iv));
-
        /* calculate the security checksum */
        x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
        x |= txb->seq & 0x3fffffff;
        crypto.buf[0] = htonl(call->call_id);
        crypto.buf[1] = htonl(x);
 
-       sg_init_one(&sg, crypto.buf, 8);
-       skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
-       ret = crypto_skcipher_encrypt(req);
-       skcipher_request_zero(req);
-       if (ret < 0)
-               goto out;
+       /* continue encrypting from where we left off */
+       fcrypt_pcbc_encrypt(call->conn->rxkad.cipher,
+                           call->conn->rxkad.csum_iv.x, crypto.buf, crypto.buf,
+                           1);
 
        y = ntohl(crypto.buf[1]);
        y = (y >> 16) & 0xffff;
@@ -395,14 +314,16 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
                ret = 0;
                break;
        case RXRPC_SECURITY_AUTH:
-               ret = rxkad_secure_packet_auth(call, txb, req);
+               rxkad_secure_packet_auth(call, txb);
                if (txb->alloc_size == RXRPC_JUMBO_DATALEN)
                        txb->jumboable = true;
+               ret = 0;
                break;
        case RXRPC_SECURITY_ENCRYPT:
-               ret = rxkad_secure_packet_encrypt(call, txb, req);
+               rxkad_secure_packet_encrypt(call, txb);
                if (txb->alloc_size == RXRPC_JUMBO_DATALEN)
                        txb->jumboable = true;
+               ret = 0;
                break;
        default:
                ret = -EPERM;
@@ -417,8 +338,6 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
                memset(p + txb->pkt_len, 0, gap);
        }
 
-out:
-       skcipher_request_free(req);
        _leave(" = %d [set %x]", ret, y);
        return ret;
 }
@@ -427,17 +346,13 @@ out:
  * decrypt partial encryption on a packet (level 1 security)
  */
 static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
-                                rxrpc_seq_t seq,
-                                struct skcipher_request *req)
+                                rxrpc_seq_t seq)
 {
        struct rxkad_level1_hdr *sechdr;
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       struct rxrpc_crypt iv;
-       struct scatterlist sg[1];
        void *data = call->rx_dec_buffer;
        u32 len = sp->len, data_size, buf;
        u16 check;
-       int ret;
 
        _enter("");
 
@@ -445,21 +360,8 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
                return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
                                          rxkad_abort_1_short_header);
 
-       /* Decrypt the skbuff in-place.  TODO: We really want to decrypt
-        * directly into the target buffer.
-        */
-       sg_init_one(sg, data, len);
-
-       /* start the decryption afresh */
-       memset(&iv, 0, sizeof(iv));
-
-       skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
-       ret = crypto_skcipher_decrypt(req);
-       skcipher_request_zero(req);
-       if (ret < 0)
-               return ret;
+       /* Decrypt the first 8-byte block of the packet, using the zero IV. */
+       fcrypt_pcbc_decrypt(call->conn->rxkad.cipher, zero_iv, data, data, 1);
 
        /* Extract the decrypted packet length */
        sechdr = data;
@@ -488,18 +390,14 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
  * wholly decrypt a packet (level 2 security)
  */
 static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
-                                rxrpc_seq_t seq,
-                                struct skcipher_request *req)
+                                rxrpc_seq_t seq)
 {
        const struct rxrpc_key_token *token;
        struct rxkad_level2_hdr *sechdr;
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       struct rxrpc_crypt iv;
-       struct scatterlist sg[1];
        void *data = call->rx_dec_buffer;
        u32 len = sp->len, data_size, buf;
        u16 check;
-       int ret;
 
        _enter(",{%d}", len);
 
@@ -510,26 +408,10 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
        /* Don't let the crypto algo see a misaligned length. */
        len = round_down(len, 8);
 
-       /* Decrypt in place in the call's decryption buffer.  TODO: We really
-        * want to decrypt directly into the target buffer.
-        */
-       sg_init_one(sg, data, len);
-
        /* decrypt from the session key */
        token = call->conn->key->payload.data[0];
-       memcpy(&iv, token->kad->session_key, sizeof(iv));
-
-       skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, sg, sg, len, iv.x);
-       ret = crypto_skcipher_decrypt(req);
-       skcipher_request_zero(req);
-       if (ret < 0) {
-               if (ret == -ENOMEM)
-                       return ret;
-               return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
-                                         rxkad_abort_2_crypto_unaligned);
-       }
+       fcrypt_pcbc_decrypt(call->conn->rxkad.cipher, token->kad->session_key,
+                           data, data, len / FCRYPT_BSIZE);
 
        /* Extract the decrypted packet length */
        sechdr = data;
@@ -562,9 +444,6 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
 static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       struct skcipher_request *req;
-       struct rxrpc_crypt iv;
-       struct scatterlist sg;
        union {
                __be32 buf[2];
        } crypto __aligned(8);
@@ -579,27 +458,16 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
        if (!call->conn->rxkad.cipher)
                return 0;
 
-       req = rxkad_get_call_crypto(call);
-       if (!req)
-               return -ENOMEM;
-
-       /* continue encrypting from where we left off */
-       memcpy(&iv, call->conn->rxkad.csum_iv.x, sizeof(iv));
-
        /* validate the security checksum */
        x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
        x |= seq & 0x3fffffff;
        crypto.buf[0] = htonl(call->call_id);
        crypto.buf[1] = htonl(x);
 
-       sg_init_one(&sg, crypto.buf, 8);
-       skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
-       ret = crypto_skcipher_encrypt(req);
-       skcipher_request_zero(req);
-       if (ret < 0)
-               goto out;
+       /* continue encrypting from where we left off */
+       fcrypt_pcbc_encrypt(call->conn->rxkad.cipher,
+                           call->conn->rxkad.csum_iv.x, crypto.buf, crypto.buf,
+                           1);
 
        y = ntohl(crypto.buf[1]);
        cksum = (y >> 16) & 0xffff;
@@ -617,18 +485,16 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
                ret = 0;
                break;
        case RXRPC_SECURITY_AUTH:
-               ret = rxkad_verify_packet_1(call, skb, seq, req);
+               ret = rxkad_verify_packet_1(call, skb, seq);
                break;
        case RXRPC_SECURITY_ENCRYPT:
-               ret = rxkad_verify_packet_2(call, skb, seq, req);
+               ret = rxkad_verify_packet_2(call, skb, seq);
                break;
        default:
                ret = -ENOANO;
                break;
        }
-
 out:
-       skcipher_request_free(req);
        return ret;
 }
 
@@ -712,41 +578,6 @@ static void rxkad_calc_response_checksum(struct rxkad_response *response)
        response->encrypted.checksum = htonl(csum);
 }
 
-/*
- * encrypt the response packet
- */
-static int rxkad_encrypt_response(struct rxrpc_connection *conn,
-                                 struct sk_buff *response,
-                                 const struct rxkad_key *s2)
-{
-       struct skcipher_request *req;
-       struct rxrpc_crypt iv;
-       struct scatterlist sg[1];
-       size_t encsize = sizeof(((struct rxkad_response *)0)->encrypted);
-       int ret;
-
-       sg_init_table(sg, ARRAY_SIZE(sg));
-       ret = skb_to_sgvec(response, sg,
-                          sizeof(struct rxrpc_wire_header) +
-                          offsetof(struct rxkad_response, encrypted), encsize);
-       if (ret < 0)
-               return ret;
-
-       req = skcipher_request_alloc(&conn->rxkad.cipher->base, GFP_NOFS);
-       if (!req)
-               return -ENOMEM;
-
-       /* continue encrypting from where we left off */
-       memcpy(&iv, s2->session_key, sizeof(iv));
-
-       skcipher_request_set_sync_tfm(req, conn->rxkad.cipher);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, sg, sg, encsize, iv.x);
-       ret = crypto_skcipher_encrypt(req);
-       skcipher_request_free(req);
-       return ret;
-}
-
 /*
  * Validate a challenge packet.
  */
@@ -846,6 +677,12 @@ int rxkad_insert_response_header(struct rxrpc_connection *conn,
 
        rxkad_calc_response_checksum(&h.resp);
 
+       /* encrypt the response packet */
+       static_assert(sizeof(h.resp.encrypted) % FCRYPT_BSIZE == 0);
+       fcrypt_pcbc_encrypt(conn->rxkad.cipher, token->kad->session_key,
+                           &h.resp.encrypted, &h.resp.encrypted,
+                           sizeof(h.resp.encrypted) / FCRYPT_BSIZE);
+
        ret = skb_store_bits(response, *offset, &h, sizeof(h));
        *offset += sizeof(h);
        return ret;
@@ -890,10 +727,6 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
        if (ret < 0)
                goto error;
 
-       ret = rxkad_encrypt_response(conn, response, token->kad);
-       if (ret < 0)
-               goto error;
-
        ret = skb_store_bits(response, offset, token->kad->ticket,
                             token->kad->ticket_len);
        if (ret < 0)
@@ -1072,39 +905,22 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
 /*
  * decrypt the response packet
  */
-static int rxkad_decrypt_response(struct rxrpc_connection *conn,
-                                 struct rxkad_response *resp,
-                                 const struct rxrpc_crypt *session_key)
+static void rxkad_decrypt_response(struct rxrpc_connection *conn,
+                                  struct rxkad_response *resp,
+                                  const struct rxrpc_crypt *session_key)
 {
-       struct skcipher_request *req = rxkad_ci_req;
-       struct scatterlist sg[1];
-       struct rxrpc_crypt iv;
-       int ret;
+       struct fcrypt_key cipher;
 
        _enter(",,%08x%08x",
               ntohl(session_key->n[0]), ntohl(session_key->n[1]));
 
-       mutex_lock(&rxkad_ci_mutex);
-       ret = crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
-                                         sizeof(*session_key));
-       if (ret < 0)
-               goto unlock;
-
-       memcpy(&iv, session_key, sizeof(iv));
-
-       sg_init_table(sg, 1);
-       sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
-       skcipher_request_set_sync_tfm(req, rxkad_ci);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
-       ret = crypto_skcipher_decrypt(req);
-       skcipher_request_zero(req);
-
-unlock:
-       mutex_unlock(&rxkad_ci_mutex);
+       fcrypt_preparekey(&cipher, session_key->x);
 
+       static_assert(sizeof(resp->encrypted) % FCRYPT_BSIZE == 0);
+       fcrypt_pcbc_decrypt(&cipher, session_key->x, &resp->encrypted,
+                           &resp->encrypted,
+                           sizeof(resp->encrypted) / FCRYPT_BSIZE);
        _leave("");
-       return ret;
 }
 
 /*
@@ -1191,9 +1007,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
 
        /* use the session key from inside the ticket to decrypt the
         * response */
-       ret = rxkad_decrypt_response(conn, response, &session_key);
-       if (ret < 0)
-               goto error;
+       rxkad_decrypt_response(conn, response, &session_key);
 
        if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
            ntohl(response->encrypted.cid) != conn->proto.cid ||
@@ -1270,8 +1084,8 @@ static void rxkad_clear(struct rxrpc_connection *conn)
 {
        _enter("");
 
-       if (conn->rxkad.cipher)
-               crypto_free_sync_skcipher(conn->rxkad.cipher);
+       kfree_sensitive(conn->rxkad.cipher);
+       conn->rxkad.cipher = NULL;
 }
 
 /*
@@ -1279,26 +1093,11 @@ static void rxkad_clear(struct rxrpc_connection *conn)
  */
 static int rxkad_init(void)
 {
-       struct crypto_sync_skcipher *tfm;
-       struct skcipher_request *req;
-
-       /* pin the cipher we need so that the crypto layer doesn't invoke
-        * keventd to go get it */
-       tfm = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
-       if (IS_ERR(tfm))
-               return PTR_ERR(tfm);
-
-       req = skcipher_request_alloc(&tfm->base, GFP_KERNEL);
-       if (!req)
-               goto nomem_tfm;
-
-       rxkad_ci_req = req;
-       rxkad_ci = tfm;
+       if (fips_enabled) {
+               pr_warn("rxkad support is disabled due to FIPS\n");
+               return -ENOENT;
+       }
        return 0;
-
-nomem_tfm:
-       crypto_free_sync_skcipher(tfm);
-       return -ENOMEM;
 }
 
 /*
@@ -1306,8 +1105,6 @@ nomem_tfm:
  */
 static void rxkad_exit(void)
 {
-       crypto_free_sync_skcipher(rxkad_ci);
-       skcipher_request_free(rxkad_ci_req);
 }
 
 /*