diff --git a/net/rxrpc/Kconfig b/net/rxrpc/Kconfig index de19c67dc965..2cebb666dc07 100644 --- a/net/rxrpc/Kconfig +++ b/net/rxrpc/Kconfig @@ -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. diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 29d32aa4ecc7..5802f6f78723 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -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) \ diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c index 3ec3d89fdf14..a0aa78d89289 100644 --- a/net/rxrpc/key.c +++ b/net/rxrpc/key.c @@ -10,7 +10,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include #include #include #include diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index d8bc5ecbfc3d..ca9f0e82cb9a 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -7,16 +7,18 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include +#include +#include +#include #include #include #include #include #include -#include #include #include #include +#include #include #include #include @@ -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; diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c index 27491f1e1273..3efe104b1930 100644 --- a/net/rxrpc/server_key.c +++ b/net/rxrpc/server_key.c @@ -10,7 +10,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include #include #include #include diff --git a/net/rxrpc/tests/rxrpc_kunit.c b/net/rxrpc/tests/rxrpc_kunit.c index 85a9859fae44..95fd05a07d17 100644 --- a/net/rxrpc/tests/rxrpc_kunit.c +++ b/net/rxrpc/tests/rxrpc_kunit.c @@ -5,6 +5,7 @@ * Copyright 2026 Google LLC */ #include "../ar-internal.h" +#include #include 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), {}, };