CVE-2026-71225: Libkcapi: iv reuse in libkcapi one-shot symmetric cipher chunking causes cipher state reset across chunk boundaries
A flaw was found in libkcapi. When performing one-shot symmetric cipher operations on large inputs (over 64 KiB) in stateful modes such as Counter (CTR) or Cipher Block Chaining (CBC), the library improperly reuses the Initialization Vector (IV) for each internal data chunk. A remote attacker could potentially exploit this by making an application that uses libkcapi process specially crafted large inputs. This can lead to a significant weakening of data confidentiality, as the repeated IV use can expose relationships in encrypted plaintext, and may also affect data integrity by causing incorrect cryptographic processing.
Other sources
AIONLYREPORT package: libkcapi-1.5.0-3.el10 ------ Summary: IV Reuse in Symmetric Cipher Chunking: large one-shot symmetric cipher operations can resend the original IV for each internal chunk, restarting cipher state and breaking expected continuous-message behavior. Requirements to exploit: An attacker must be able to make an application using libkcapi-1.5.0-3.el10 call the one-shot symmetric cipher APIs on data larger than sysconf(SCPAGESIZE) ALGMAXPAGES (typically 64 KiB) in an affected stateful mode such as ctr or cbc, and observe the resulting ciphertext or decryption behavior. Reachability depends on the consuming application; the available evidence does not establish that every deployment exposes this path. Component affected: libkcapi-1.5.0-3.el10, lib/kcapi-sym.c, lib/kcapi-kernel-if.c, one-shot symmetric cipher path (kcapicipherencrypt, kcapicipherdecrypt, kcapiciphercryptchunk, kcapicommonsendmeta) Version affected: libkcapi-1.5.0-3.el10 Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N - 6.8 (MEDIUM) AV:N - In the worst-case deployment, a remote caller can trigger the affected one-shot API through a network-facing application that uses this library for large-buffer encryption or decryption. AC:H - Exploitation depends on specific application behavior: the one-shot path must be used, the input must cross the internal chunk threshold, and the mode must be one whose security depends on continuous IV/chaining state. PR:N - No privileges are inherent to the flaw itself. UI:N - No user interaction is required once the application processes the crafted large input. S:U - The impact remains within the vulnerable cryptographic operation and does not cross a separate security boundary. C:H - For ctr, restarting the keystream at chunk boundaries can expose plaintext relationships and materially weaken confidentiality. I:L - Resetting state across chunk boundaries can cause applications to process data with different cryptographic semantics than a continuous message, which can affect integrity expectations in some uses. A:N - No direct availability impact is established from the available evidence. Impact: Moderate. Based on Red Hat severity guidance, this flaw can cause a meaningful confidentiality loss or cryptographic semantic break in applications that use the affected large-buffer one-shot path, but exploitation depends on specific API usage patterns and affected modes rather than presenting an easily exploitable default remote compromise path in this SRPM package. Embargo: no Reason: The currently supported impact is use-dependent, practical mitigations exist, and the available evidence does not show an easily weaponized default exposure that would normally justify embargo handling. Acknowledgement: Aisle Research Vulnerability Details: The one-shot symmetric cipher entry points store the caller-provided IV once and then pass the request into kcapiciphercryptchunk(). For inputs larger than handle->pagesize ALGMAXPAGES, kcapiciphercryptchunk() splits the request into multiple chunks and calls kcapiciphercrypt() for each chunk. Each kcapiciphercrypt() call sends fresh operation metadata, and kcapicommonsendmeta() copies handle->cipher.iv into ALGSETIV every time. No IV advancement is visible between chunks, so each chunk is processed as a new operation with the same IV instead of as a continuation of one message. c handle->cipher.iv = iv; return kcapiciphercryptchunk(handle, in, inlen, out, outlen, access, ALGOPENCRYPT / or DECRYPT /); c while (inlen && outlen) { ... ret = kcapiciphercrypt(handle, in, inprocess, out, outprocess, access, enc); ... } c if (handle->cipher.iv) { ... memcpy(algiv->iv, handle->cipher.iv, tfm->info.ivsize); } For ctr, this restarts the keystream at each chunk boundary and can expose plaintext relationships across chunks. For cbc, the chaining value is reset at each boundary, so large one-shot processing no longer matches the behavior of one continuous CBC message. Based on the available evidence, this report is limited to the one-shot symmetric cipher path described above. Steps to reproduce: 1. Initialize a ctr(aes) handle and set the key. 2. Prepare 131072 bytes of plaintext, with block 0 identical to the block at offset 65536. 3. Encrypt the buffer with the one-shot API kcapicipherencrypt() using a fixed IV. 4. Encrypt the same plaintext as one continuous message using kcapicipherstreaminitenc(), repeated kcapicipherstreamupdate(), kcapicipherstreamupdatelast(), and kcapicipherstreamop(). 5. Compare the outputs. The observed condition is outoneshot != outstream, even though both operations are intended to represent the same continuous-message semantics. 6. For ctr(aes), verify that outoneshot[0:16] == outoneshot[65536:65552] when the corresponding plaintext blocks are equal. This indicates keystream restart at the chunk boundary. 7. Repeat with cbc(aes) and observe a mismatch versus the continuous-stream result at the chunk boundary. Mitigation: Until a fix is available, avoid using the one-shot symmetric cipher APIs for inputs larger than sysconf(SCPAGESIZE) ALGMAXPAGES when continuous-message semantics matter. Prefer the streaming interface for long messages, or keep one-shot inputs below the internal chunking threshold so the IV is applied only once per operation. Proposed Fix: Send operation metadata and IV only for the first internal chunk, then keep the AFALG operation open and send only data for subsequent chunks so cipher state is preserved across the full message. diff diff --git a/lib/kcapi-kernel-if.c b/lib/kcapi-kernel-if.c @@ ssizet kcapiciphercryptchunk(struct kcapihandle handle, const uint8t in, sizet inlen, uint8t out, sizet outlen, int access, unsigned int enc) { + bool first = true; ssizet totallen = 0; @@ while (inlen && outlen) { sizet inprocess = inlen; sizet outprocess = outlen; + bool last; + struct iovec iov; @@ if (inlen > maxprocess) inprocess = maxprocess; if (outlen > maxprocess) outprocess = maxprocess; + last = (inlen <= maxprocess); ret = kcapiciphercrypt(handle, in, inprocess, out, outprocess, access, enc); + if (first) { + if ((access == KCAPIACCESSHEURISTIC && inprocess <= (1<<13)) || + access == KCAPIACCESSSENDMSG) { + iov.iovbase = (void )(uintptrt)in; + iov.iovlen = inprocess; + ret = kcapicommonsendmeta(handle, &iov, 1, enc, last ? 0 : MSGMORE); + } else { + ret = kcapicommonsendmeta(handle, NULL, 0, enc, MSGMORE); + if (ret >= 0) + ret = kcapicommonvmsplicechunk(handle, in, inprocess, + last ? 0 : SPLICEFMORE); + } + first = false; + } else { + if ((access == KCAPIACCESSHEURISTIC && inprocess <= (1<<13)) || + access == KCAPIACCESSSENDMSG) { + iov.iovbase = (void )(uintptrt)in; + iov.iovlen = inprocess; + ret = kcapicommonsenddata(handle, &iov, 1, last ? 0 : MSGMORE); + } else { + ret = kcapicommonvmsplicechunk(handle, in, inprocess, + last ? 0 : SPLICEFMORE); + } + } if (ret < 0) return ret; + ret = kcapicommonreaddata(handle, out, outprocess); + if (ret < 0) + return ret; @@ } return totallen; }
------ This report was generated using AI technology. Always review AI-generated content prior to use
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Until a fix is available, avoid using the one-shot symmetric cipher APIs `kcapi_cipher_encrypt()` / `kcapi_cipher_decrypt()` on large inputs (> 64 KiB, i.e., larger than `sysconf(_SC_PAGESIZE) * ALG_MAX_PAGES`), especially in stateful modes such as `ctr` or `cbc`, because libkcapi reuses the IV across internal chunk boundaries.
libkcapi (one-shot symmetric cipher APIs) Avoid using one-shot symmetric cipher entry points for large inputs = enabled (do not use) - Configuration
Use the streaming interface (e.g., `kcapi_cipher_stream_init_enc()`, repeated `kcapi_cipher_stream_update()`, and `kcapi_cipher_stream_update_last()` / `kcapi_cipher_stream_op()`) so the cipher state is preserved across the full message and IV/chaining state is not reset per internal chunk.
libkcapi Use streaming interface instead of one-shot = enabled