Fix AES-CBC with mbedTLS 3.x: restore PKCS7 padding and apply caller IV - #142
Open
yveshughes wants to merge 1 commit into
Open
Fix AES-CBC with mbedTLS 3.x: restore PKCS7 padding and apply caller IV#142yveshughes wants to merge 1 commit into
yveshughes wants to merge 1 commit into
Conversation
mbedtls_cipher_setup() in mbedTLS 3.x no longer installs a default
padding mode for CBC contexts (mbedTLS 2.x defaulted to PKCS7, as does
OpenSSL's EVP layer). Without an explicit padding mode,
mbedtls_cipher_finish() fails with MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
(-0x6100) on every AES-CBC operation that uses CIPHER_FLAG_FINISH,
which breaks audio decryption ("Failed to decrypt audio packet") for
any client built with USE_MBEDTLS against mbedTLS 3.x. Set PKCS7
explicitly for CBC contexts at init, guarded by
MBEDTLS_CIPHER_MODE_WITH_PADDING.
Additionally, the mbedTLS path never applied the caller-provided IV
unless CIPHER_FLAG_RESET_IV was set, leaving the context IV zeroed
from setup. The OpenSSL path passes the IV to the first
EVP_*Init_ex() call regardless of that flag, which the pre-Gen 7 CBC
remote input encryption in InputStream.c relies on (initial caller-set
IV followed by cross-packet CBC chaining). Apply the caller's IV
during first-time initialization for non-GCM contexts to match.
Verified against OpenSSL: AES-128-CBC/PKCS7 packets encrypted via the
OpenSSL path decrypt correctly through the mbedTLS path, and mbedTLS
CBC encryption byte-matches OpenSSL output including cross-packet
chaining.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Ran in to this whilst updating moonlight-android. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Building with
USE_MBEDTLS=ONagainst mbedTLS 3.x breaks both AES-CBC uses ofPlatformCrypto.c, while the same code works with mbedTLS 2.x and OpenSSL. There are two separate divergences from the OpenSSL path:1. mbedTLS 3.x removed the default PKCS7 padding mode for CBC contexts
In mbedTLS 2.x,
mbedtls_cipher_setup()initialized CBC contexts with PKCS7 padding by default (matching OpenSSL's EVP layer, which also defaults to PKCS7). In mbedTLS 3.x this default was removed — a freshly set-up CBC context has no padding mode, andmbedtls_cipher_finish()fails withMBEDTLS_ERR_CIPHER_BAD_INPUT_DATA(-0x6100) on any input.Since
PltDecryptMessage()never set a padding mode explicitly, everyALGORITHM_AES_CBC+CIPHER_FLAG_FINISHoperation fails. The user-visible symptom isFailed to decrypt audio packeton every audio packet when streaming from Sunshine or GameStream with an mbedTLS-3.x-built client — audio is completely broken.Fix: explicitly set
MBEDTLS_PADDING_PKCS7on CBC contexts at first-time init in bothPltEncryptMessage()andPltDecryptMessage(), guarded by#ifdef MBEDTLS_CIPHER_MODE_WITH_PADDING.2. The caller's IV is never applied without
CIPHER_FLAG_RESET_IVThe OpenSSL path passes the caller's IV into the first
EVP_EncryptInit_ex()/EVP_DecryptInit_ex()call even whenCIPHER_FLAG_RESET_IVis not set. The mbedTLS path only callsmbedtls_cipher_set_iv()when that flag is present, so without it the context keeps the all-zero IV from setup and the first block is en/decrypted with the wrong IV.This affects the pre-Gen 7 CBC remote input encryption in
InputStream.c, which initializes the context once with the real IV and then relies on cross-packet CBC chaining (noCIPHER_FLAG_RESET_IV).Fix: apply the caller's IV (
set_iv+reset) during first-time initialization for non-GCM contexts. GCM is excluded because it passes its per-message IV directly tombedtls_cipher_auth_{encrypt,decrypt}_ext().Verification
Tested on Linux against mbedTLS 3.6.2 with standalone host-side tests cross-checking against OpenSSL:
PltEncryptMessage()path (Sunshine's audio packet format) decrypt correctly through the fixed mbedTLSPltDecryptMessage()path.PltEncryptMessage()CBC output is byte-identical to OpenSSL output across a sequence of packets on one context, confirming the cross-packet CBC chaining behavior (input-stream style, noRESET_IV) matches.GCM paths (video/control, Gen 7+ input) are unaffected: they always pass
CIPHER_FLAG_RESET_IVor use the auth-crypt entry points, and padding does not apply to GCM.Related: #75 migrated to the mbedTLS 3.x API surface but didn't cover this behavioral change in
mbedtls_cipher_setup().🤖 Generated with Claude Code