* [PATCH 1/2] crypto: qce: Fix xts-aes-qce for weak keys
2026-06-10 5:54 [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures Kuldeep Singh
@ 2026-06-10 5:54 ` Kuldeep Singh
2026-06-10 5:54 ` [PATCH 2/2] crypto: qce: Fix CTR-AES for partial block requests Kuldeep Singh
2026-06-10 18:42 ` [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures Eric Biggers
2 siblings, 0 replies; 7+ messages in thread
From: Kuldeep Singh @ 2026-06-10 5:54 UTC (permalink / raw)
To: Thara Gopinath, Herbert Xu, David S. Miller, Bartosz Golaszewski,
Eric Biggers
Cc: Thara Gopinath, linux-crypto, linux-arm-msm, linux-kernel,
Kuldeep Singh
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.
Fixes: f0d078dd6c49 ("crypto: qce - Return unsupported if key1 and key 2 are same for AES XTS algorithm")
Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
---
drivers/crypto/qce/cipher.h | 1 +
drivers/crypto/qce/skcipher.c | 20 +++++++++++++-------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h
index 850f257d00f3..daea07551118 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 db0b648a56eb..224693a831f5 100644
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -13,6 +13,7 @@
#include <crypto/aes.h>
#include <crypto/internal/des.h>
#include <crypto/internal/skcipher.h>
+#include <crypto/xts.h>
#include "cipher.h"
@@ -180,14 +181,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;
}
@@ -287,12 +291,14 @@ static int qce_skcipher_crypt(struct skcipher_request *req, int encrypt)
* AES-XTS request with len > QCE_SECTOR_SIZE and
* is not a multiple of it.(Revisit this condition to check if it is
* needed in all versions of CE)
+ * AES-XTS for weak keys in non-FIPS mode.
*/
if (IS_AES(rctx->flags) &&
((keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256) ||
(IS_XTS(rctx->flags) && ((req->cryptlen <= aes_sw_max_len) ||
(req->cryptlen > QCE_SECTOR_SIZE &&
- req->cryptlen % QCE_SECTOR_SIZE))))) {
+ req->cryptlen % QCE_SECTOR_SIZE))) ||
+ (IS_XTS(rctx->flags) && ctx->use_fallback))) {
skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
skcipher_request_set_callback(&rctx->fallback_req,
req->base.flags,
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/2] crypto: qce: Fix CTR-AES for partial block requests
2026-06-10 5:54 [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures Kuldeep Singh
2026-06-10 5:54 ` [PATCH 1/2] crypto: qce: Fix xts-aes-qce for weak keys Kuldeep Singh
@ 2026-06-10 5:54 ` Kuldeep Singh
2026-06-10 18:46 ` Eric Biggers
2026-06-10 18:42 ` [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures Eric Biggers
2 siblings, 1 reply; 7+ messages in thread
From: Kuldeep Singh @ 2026-06-10 5:54 UTC (permalink / raw)
To: Thara Gopinath, Herbert Xu, David S. Miller, Bartosz Golaszewski,
Eric Biggers
Cc: Thara Gopinath, linux-crypto, linux-arm-msm, linux-kernel,
Kuldeep Singh
In CTR mode, the IV acts as the initial counter block.
APer NIST SP 800-38A, after a CTR mode operation the next unused counter
value is:
IV_next = IV_in + ceil(cryptlen / AES_BLOCK_SIZE)
The skcipher requires req->iv to hold this updated counter on
completion, ensuring chained requests produce correct results.
Referring to Crypto6.0 documentation, Section 2.2.5 says:
"The count value increments automatically once per block of data (in
AES, a block is 16 bytes) based on the value in the
CRYPTO_ENCR_CNTR_MASK registers."
QCE increments internal counter register once per full 16-byte block(for
ctr-aes) is processed. In case of partial request length, the hardware
uses the current counter to generate keystreams but does not increment
the counter register afterwards. So the counter value written in
CRYPTO_ENCR_CNTRn_IVn later once read by software is one less than the
expected value.
Crypto selftest framework capture this scenario with test vector
4 comprising of a 499-byte payload (31 full blocks + 3 partial bytes).
Error:
[ 5.606169] alg: skcipher: ctr-aes-qce encryption test failed (wrong output IV) on test vector 4, cfg="in-place (one sglist)"
[ 5.606176] 00000000: e7 82 1d b8 53 11 ac 47 e2 7d 18 d6 71 0c a7 61
[ 5.606192] alg: self-tests for ctr(aes) using ctr-aes-qce failed (rc=-22)
Expected iv_out: 0x62 (iv_in + 32)
Obtained iv_out: 0x61 (iv_in + 31, partial block not counted)
To fix this, just increase the counter value for partial block requests
by 1 and for the full block size requests, don't take any action as
expected value is already returned by the hardware.
Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
---
drivers/crypto/qce/skcipher.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c
index 224693a831f5..b25e3b76b6c8 100644
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <crypto/aes.h>
+#include <crypto/algapi.h>
#include <crypto/internal/des.h>
#include <crypto/internal/skcipher.h>
#include <crypto/xts.h>
@@ -59,6 +60,14 @@ static void qce_skcipher_done(void *data)
dev_dbg(qce->dev, "skcipher operation error (%x)\n", status);
memcpy(rctx->iv, result_buf->encr_cntr_iv, rctx->ivsize);
+ /*
+ * QCE hardware does not increment the counter for a partial final
+ * block. Increment it in software so that iv_out reflects the correct
+ * next counter value expected by the CTR mode.
+ */
+ if (IS_CTR(rctx->flags) &&
+ (rctx->cryptlen % crypto_skcipher_chunksize(crypto_skcipher_reqtfm(req))))
+ crypto_inc(rctx->iv, rctx->ivsize);
qce->async_req_done(tmpl->qce, error);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] crypto: qce: Fix CTR-AES for partial block requests
2026-06-10 5:54 ` [PATCH 2/2] crypto: qce: Fix CTR-AES for partial block requests Kuldeep Singh
@ 2026-06-10 18:46 ` Eric Biggers
2026-06-11 9:49 ` Kuldeep Singh
0 siblings, 1 reply; 7+ messages in thread
From: Eric Biggers @ 2026-06-10 18:46 UTC (permalink / raw)
To: Kuldeep Singh
Cc: Thara Gopinath, Herbert Xu, David S. Miller, Bartosz Golaszewski,
Thara Gopinath, linux-crypto, linux-arm-msm, linux-kernel
On Wed, Jun 10, 2026 at 11:24:05AM +0530, Kuldeep Singh wrote:
> In CTR mode, the IV acts as the initial counter block.
> APer NIST SP 800-38A, after a CTR mode operation the next unused counter
> value is:
>
> IV_next = IV_in + ceil(cryptlen / AES_BLOCK_SIZE)
>
> The skcipher requires req->iv to hold this updated counter on
> completion, ensuring chained requests produce correct results.
>
> Referring to Crypto6.0 documentation, Section 2.2.5 says:
> "The count value increments automatically once per block of data (in
> AES, a block is 16 bytes) based on the value in the
> CRYPTO_ENCR_CNTR_MASK registers."
>
> QCE increments internal counter register once per full 16-byte block(for
> ctr-aes) is processed. In case of partial request length, the hardware
> uses the current counter to generate keystreams but does not increment
> the counter register afterwards. So the counter value written in
> CRYPTO_ENCR_CNTRn_IVn later once read by software is one less than the
> expected value.
>
> Crypto selftest framework capture this scenario with test vector
> 4 comprising of a 499-byte payload (31 full blocks + 3 partial bytes).
> Error:
> [ 5.606169] alg: skcipher: ctr-aes-qce encryption test failed (wrong output IV) on test vector 4, cfg="in-place (one sglist)"
> [ 5.606176] 00000000: e7 82 1d b8 53 11 ac 47 e2 7d 18 d6 71 0c a7 61
> [ 5.606192] alg: self-tests for ctr(aes) using ctr-aes-qce failed (rc=-22)
> Expected iv_out: 0x62 (iv_in + 32)
> Obtained iv_out: 0x61 (iv_in + 31, partial block not counted)
>
> To fix this, just increase the counter value for partial block requests
> by 1 and for the full block size requests, don't take any action as
> expected value is already returned by the hardware.
>
> Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
This fix isn't Cc'ed to stable, so stable kernels will remain vulnerable
to this bug.
- Eric
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] crypto: qce: Fix CTR-AES for partial block requests
2026-06-10 18:46 ` Eric Biggers
@ 2026-06-11 9:49 ` Kuldeep Singh
0 siblings, 0 replies; 7+ messages in thread
From: Kuldeep Singh @ 2026-06-11 9:49 UTC (permalink / raw)
To: Eric Biggers
Cc: Thara Gopinath, Herbert Xu, David S. Miller, Bartosz Golaszewski,
Thara Gopinath, linux-crypto, linux-arm-msm, linux-kernel
> This fix isn't Cc'ed to stable, so stable kernels will remain vulnerable
> to this bug.
Sure, I'll Cc stable tag in v2 with any other feedback/comments on these
patches.
--
Regards
Kuldeep
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures
2026-06-10 5:54 [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures Kuldeep Singh
2026-06-10 5:54 ` [PATCH 1/2] crypto: qce: Fix xts-aes-qce for weak keys Kuldeep Singh
2026-06-10 5:54 ` [PATCH 2/2] crypto: qce: Fix CTR-AES for partial block requests Kuldeep Singh
@ 2026-06-10 18:42 ` Eric Biggers
2026-06-11 9:47 ` Kuldeep Singh
2 siblings, 1 reply; 7+ messages in thread
From: Eric Biggers @ 2026-06-10 18:42 UTC (permalink / raw)
To: Kuldeep Singh
Cc: Thara Gopinath, Herbert Xu, David S. Miller, Bartosz Golaszewski,
Thara Gopinath, linux-crypto, linux-arm-msm, linux-kernel
On Wed, Jun 10, 2026 at 11:24:03AM +0530, Kuldeep Singh wrote:
> Steps followed:
> - Enable EXPERT and CRYPTO_SEFLTESTS config.
So the full tests (CRYPTO_SELFTESTS_FULL) still haven't been run?
- Eric
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures
2026-06-10 18:42 ` [PATCH 0/2] Fix Qualcomm Crypto engine self tests failures Eric Biggers
@ 2026-06-11 9:47 ` Kuldeep Singh
0 siblings, 0 replies; 7+ messages in thread
From: Kuldeep Singh @ 2026-06-11 9:47 UTC (permalink / raw)
To: Eric Biggers, Bartosz Golaszewski
Cc: Thara Gopinath, Herbert Xu, David S. Miller, Bartosz Golaszewski,
Thara Gopinath, linux-crypto, linux-arm-msm, linux-kernel
On 11-06-2026 00:12, Eric Biggers wrote:
> On Wed, Jun 10, 2026 at 11:24:03AM +0530, Kuldeep Singh wrote:
>> Steps followed:
>> - Enable EXPERT and CRYPTO_SEFLTESTS config.
>
> So the full tests (CRYPTO_SELFTESTS_FULL) still haven't been run?
Crypto_selftests was only run as there's some discussion ongoing with
Bartosz on removal of deprecated/unsafe algos.
Seems Bartosz will be sending patches for algorithm removal changes.
The rest relevant selftests issues we'll fix accordingly.
--
Regards
Kuldeep
^ permalink raw reply [flat|nested] 7+ messages in thread