{"record":{"id":"2972f28aed48c035","repo":"w7corp/easywechat","slug":"40006","errorCode":"-40006","errorMessage":"$e->getMessage()","messagePattern":"\\$e->getMessage\\(\\)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Kernel/Encryptor.php","lineNumber":155,"sourceCode":"     */\n    public function encryptAsArray(string $plaintext, ?string $nonce = null, int|string|null $timestamp = null): array\n    {\n        try {\n            $plaintext = Pkcs7::padding(\n                random_bytes(self::BLOCK_SIZE).pack('N', strlen($plaintext)).$plaintext.$this->appId,\n                blockSize: strlen($this->aesKey)\n            );\n            $ciphertext = base64_encode(\n                openssl_encrypt(\n                    $plaintext,\n                    'aes-256-cbc',\n                    $this->aesKey,\n                    OPENSSL_NO_PADDING,\n                    iv: substr($this->aesKey, 0, self::BLOCK_SIZE)\n                ) ?: ''\n            );\n        } catch (Throwable $e) {\n            throw new RuntimeException($e->getMessage(), self::ERROR_ENCRYPT_AES);\n        }\n\n        $nonce ??= Str::random();\n        $timestamp ??= time();\n\n        return [\n            'ciphertext' => $ciphertext,\n            'signature' => $this->createSignature($this->token, $timestamp, $nonce, $ciphertext),\n            'timestamp' => $timestamp,\n            'nonce' => $nonce,\n        ];\n    }\n\n    public function createSignature(string|int ...$attributes): string\n    {\n        $attributes = array_map(\n            static fn (string|int $attribute): string => (string) $attribute,\n            $attributes","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Kernel/Encryptor.php#L137-L173","documentation":"Encryptor::encryptAsArray() wraps the PKCS7 padding + AES-256-CBC encryption block in a try/catch and rethrows any Throwable as RuntimeException(code -40006 ERROR_ENCRYPT_AES). The constructor decodes the key via base64_decode($aesKey.'='), so a wrong-length EncodingAESKey produces an aesKey whose strlen is not 32 — Pkcs7::padding then throws ('$blockSize may not be more than 32 bytes' when strlen > 32) or PHP throws DivisionByZeroError ('Modulo by zero') when the key decoded to an empty string.","triggerScenarios":"Configuring Encryptor/app with an aes_key that is not the 43-char base64 EncodingAESKey: an empty string, a wrong-length string, an already-base64-decoded binary key, or one with trailing whitespace/typo — so strlen($this->aesKey) != 32 and padding fails before openssl_encrypt runs.","commonSituations":"Copy-paste errors in EncodingAESKey from the WeChat admin console, confusing the plain token with aes_key, reusing an OfficialAccount key for a Work app (or vice versa), passing the 44-char padded base64 instead of the 43-char key.","solutions":["Inspect the exception message: 'Modulo by zero' means aes_key decoded to an empty string; '$blockSize may not be more than 32 bytes' means it decoded to >32 bytes — both point at a malformed EncodingAESKey","Verify aes_key is the exact 43-character EncodingAESKey shown in the WeChat/WeCom admin (decodes with the appended '=' to exactly 32 bytes)","Double-check you did not include quotes, spaces or newlines when copying the key into config/env"],"exampleFix":"// before\n$encryptor = new Encryptor($appId, $token, 'wrong-or-empty-key');\n$encryptor->encrypt('hello'); // RuntimeException -40006\n\n// after: use the exact 43-char EncodingAESKey\n$encodingAesKey = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG'; // 43 chars\n$encryptor = new Encryptor($appId, $token, $encodingAesKey);\n$encryptor->encrypt('hello');","handlingStrategy":"validation","validationCode":"// Validate the EncodingAESKey before constructing the Encryptor\nfunction isValidEncodingAesKey(string $key): bool\n{\n    return strlen($key) === 43 && strlen(base64_decode($key.'=', true)) === 32;\n}\n\nif (! isValidEncodingAesKey($config['aes_key'])) {\n    throw new InvalidArgumentException('aes_key must be the 43-char EncodingAESKey');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $encrypted = $encryptor->encryptAsArray($plaintext);\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\RuntimeException $e) {\n    if ($e->getCode() === \\EasyWeChat\\Kernel\\Encryptor::ERROR_ENCRYPT_AES) {\n        // message is 'Modulo by zero' (empty decoded key) or '$blockSize may not be more than 32 bytes' -> wrong aes_key\n        report_config_error('Invalid EncodingAESKey', $e->getMessage());\n    }\n    throw $e;\n}","preventionTips":["Add a boot-time assertion that base64_decode(aes_key.'=') is exactly 32 bytes","Copy keys from the admin console with trailing-whitespace trimming (trim() on load)"],"tags":["php","easywechat","encryption","aes","config","wechat-callback"],"backgroundTag":"invalid-aes-key","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}