w7corp/easywechat · error · InvalidArgumentException
Encrypt AES ECB failed.
Error message
Encrypt AES ECB failed.
What it means
Support\AesEcb::encrypt() uses the fixed 'aes-256-ecb' cipher with OPENSSL_RAW_DATA; a false return (surfaced via openssl_error_string(), fallback 'Encrypt AES ECB failed.') throws InvalidArgumentException. AES-256 needs exactly a 32-byte key; in the Pay v2 flow the sibling decrypt uses md5($apiKeyV2) as the key precisely because md5 yields 32 bytes.
Source
Thrown at src/Kernel/Support/AesEcb.php:24
use EasyWeChat\Kernel\Contracts\Aes;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use function base64_decode;
use function openssl_decrypt;
use function openssl_error_string;
class AesEcb implements Aes
{
/**
* @throws InvalidArgumentException
*/
public static function encrypt(string $plaintext, string $key, ?string $iv = null): string
{
$ciphertext = \openssl_encrypt($plaintext, 'aes-256-ecb', $key, OPENSSL_RAW_DATA, (string) $iv);
if ($ciphertext === false) {
throw new InvalidArgumentException(openssl_error_string() ?: 'Encrypt AES ECB failed.');
}
return \base64_encode($ciphertext);
}
/**
* @throws InvalidArgumentException
*/
public static function decrypt(string $ciphertext, string $key, ?string $iv = null): string
{
$plaintext = openssl_decrypt(
base64_decode($ciphertext, true) ?: '',
'aes-256-ecb',
$key,
OPENSSL_RAW_DATA,
(string) $iv
);
View on GitHub (pinned to f0cf0a8b83)
Solutions
- Pass a 32-byte key: for WeChat Pay v2 semantics use md5($apiKey), matching Pay\Server's usage
- Log openssl_error_string() on failure — it pinpoints the key-length problem
- Add a strlen($key) === 32 assertion before calling so mis-sized keys fail loudly at the call site
Example fix
// before $cipher = AesEcb::encrypt($xml, $apiV2Key); // arbitrary length -> fails // after $cipher = AesEcb::encrypt($xml, md5($apiV2Key)); // 32-byte key, matches Pay\Server decrypt
Defensive patterns
Strategy: validation
Validate before calling
// Assert the 32-byte key requirement before encrypting (aes-256-ecb)
if (strlen($key) !== 32) {
throw new InvalidArgumentException('AesEcb key must be 32 bytes (use md5($apiV2Key) for WeChat Pay v2), got '.strlen($key));
}
$ciphertext = AesEcb::encrypt($plaintext, $key); Type guard
function isRawAes256Key(string $key): bool
{
return strlen($key) === 32;
} Try / catch
try {
$ciphertext = AesEcb::encrypt($xml, $key);
} catch (\EasyWeChat\Kernel\Exceptions\InvalidArgumentException $e) {
if (strlen($key) !== 32) {
$ciphertext = AesEcb::encrypt($xml, md5($key)); // v2 pay semantics
} else {
throw $e;
}
} Prevention
- Derive the v2 Pay key once (md5) at config load and reuse the 32-byte value everywhere
- Assert key length at the call site so mis-sized keys fail with a clear message
When it happens
Trigger: Calling AesEcb::encrypt() with a key that is not 32 bytes — e.g. the raw WeChat Pay v2 API key (arbitrary length) instead of md5($key), or an undecoded base64 key.
Common situations: Copy-pasting decrypt code into an encrypt path without the md5() transform, key-length assumptions carried over from AES-128 helpers, silent key truncation in config.
Related errors
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/474181bd7aa53fee.
Report an issue: GitHub.