shadowsocks/shadowsocks-windows · critical · System.Exception

openssl: fail to create ctx

Error message

openssl: fail to create ctx

What it means

Thrown from AEADOpenSSLEncryptor.InitCipher when OpenSSL.EVP_CIPHER_CTX_new returns IntPtr.Zero, meaning OpenSSL could not allocate a new cipher context. Allocation failure is almost always a sign of an uninitialized or broken OpenSSL library (the context struct is tiny, so genuine out-of-memory is rare).

Source

Thrown at shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs:52

        };

        public static List<string> SupportedCiphers()
        {
            return new List<string>(_ciphers.Keys);
        }

        protected override Dictionary<string, EncryptorInfo> getCiphers()
        {
            return _ciphers;
        }

        public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
        {
            base.InitCipher(salt, isEncrypt, isUdp);
            _cipherInfoPtr = OpenSSL.GetCipherInfo(_innerLibName);
            if (_cipherInfoPtr == IntPtr.Zero) throw new System.Exception("openssl: cipher not found");
            IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
            if (ctx == IntPtr.Zero) throw new System.Exception("openssl: fail to create ctx");

            if (isEncrypt)
            {
                _encryptCtx = ctx;
            }
            else
            {
                _decryptCtx = ctx;
            }

            DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt, _Masterkey,
                isEncrypt ? _opensslEncSubkey : _opensslDecSubkey);

            var ret = OpenSSL.EVP_CipherInit_ex(ctx, _cipherInfoPtr, IntPtr.Zero, null, null,
                isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
            if (ret != 1) throw new System.Exception("openssl: fail to init ctx");

            ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);

View on GitHub (pinned to 891d971682)

Solutions

  1. Ensure OpenSSL is initialised before any crypto call (modern OpenSSL auto-inits, but check for explicit cleanup elsewhere).
  2. Confirm the correct libcrypto is loaded (no DLL hijack / wrong bitness).
  3. Avoid calling crypto during process shutdown / after global cleanup.
  4. If it persists, switch to the mbedTLS backend.

Example fix

// before
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
if (ctx == IntPtr.Zero) throw new System.Exception("openssl: fail to create ctx");

// after
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
if (ctx == IntPtr.Zero)
    throw new System.Exception("openssl: fail to create ctx (library not initialised or wrong libcrypto loaded)");
Defensive patterns

Strategy: fallback

Validate before calling

// Ensure OpenSSL is usable before relying on it
IntPtr probe = OpenSSL.EVP_CIPHER_CTX_new();
if (probe == IntPtr.Zero) /* fall back to mbedTLS */
else OpenSSL.EVP_CIPHER_CTX_free(probe);

Type guard

bool OpenSSLReady() => OpenSSL.EVP_CIPHER_CTX_new() != IntPtr.Zero;

Try / catch

try { useOpenSSL(); }
catch (Exception ex) when (ex.Message.Contains("fail to create ctx"))
{ /* fall back to mbedTLS backend; likely OpenSSL not initialised/wrong lib */ }

Prevention

When it happens

Trigger: OpenSSL was not initialised (no OPENSSL_init_crypto / legacy init) before EVP_CIPHER_CTX_new; the native library failed to load or was already torn down; calling into OpenSSL after it was globally cleaned up.

Common situations: Mixing OpenSSL versions across native deps; calling crypto after EVP_cleanup/atexit; a DLL hijack loading the wrong libcrypto; process shutdown racing with crypto teardown.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13). Data as JSON: /api/errors/adcee774cdec0546. Report an issue: GitHub.