[PATCH v8 06/14] crypto: qce - Fix xts-aes-qce for weak keys
From: Bartosz Golaszewski <hidden>
Date: 2026-09-21 12:59:05
Also in:
linux-arm-msm, linux-crypto, lkml, stable
Subsystem:
crypto api, qualcomm crypto drivers, the rest · Maintainers:
Herbert Xu, "David S. Miller", Bartosz Golaszewski, Linus Torvalds
From: Kuldeep Singh <redacted>
The QCE hardware does not support AES XTS mode when key1 and key2 are
equal. The driver was handling this by unconditionally rejecting the
keys with -ENOKEY(-126), regardless of whether FIPS mode is active or
the FORBID_WEAK_KEYS flag is set.
[ 5.599170] alg: skcipher: xts-aes-qce setkey failed on test vector 0; expected_error=0, actual_error=-126, flags=0x1
[ 5.599184] alg: self-tests for xts(aes) using xts-aes-qce failed (rc=-126)
In general for weak keys,
- If FIPS mode is active or FORBID_WEAK_KEYS is set: return -EINVAL.
- In non-FIPS mode, Accept the key and encrypt successfully.
Since QCE was returning -ENOKEY for non-FIPS mode whereas the
expectation is to encrypt content and return success, the selftest saw a
mismatch and failed.
There are two problems in QCE behavior:
* -ENOKEY is returned instead of -EINVAL for the FIPS/weak-key
rejection case.
* key1 == key2 is rejected even in non-FIPS mode
Fix xts-aes-qce behavior by using generic helper xts_verify_key() to
reject keys early with -EINVAL for FIPS mode active(or FORBID_WEAK_KEYS
set). For non-FIPS mode, since QCE hardware cannot accept the keys, use
software fallback mechanism to encrypt the data.
Cc: stable@vger.kernel.org
Fixes: f0d078dd6c49 ("crypto: qce - Return unsupported if key1 and key 2 are same for AES XTS algorithm")
Signed-off-by: Kuldeep Singh <redacted>
Tested-by: Kuldeep Singh <redacted>
Signed-off-by: Bartosz Golaszewski <redacted>
---
drivers/crypto/qce/cipher.h | 1 +
drivers/crypto/qce/skcipher.c | 18 ++++++++++++------
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h
index 850f257d00f3aca0397adc1f703aea690c754d60..daea07551118d444d2f749588bdfe2ae2c6c553f 100644
--- a/drivers/crypto/qce/cipher.h
+++ b/drivers/crypto/qce/cipher.h@@ -14,6 +14,7 @@ struct qce_cipher_ctx { u8 enc_key[QCE_MAX_KEY_SIZE]; unsigned int enc_keylen; + bool use_fallback; struct crypto_skcipher *fallback; };
diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c
index 4b7545e6aed220b7fb5af7dbf20ab47db5d1d180..35bd59656931c5f12614405490f1e254849b9eb5 100644
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c@@ -12,6 +12,7 @@ #include <linux/errno.h> #include <crypto/aes.h> #include <crypto/internal/skcipher.h> +#include <crypto/xts.h> #include "cipher.h"
@@ -194,14 +195,17 @@ static int qce_skcipher_setkey(struct crypto_skcipher *ablk, const u8 *key, if (!key || !keylen) return -EINVAL; - /* - * AES XTS key1 = key2 not supported by crypto engine. - * Revisit to request a fallback cipher in this case. - */ if (IS_XTS(flags)) { + ret = xts_verify_key(ablk, key, keylen); + if (ret) + return ret; __keylen = keylen >> 1; - if (!memcmp(key, key + __keylen, __keylen)) - return -ENOKEY; + /* + * QCE does not support key1 == key2 for XTS. + * Use fallback cipher in this case. + */ + ctx->use_fallback = !crypto_memneq(key, key + __keylen, + __keylen); } else { __keylen = keylen; }
@@ -261,6 +265,7 @@ static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt) * needed in all versions of CE) * AES-CTR with a partial final block (the CE stalls waiting for a full * block of input). + * AES-XTS with key1 == key2 (not supported by the CE). * A payload fragmented across more than one scatterlist entry (the CE * stalls waiting for input in that case too). */
@@ -270,6 +275,7 @@ static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt) (IS_XTS(rctx->flags) && ((req->cryptlen <= aes_sw_max_len) || (req->cryptlen > QCE_SECTOR_SIZE && req->cryptlen % QCE_SECTOR_SIZE))) || + (IS_XTS(rctx->flags) && ctx->use_fallback) || sg_nents_for_len(req->src, req->cryptlen) > 1 || sg_nents_for_len(req->dst, req->cryptlen) > 1)) { skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
--
2.47.3