From 7562ae5e371af35a65e9eb8bf1943536c0164ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 29 Jun 2026 09:14:51 +0200 Subject: [PATCH] F-6427 - Reject RC2 cipher ops when no key is set The RC2 encrypt and decrypt operations used the expanded key schedule without checking that a key had ever been configured. On a zeroed or otherwise unkeyed context the ECB ops ran over an all-zero schedule and returned success, and the CBC wrappers inherited the same behavior, so a caller who skipped wc_Rc2SetKey received ciphertext under an unintended key with no error signalled. Guard wc_Rc2EcbEncrypt and wc_Rc2EcbDecrypt on a zero keylen and return MISSING_KEY when no key has been set. The CBC wrappers call these and propagate the error. Mirrors the existing 3DES keySet guard. Add a regression test covering the unkeyed path for all four ops. --- tests/api/test_rc2.c | 31 +++++++++++++++++++++++++++++++ tests/api/test_rc2.h | 2 ++ wolfcrypt/src/rc2.c | 24 ++++++++++++++++-------- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/tests/api/test_rc2.c b/tests/api/test_rc2.c index 10b7194e4c..19f59e786a 100644 --- a/tests/api/test_rc2.c +++ b/tests/api/test_rc2.c @@ -228,6 +228,37 @@ int test_wc_Rc2CbcEncryptDecrypt(void) } /* END test_wc_Rc2CbcEncryptDecrypt */ +/* + * Cipher operations must fail safely when no key has been configured. + */ +int test_wc_Rc2_MissingKey(void) +{ + EXPECT_DECLS; +#ifdef WC_RC2 + Rc2 rc2; + byte out[RC2_BLOCK_SIZE]; + byte in[RC2_BLOCK_SIZE]; + + XMEMSET(out, 0, sizeof(out)); + XMEMSET(in, 0, sizeof(in)); + + /* Zeroed context, never keyed: every op must reject with MISSING_KEY + * rather than ciphering under an all-zero key schedule. */ + XMEMSET(&rc2, 0, sizeof(rc2)); + + ExpectIntEQ(wc_Rc2EcbEncrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Rc2EcbDecrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Rc2CbcEncrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Rc2CbcDecrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + return EXPECT_RESULT(); +} /* END test_wc_Rc2_MissingKey */ + + #define MC_CIPHER_TEST_COUNT 100 #define MC_RC2_MAX_DATA_SZ 1024 diff --git a/tests/api/test_rc2.h b/tests/api/test_rc2.h index acdd08e3ae..a9219494af 100644 --- a/tests/api/test_rc2.h +++ b/tests/api/test_rc2.h @@ -28,6 +28,7 @@ int test_wc_Rc2SetKey(void); int test_wc_Rc2SetIV(void); int test_wc_Rc2EcbEncryptDecrypt(void); int test_wc_Rc2CbcEncryptDecrypt(void); +int test_wc_Rc2_MissingKey(void); int test_wc_Rc2Cbc_MonteCarlo(void); int test_wc_Rc2Free(void); @@ -36,6 +37,7 @@ int test_wc_Rc2Free(void); TEST_DECL_GROUP("rc2", test_wc_Rc2SetIV), \ TEST_DECL_GROUP("rc2", test_wc_Rc2EcbEncryptDecrypt), \ TEST_DECL_GROUP("rc2", test_wc_Rc2CbcEncryptDecrypt), \ + TEST_DECL_GROUP("rc2", test_wc_Rc2_MissingKey), \ TEST_DECL_GROUP("rc2", test_wc_Rc2Cbc_MonteCarlo), \ TEST_DECL_GROUP("rc2", test_wc_Rc2Free) diff --git a/wolfcrypt/src/rc2.c b/wolfcrypt/src/rc2.c index 3fd9ecbbac..f4050b97bf 100644 --- a/wolfcrypt/src/rc2.c +++ b/wolfcrypt/src/rc2.c @@ -171,6 +171,10 @@ int wc_Rc2EcbEncrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BUFFER_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + r10 = (word16)((word16)in[1] << 8) | in[0]; /* R[0] */ r32 = (word16)((word16)in[3] << 8) | in[2]; /* R[1] */ r54 = (word16)((word16)in[5] << 8) | in[4]; /* R[2] */ @@ -236,6 +240,10 @@ int wc_Rc2EcbDecrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BUFFER_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + r0 = (word16)((word16)in[1] << 8) | in[0]; r1 = (word16)((word16)in[3] << 8) | in[2]; r2 = (word16)((word16)in[5] << 8) | in[4]; @@ -285,14 +293,14 @@ int wc_Rc2CbcEncrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BAD_FUNC_ARG; } - if (sz == 0) { - return 0; - } - if (sz % RC2_BLOCK_SIZE != 0) { return BAD_LENGTH_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + blocks = sz / RC2_BLOCK_SIZE; while (blocks--) { @@ -320,14 +328,14 @@ int wc_Rc2CbcDecrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BAD_FUNC_ARG; } - if (sz == 0) { - return 0; - } - if (sz % RC2_BLOCK_SIZE != 0) { return BAD_LENGTH_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + blocks = sz / RC2_BLOCK_SIZE; while (blocks--) {