From: Zhushuai Yin <yinzhushuai@huawei.com> The HW SEC engine requires each non-last BD (Buffer Descriptor) to have 16B-aligned in_bytes for stream modes (CTR/CFB/OFB). When an application calls EVP_EncryptUpdate multiple times with non-16B-aligned chunk sizes on the same ctx, each update generates one BD; non-aligned non-last BDs corrupt the HW internal byte-level keystream state, producing wrong ciphertext from the chunk boundary onward. Fix this in uadk_prov_cipher_stream_update() by detecting stream-mode (CTR/CFB/OFB) input whose length is not a multiple of the IV/block size and routing the whole input to the SW fallback, so the HW never sees a non-aligned non-last BD. Also fix uadk_prov_cipher_soft_update() to re-init the SW ctx only on the HW->SW transition (switch_flag != UADK_DO_SOFT) instead of on every call. Re-initing every call reset the IV to priv->iv, causing counter/IV reuse across consecutive SW updates and further ciphertext corruption; preserving the SW state keeps the counter/IV chain continuous. Signed-off-by: Zhushuai Yin <yinzhushuai@huawei.com> --- src/uadk_prov_cipher.c | 44 ++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/uadk_prov_cipher.c b/src/uadk_prov_cipher.c index 1990116..b6c1dbb 100644 --- a/src/uadk_prov_cipher.c +++ b/src/uadk_prov_cipher.c @@ -338,18 +338,25 @@ static int uadk_prov_cipher_soft_update(struct cipher_priv_ctx *priv, unsigned c if (!priv->sw_cipher) return UADK_P_FAIL; - if (!EVP_CipherInit_ex2(priv->sw_ctx, priv->sw_cipher, priv->key, priv->iv, - priv->enc, NULL)) { - UADK_ERR("cipher soft init error!\n"); - return UADK_P_FAIL; - } - /* - * Sync padding setting so SW fallback respects the caller's pad config - * (e.g. one-shot OSSL_FUNC_CIPHER_CIPHER temporarily sets pad=0 for - * raw block cipher, matching default provider behavior). + * Re-init SW ctx only on HW→SW transition or first SW call. Consecutive + * SW calls preserve state (counter/IV chain); re-initing every call + * resets IV to priv->iv, causing counter/IV reuse. */ - EVP_CIPHER_CTX_set_padding(priv->sw_ctx, priv->pad); + if (priv->switch_flag != UADK_DO_SOFT) { + if (!EVP_CipherInit_ex2(priv->sw_ctx, priv->sw_cipher, priv->key, priv->iv, + priv->enc, NULL)) { + UADK_ERR("cipher soft init error!\n"); + return UADK_P_FAIL; + } + + /* + * Sync padding setting so SW fallback respects the caller's pad config + * (e.g. one-shot OSSL_FUNC_CIPHER_CIPHER temporarily sets pad=0 for + * raw block cipher, matching default provider behavior). + */ + EVP_CIPHER_CTX_set_padding(priv->sw_ctx, priv->pad); + } if (!EVP_CipherUpdate(priv->sw_ctx, out, outl, in, len)) { UADK_ERR("cipher soft update error!\n"); @@ -1061,6 +1068,23 @@ static int uadk_prov_cipher_stream_update(void *vctx, unsigned char *output, goto do_soft; } + /* + * Stream mode non-aligned fallback: HW requires 16B-aligned BDs for + * multi-BD stream continuity in CTR/CFB/OFB. Non-aligned input would + * corrupt the HW keystream state. Switch the whole input to SW. + */ + if ((priv->setup.mode == WD_CIPHER_CTR || + priv->setup.mode == WD_CIPHER_CFB || + priv->setup.mode == WD_CIPHER_OFB) && + priv->ivlen && (inl & (priv->ivlen - 1))) { + if (!priv->sw_cipher) + uadk_create_cipher_soft_ctx(priv); + if (!priv->sw_cipher) + goto hw_path; + goto do_soft; + } + +hw_path: ret = uadk_prov_hw_cipher(priv, output, outl, outsize, input, inl); if (ret != UADK_P_SUCCESS) { if (priv->sw_cipher) -- 2.43.0