{"record":{"id":"cae99c79b75003a6","repo":"shadowsocks/shadowsocks-windows","slug":"openssl-fail-to-finalize-aead","errorCode":null,"errorMessage":"openssl: fail to finalize AEAD","messagePattern":"openssl: fail to finalize AEAD","errorType":"exception","errorClass":"CryptoErrorException","httpStatus":null,"severity":"critical","filePath":"shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs","lineNumber":101,"sourceCode":"        }\r\n\r\n        public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)\r\n        {\r\n            OpenSSL.SetCtxNonce(_encryptCtx, _encNonce, true);\r\n            // buf: all plaintext\r\n            // outbuf: ciphertext + tag\r\n            int ret;\r\n            int tmpLen = 0;\r\n            clen = 0;\r\n            var tagBuf = new byte[tagLen];\r\n\r\n            ret = OpenSSL.EVP_CipherUpdate(_encryptCtx, ciphertext, out tmpLen,\r\n                plaintext, (int) plen);\r\n            if (ret != 1) throw new CryptoErrorException(\"openssl: fail to encrypt AEAD\");\r\n            clen += (uint) tmpLen;\r\n            // For AEAD cipher, it should not output anything\r\n            ret = OpenSSL.EVP_CipherFinal_ex(_encryptCtx, ciphertext, ref tmpLen);\r\n            if (ret != 1) throw new CryptoErrorException(\"openssl: fail to finalize AEAD\");\r\n            if (tmpLen > 0)\r\n            {\r\n                throw new System.Exception(\"openssl: fail to finish AEAD\");\r\n            }\r\n\r\n            OpenSSL.AEADGetTag(_encryptCtx, tagBuf, tagLen);\r\n            Array.Copy(tagBuf, 0, ciphertext, clen, tagLen);\r\n            clen += (uint) tagLen;\r\n        }\r\n\r\n        public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)\r\n        {\r\n            OpenSSL.SetCtxNonce(_decryptCtx, _decNonce, false);\r\n            // buf: ciphertext + tag\r\n            // outbuf: plaintext\r\n            int ret;\r\n            int tmpLen = 0;\r\n            plen = 0;\r","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/shadowsocks/shadowsocks-windows/blob/891d971682eefcaa2e640258d3b352a3ad3b2233/shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs#L83-L119","documentation":"Thrown as CryptoErrorException when EVP_CipherFinal_ex returns non-1 during AEAD encryption. CipherFinal_ex flushes the cipher pipeline and, for GCM, finalises tag material. Because AEAD ciphers stream all ciphertext through CipherUpdate with padding disabled, Final succeeding is the expected steady state; failure after a successful Update signals an internally inconsistent or corrupted cipher context.","triggerScenarios":"The EVP context is corrupted by a memory overwrite or use-after-free between Update and Final. The padding/IV-length ctrl calls in InitCipher were skipped, reordered, or returned non-1. The cipher object behind _cipherInfoPtr is not actually an AEAD type despite the _ciphers entry. A FIPS/self-test abort or native libcrypto fault on the running context.","commonSituations":"Method strings differ between client and server (one side aes-256-gcm against a peer built on a mismatched lib). Corrupted key-derivation output from a malformed salt. Partial upgrade of the OpenSSL DLL leaving libcrypto internally inconsistent. Heap corruption from another thread stomping the context.","solutions":["Confirm the method string on both peers is one of the supported AEAD ciphers (aes-128-gcm, aes-192-gcm, aes-256-gcm, chacha20-ietf-poly1305) and matches exactly.","Re-derive the session subkey from a fresh salt and re-run InitCipher on a new encryptor instance.","Audit InitCipher to confirm every EVP_CipherInit_ex / EVP_CIPHER_CTX_ctrl / set_key_length return code is checked, not swallowed.","Verify native libcrypto integrity (reinstall or pin the OpenSSL build)."],"exampleFix":"// before\nenc.cipherEncrypt(plain, (uint)plain.Length, cipher, ref clen);\n\n// after — recreate the context once on a finalize failure\ntry {\n    enc.cipherEncrypt(plain, (uint)plain.Length, cipher, ref clen);\n} catch (CryptoErrorException ex) when (ex.Message.Contains(\"finalize\")) {\n    enc.Dispose();\n    enc = new AEADOpenSSLEncryptor(method, password);\n    enc.InitCipher(salt, true, isUdp);\n    enc.cipherEncrypt(plain, (uint)plain.Length, cipher, ref clen);\n}","handlingStrategy":"try-catch","validationCode":"// nothing to validate at the call site; verify the init steps succeeded upstream\nif (_cipherInfoPtr == IntPtr.Zero || _encryptCtx == IntPtr.Zero)\n    throw new InvalidOperationException(\"AEAD context not initialised\");","typeGuard":null,"tryCatchPattern":"try {\n    enc.cipherEncrypt(plain, (uint)plain.Length, cipher, ref clen);\n} catch (CryptoErrorException ex) when (ex.Message.Contains(\"finalize\")) {\n    // re-key with a fresh salt once on a new encryptor\n    enc.Dispose();\n    enc = new AEADOpenSSLEncryptor(method, password);\n    enc.InitCipher(salt, true, isUdp);\n    enc.cipherEncrypt(plain, (uint)plain.Length, cipher, ref clen);\n}","preventionTips":["Match method strings between peers exactly.","Derive the session subkey from a fresh salt each session.","Verify every EVP_*Ctrl return code in InitCipher is checked.","Pin the OpenSSL native version at build time."],"tags":["openssl","crypto","aead","encryption","native-interop"],"backgroundTag":null,"analyzedSha":"891d971682eefcaa2e640258d3b352a3ad3b2233","analyzedAt":"2026-08-13T10:12:34.434Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}