{"record":{"id":"6344e381faf896df","repo":"shadowsocks/shadowsocks-windows","slug":"openssl-fail-to-finish-aead","errorCode":null,"errorMessage":"openssl: fail to finish AEAD","messagePattern":"openssl: fail to finish AEAD","errorType":"exception","errorClass":"System.Exception","httpStatus":null,"severity":"error","filePath":"shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs","lineNumber":104,"sourceCode":"        {\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\n\r\n            // split tag\r\n            byte[] tagbuf = new byte[tagLen];\r","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/shadowsocks/shadowsocks-windows/blob/891d971682eefcaa2e640258d3b352a3ad3b2233/shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs#L86-L122","documentation":"Thrown as a plain System.Exception when EVP_CipherFinal_ex writes more than 0 bytes during AEAD encryption. For AEAD stream ciphers (AES-GCM, ChaCha20-Poly1305) with padding disabled, all ciphertext is emitted by CipherUpdate and Final must produce zero bytes. A positive tmpLen means the cipher is behaving like a padded block cipher, i.e. it is not configured as a true AEAD stream.","triggerScenarios":"InitCipher's EVP_CIPHER_CTX_set_padding(ctx, 0) call was skipped or returned non-1. The selected method resolved to a non-AEAD cipher object. The same context was reused after a method switch without re-init. An OpenSSL build whose GCM final incorrectly emits trailing data (rare bug).","commonSituations":"A typo in the method name causes fallback to a non-AEAD/block cipher. A modified InitCipher drops the set-padding call. The _ciphers dictionary is extended with a non-AEAD entry that shares this code path.","solutions":["Verify EVP_CIPHER_CTX_set_padding(_encryptCtx, 0) is executed in InitCipher after the key is set and returns 1.","Confirm the cipher is one of the AEAD types and that _cipherInfoPtr points to a GCM or ChaCha20-Poly1305 cipher (OpenSSL.GetCipherInfo must not return Zero).","Ensure a context is never reused after switching methods; always build a fresh encryptor."],"exampleFix":"// before — padding never disabled\nret = OpenSSL.EVP_CipherInit_ex(ctx, _cipherInfoPtr, IntPtr.Zero, key, null, enc);\n\n// after — explicitly disable padding after init and check the return code\nret = OpenSSL.EVP_CipherInit_ex(ctx, _cipherInfoPtr, IntPtr.Zero, key, null, enc);\nif (ret != 1) throw new Exception(\"openssl: fail to init ctx\");\nint pad = OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);\nif (pad != 1) throw new Exception(\"openssl: fail to disable padding\");","handlingStrategy":"validation","validationCode":"// confirm padding is disabled — an AEAD cipher must stream with zero final output\nint pad = OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);\nif (pad != 1) throw new InvalidOperationException(\"cannot disable padding for AEAD\");","typeGuard":null,"tryCatchPattern":"try { enc.cipherEncrypt(plain, (uint)plain.Length, cipher, ref clen); }\ncatch (Exception ex) when (ex.Message.Contains(\"finish AEAD\")) {\n    // cipher is not behaving as an AEAD stream — this is a config/setup bug\n    logger.Error(\"cipher not behaving as AEAD stream; check padding and method\");\n    throw;\n}","preventionTips":["Ensure EVP_CIPHER_CTX_set_padding(ctx, 0) runs after key init.","Register only true AEAD ciphers in the _ciphers dictionary.","Never reuse a context after switching methods."],"tags":["openssl","crypto","aead","sanity-check","encryption"],"backgroundTag":null,"analyzedSha":"891d971682eefcaa2e640258d3b352a3ad3b2233","analyzedAt":"2026-08-13T10:12:34.434Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}