{"record":{"id":"87db5ec80a0f5ac5","repo":"w7corp/easywechat","slug":"encrypt-failed","errorCode":null,"errorMessage":"Encrypt failed","messagePattern":"Encrypt failed","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Kernel/Support/AesGcm.php","lineNumber":37,"sourceCode":"\n    /**\n     * @throws InvalidArgumentException\n     */\n    public static function encrypt(string $plaintext, string $key, ?string $iv = null, string $aad = ''): string\n    {\n        $ciphertext = openssl_encrypt(\n            $plaintext,\n            'aes-256-gcm',\n            $key,\n            OPENSSL_RAW_DATA,\n            (string) $iv,\n            $tag,\n            $aad,\n            self::BLOCK_SIZE\n        );\n\n        if ($ciphertext === false) {\n            throw new InvalidArgumentException(openssl_error_string() ?: 'Encrypt failed');\n        }\n\n        return base64_encode($ciphertext.$tag);\n    }\n\n    /**\n     * @throws InvalidArgumentException\n     */\n    public static function decrypt(string $ciphertext, string $key, ?string $iv = null, string $aad = ''): string\n    {\n        $ciphertext = base64_decode($ciphertext);\n\n        $tag = substr($ciphertext, -self::BLOCK_SIZE);\n\n        $ciphertext = substr($ciphertext, 0, -self::BLOCK_SIZE);\n\n        $plaintext = openssl_decrypt($ciphertext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, (string) $iv, $tag, $aad);\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Kernel/Support/AesGcm.php#L19-L55","documentation":"Thrown when openssl_encrypt() returns false for aes-256-gcm. AesGcm::encrypt is the SDK's GCM helper (no internal caller; WeChat Pay v3-style encryption): it uses OPENSSL_RAW_DATA, a 16-byte tag, and returns base64(ciphertext.tag). OpenSSL fails when the key is not exactly 32 bytes, when the IV is empty — (string) null === '' and GCM requires a non-empty nonce — or on unsupported tag lengths, so the dominant cause in this code is a null/empty $iv or a key of the wrong length.","triggerScenarios":"Calling AesGcm::encrypt($plain, $key, iv: null) or iv: '' with aes-256-gcm (empty nonce makes openssl_encrypt return false); passing a key whose strlen() is not 32 (e.g. a 43-char EncodingAESKey used verbatim, or an APIv3 key with a trailing newline); calling with a key byte length of 16/24 copied from aes-128 code.","commonSituations":"The 32-char APIv3 key loaded from an env var that got quoted or whitespace-padded; reusing the WeChat EncodingAESKey without base64-decoding it; hand-rolled nonce generation that can return an empty string.","solutions":["Pass a non-empty nonce, normally 12 random bytes: AesGcm::encrypt($plain, $key, random_bytes(12), $aad).","Check strlen($key) === 32 — aes-256-gcm accepts exactly 32 bytes.","trim() keys and nonces loaded from config/env files.","Confirm GCM support: php -r 'var_dump(in_array(\"aes-256-gcm\", openssl_get_cipher_methods()));'."],"exampleFix":"// before: null iv -> (string) null === '' -> openssl_encrypt returns false\n$ct = AesGcm::encrypt($plain, $key, iv: null, aad: 'transaction');\n// after: explicit 12-byte nonce with a 32-byte key\n$ct = AesGcm::encrypt($plain, $key, random_bytes(12), 'transaction');","handlingStrategy":"validation","validationCode":"if (strlen($key) !== 32) { throw new InvalidArgumentException('key must be 32 bytes for aes-256-gcm'); }\n$nonce = $nonce ?? random_bytes(12);\nif ($nonce === '') { throw new InvalidArgumentException('GCM nonce must not be empty'); }\n$cipher = AesGcm::encrypt($plain, $key, $nonce, $aad);","typeGuard":null,"tryCatchPattern":"try { $cipher = AesGcm::encrypt($plain, $key, $nonce, $aad); } catch (\\EasyWeChat\\Kernel\\Exceptions\\InvalidArgumentException $e) { // openssl_error_string() output is in the message throw new RuntimeException('Failed to encrypt payload: '.$e->getMessage(), 0, $e); }","preventionTips":["Centralize nonce generation with random_bytes(12)","Assert strlen($key) === 32 once at bootstrap","Never reuse a nonce with the same key"],"tags":["php","openssl","aes-gcm","encryption","wechat-pay-v3"],"backgroundTag":"aes-gcm-encryption-failed","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}