]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net/rxrpc: Reimplement DES-PCBC using DES library
authorEric Biggers <ebiggers@kernel.org>
Fri, 22 May 2026 05:07:34 +0000 (00:07 -0500)
committerJakub Kicinski <kuba@kernel.org>
Wed, 10 Jun 2026 00:03:03 +0000 (17:03 -0700)
Since the use of "pcbc(des)" in rxkad_decrypt_ticket() is the only
remaining user of the crypto API "pcbc" template, just implement
DES-PCBC by locally implementing PCBC mode on top of the DES library.
Note that only the decryption direction is needed.

This will allow support for the obsolete PCBC mode to be removed from
the crypto API.

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-4-ebiggers@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/rxrpc/Kconfig
net/rxrpc/ar-internal.h
net/rxrpc/key.c
net/rxrpc/rxkad.c
net/rxrpc/server_key.c
net/rxrpc/tests/rxrpc_kunit.c

index de19c67dc9652130f11a63bbb95c91044b9d55b3..2cebb666dc071144802240350def0b33c480faa2 100644 (file)
@@ -7,6 +7,7 @@ config AF_RXRPC
        tristate "RxRPC session sockets"
        depends on INET
        select CRYPTO
+       select CRYPTO_LIB_DES if RXKAD
        select KEYS
        select NET_UDP_TUNNEL
        help
@@ -56,10 +57,6 @@ config AF_RXRPC_DEBUG
 
 config RXKAD
        bool "RxRPC Kerberos security"
-       select CRYPTO
-       select CRYPTO_MANAGER
-       select CRYPTO_SKCIPHER
-       select CRYPTO_PCBC
        help
          Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC
          through the use of the key retention service.
index 29d32aa4ecc7794f4b956c7cbcb825ddc77b3888..5802f6f78723bc84977bc15afc5887a499602aab 100644 (file)
@@ -36,6 +36,11 @@ void fcrypt_pcbc_encrypt(const struct fcrypt_key *key,
 void fcrypt_pcbc_decrypt(const struct fcrypt_key *key,
                         const u8 iv[FCRYPT_BSIZE], const void *src, void *dst,
                         size_t nblocks);
+#if IS_ENABLED(CONFIG_KUNIT)
+struct des_ctx;
+void des_pcbc_decrypt_inplace(const struct des_ctx *key, __le64 iv, u8 *data,
+                             size_t len);
+#endif
 
 #define rxrpc_queue_work(WS)   queue_work(rxrpc_workqueue, (WS))
 #define rxrpc_queue_delayed_work(WS,D) \
index 3ec3d89fdf14038f4ecbe5bfbcf4c010d4f1acfb..a0aa78d892897f5c552df3a34c582d5a49172909 100644 (file)
@@ -10,7 +10,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <crypto/skcipher.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/overflow.h>
index d8bc5ecbfc3d05f39fca448f10738409be2f3878..ca9f0e82cb9ac7995e1c2d90e5084c52370c1879 100644 (file)
@@ -7,16 +7,18 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <crypto/skcipher.h>
+#include <crypto/des.h>
+#include <kunit/visibility.h>
+#include <linux/export.h>
 #include <linux/fips.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/skbuff.h>
 #include <linux/udp.h>
-#include <linux/scatterlist.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/key-type.h>
+#include <linux/unaligned.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include <keys/rxrpc-type.h>
@@ -52,40 +54,41 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn,
  */
 static int rxkad_preparse_server_key(struct key_preparsed_payload *prep)
 {
-       struct crypto_skcipher *ci;
+       struct des_ctx *des_key;
+       int err;
 
        if (prep->datalen != 8)
                return -EINVAL;
 
        memcpy(&prep->payload.data[2], prep->data, 8);
 
-       ci = crypto_alloc_skcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(ci)) {
-               _leave(" = %ld", PTR_ERR(ci));
-               return PTR_ERR(ci);
+       des_key = kmalloc_obj(*des_key);
+       if (!des_key) {
+               _leave(" = -ENOMEM");
+               return -ENOMEM;
        }
 
-       if (crypto_skcipher_setkey(ci, prep->data, 8) < 0)
-               BUG();
+       err = des_expand_key(des_key, prep->data, 8);
+       if (err) {
+               kfree_sensitive(des_key);
+               _leave(" = %d", err);
+               return err;
+       }
 
-       prep->payload.data[0] = ci;
+       prep->payload.data[0] = des_key;
        _leave(" = 0");
        return 0;
 }
 
 static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep)
 {
-
-       if (prep->payload.data[0])
-               crypto_free_skcipher(prep->payload.data[0]);
+       kfree_sensitive(prep->payload.data[0]);
 }
 
 static void rxkad_destroy_server_key(struct key *key)
 {
-       if (key->payload.data[0]) {
-               crypto_free_skcipher(key->payload.data[0]);
-               key->payload.data[0] = NULL;
-       }
+       kfree_sensitive(key->payload.data[0]);
+       key->payload.data[0] = NULL;
 }
 
 /*
@@ -771,6 +774,22 @@ int rxkad_kernel_respond_to_challenge(struct sk_buff *challenge)
 }
 EXPORT_SYMBOL(rxkad_kernel_respond_to_challenge);
 
+/* Decrypt data in-place using DES-PCBC.  @len must be a multiple of 8. */
+VISIBLE_IF_KUNIT void des_pcbc_decrypt_inplace(const struct des_ctx *key,
+                                              __le64 iv, u8 *data, size_t len)
+{
+       for (size_t i = 0; i < len; i += DES_BLOCK_SIZE) {
+               __le64 ctext, ptext;
+
+               ctext = get_unaligned((const __le64 *)&data[i]);
+               des_decrypt(key, (u8 *)&ptext, (const u8 *)&ctext);
+               ptext ^= iv;
+               put_unaligned(ptext, (__le64 *)&data[i]);
+               iv = ptext ^ ctext;
+       }
+}
+EXPORT_SYMBOL_IF_KUNIT(des_pcbc_decrypt_inplace);
+
 /*
  * decrypt the kerberos IV ticket in the response
  */
@@ -781,13 +800,10 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
                                struct rxrpc_crypt *_session_key,
                                time64_t *_expiry)
 {
-       struct skcipher_request *req;
-       struct rxrpc_crypt iv, key;
-       struct scatterlist sg[1];
+       struct rxrpc_crypt key;
        struct in_addr addr;
        unsigned int life;
        time64_t issue, now;
-       int ret;
        bool little_endian;
        u8 *p, *q, *name, *end;
 
@@ -797,21 +813,13 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
 
        ASSERT(server_key->payload.data[0] != NULL);
 
-       memcpy(&iv, &server_key->payload.data[2], sizeof(iv));
-
-       req = skcipher_request_alloc(server_key->payload.data[0], GFP_NOFS);
-       if (!req)
-               return -ENOMEM;
-
-       sg_init_one(&sg[0], ticket, ticket_len);
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
-       ret = crypto_skcipher_decrypt(req);
-       skcipher_request_free(req);
-       if (ret < 0)
+       if (ticket_len % DES_BLOCK_SIZE != 0)
                return rxrpc_abort_conn(conn, skb, RXKADBADTICKET, -EPROTO,
                                        rxkad_abort_resp_tkt_short);
-
+       des_pcbc_decrypt_inplace(
+               server_key->payload.data[0],
+               get_unaligned((const __le64 *)&server_key->payload.data[2]),
+               ticket, ticket_len);
        p = ticket;
        end = p + ticket_len;
 
index 27491f1e12736699cb7b44a1c6936553ffe369c6..3efe104b1930cb11e3e333c733a8b72fe8a62d29 100644 (file)
@@ -10,7 +10,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <crypto/skcipher.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/skbuff.h>
index 85a9859fae441d9fd767c0492cd86f26508dba71..95fd05a07d17a60291b7e6398535bc2ef0c0ef86 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright 2026 Google LLC
  */
 #include "../ar-internal.h"
+#include <crypto/des.h>
 #include <kunit/test.h>
 
 struct fcrypt_pcbc_testvec {
@@ -93,8 +94,38 @@ static void test_fcrypt_pcbc(struct kunit *test)
        }
 }
 
+static void test_des_pcbc(struct kunit *test)
+{
+       /* This was generated from the original pcbc(des) crypto API code. */
+       static const u8 expected_ptext[24] =
+               "\xc8\xe2\x3c\xdf\x80\x61\x8a\xad\xa5\x52\xb4\x20"
+               "\x74\x32\x1f\xe4\x2c\x15\x7d\x21\x57\xda\x3f\x31";
+       u8 key[8];
+       union {
+               __le64 w;
+               u8 b[8];
+       } iv;
+       u8 data[24];
+       struct des_ctx ctx;
+       int err;
+
+       for (int i = 0; i < 8; i++) {
+               key[i] = i;
+               iv.b[i] = 255 - i;
+       }
+       for (int i = 0; i < sizeof(data); i++)
+               data[i] = i;
+
+       err = des_expand_key(&ctx, key, sizeof(key));
+       KUNIT_ASSERT_EQ(test, 0, err);
+
+       des_pcbc_decrypt_inplace(&ctx, iv.w, data, sizeof(data));
+       KUNIT_ASSERT_MEMEQ(test, expected_ptext, data, sizeof(data));
+}
+
 static struct kunit_case rxrpc_test_cases[] = {
        KUNIT_CASE(test_fcrypt_pcbc),
+       KUNIT_CASE(test_des_pcbc),
        {},
 };