shadowsocks/shadowsocks-windows · critical · System.Exception
failed to finish preparation
Error message
failed to finish preparation
What it means
Thrown from CipherSetKey when MbedTLS.cipher_reset returns non-zero, fired after a successful cipher_setkey. cipher_reset finalises the context for use; a failure here is rare and indicates the native context is in an inconsistent state after setkey (often a downstream effect of a partially valid cipher/key combo).
Source
Thrown at shadowsocks-csharp/Encryption/AEAD/AEADMbedTLSEncryptor.cs:68
}
MbedTLS.cipher_init(ctx);
if (MbedTLS.cipher_setup(ctx, MbedTLS.cipher_info_from_string(_innerLibName)) != 0)
throw new System.Exception("Cannot initialize mbed TLS cipher context");
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt,
_Masterkey, _sessionKey);
CipherSetKey(isEncrypt, _sessionKey);
}
private void CipherSetKey(bool isEncrypt, byte[] key)
{
IntPtr ctx = isEncrypt ? _encryptCtx : _decryptCtx;
int ret = MbedTLS.cipher_setkey(ctx, key, keyLen * 8,
isEncrypt ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT);
if (ret != 0) throw new System.Exception("failed to set key");
ret = MbedTLS.cipher_reset(ctx);
if (ret != 0) throw new System.Exception("failed to finish preparation");
}
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
// buf: all plaintext
// outbuf: ciphertext + tag
int ret;
byte[] tagbuf = new byte[tagLen];
uint olen = 0;
switch (_cipher)
{
case CIPHER_AES:
ret = MbedTLS.cipher_auth_encrypt(_encryptCtx,
/* nonce */
_encNonce, (uint) nonceLen,
/* AD */
IntPtr.Zero, 0,
/* plain */
View on GitHub (pinned to 891d971682)
Solutions
- Ensure InitCipher is called on a freshly allocated context per session and the context is not shared across threads.
- Check that setkey succeeded (error 10) before reset runs — the two are coupled.
- Rebuild/replace the native mbedTLS library if resets consistently fail, to rule out library corruption.
Example fix
// before
ret = MbedTLS.cipher_reset(ctx);
if (ret != 0) throw new System.Exception("failed to finish preparation");
// after
if (ret != 0)
throw new System.Exception($"failed to finish preparation (ret={ret}, cipher={_innerLibName})"); Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure context is fresh per session, not reused
if (_encryptCtx != IntPtr.Zero) { MbedTLS.cipher_free(_encryptCtx); _encryptCtx = IntPtr.Zero; } Try / catch
try { CipherSetKey(isEncrypt, key); /* includes reset */ }
catch (Exception ex) when (ex.Message == "failed to finish preparation")
{ /* recreate context from scratch and retry once */ } Prevention
- Allocate a new cipher context per session; never share across threads.
- Tear down contexts explicitly before reuse.
- If reset consistently fails, replace/rebuild the native library.
When it happens
Trigger: The cipher context entered an error state during setkey that was not caught by its return code; calling InitCipher twice on the same context without proper teardown; native memory corruption from a disposed/reused buffer.
Common situations: Reusing an encryptor context across reconnections without resetting state; a native buffer being garbage-collected or overwritten; threading on a non-thread-safe context.
Related errors
- failed to generate session key
- Cannot initialize mbed TLS cipher context
- failed to set key
- ret is {0}
- openssl: fail to create ctx
AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13).
Data as JSON: /api/errors/77b46cc12bb3b6f7.
Report an issue: GitHub.