w7corp/easywechat · error · EncryptionFailureException

Encrypt failed.

Error message

Encrypt failed.

What it means

Thrown by Pay/Utils::encryptWithRsaPublicKey() when openssl_public_encrypt() returns false for the resolved platform key. The key object existed, but OpenSSL rejected the operation: the loaded PEM is not a usable public key, the plaintext exceeds the RSA-OAEP payload limit (~214 bytes for 2048-bit, ~446 for 3072), or the key/cert material is corrupt.

Source

Thrown at src/Pay/Utils.php:168

     * @param  string|null  $serial  The serial number of the platform certificate to use for encryption. If null, the first available certificate will be used.
     * @return string The base64-encoded encrypted text.
     *
     * @throws InvalidConfigException If no platform certificate is found.
     * @throws EncryptionFailureException If the encryption process fails.
     */
    public function encryptWithRsaPublicKey(string $plaintext, ?string $serial = null): string
    {
        $platformCerts = $this->merchant->getPlatformCerts();
        /** @var string $identifier - One of the serial number of the platform certificates OR the weixin pay's public key identifier. */
        $identifier = $serial ?? array_key_first($platformCerts);
        $platformCert = $this->merchant->getPlatformCert($identifier);

        if (empty($platformCert)) {
            throw new InvalidConfigException('Missing platform certificate.');
        }

        if (! openssl_public_encrypt($plaintext, $encrypted, $platformCert, OPENSSL_PKCS1_OAEP_PADDING)) {
            throw new EncryptionFailureException('Encrypt failed.');
        }

        return base64_encode($encrypted);
    }

    /**
     * @throws InvalidConfigException
     */
    public function createV2Signature(array $params): string
    {
        $secretKey = $this->merchant->getV2SecretKey();

        if (empty($secretKey)) {
            throw new InvalidConfigException('Missing v2 secret key.');
        }

        ksort($params);

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Verify the loaded PEM is WeChat Pay's PLATFORM public key/cert (subject = WeChat Pay), not your merchant cert or private key
  2. Check the plaintext length against the key size: for 2048-bit RSA-OAEP keep it under ~214 bytes; encrypt field-by-field, never a JSON blob
  3. Re-download the cert file and confirm it starts with '-----BEGIN CERTIFICATE-----' (or PUBLIC KEY) and is not truncated; validate with openssl_x509_checkpurpose/openssl_pkey_get_public

Example fix

// before
$platformCerts = [ file_get_contents('/certs/apiclient_cert.pem') ]; // merchant's own cert
// after
$platformCerts = [ file_get_contents('/certs/wechatpay-platform-cert.pem') ];
// and encrypt only the short field:
$enc = $utils->encryptWithRsaPublicKey($bankCard['account_no']);
Defensive patterns

Strategy: validation

Validate before calling

$pub = openssl_pkey_get_public($pem);
if ($pub === false) {
    throw new \RuntimeException('platform PEM is not a valid public key/cert');
}
$details = openssl_pkey_get_details($pub);
$maxLen = $details['bits'] / 8 - 42; // OAEP overhead
if (strlen($plaintext) > $maxLen) {
    throw new \InvalidArgumentException('plaintext too long for RSA-OAEP: encrypt fields separately');
}

Type guard

function isUsableRsaPublicKey(string $pem): bool
{
    return openssl_pkey_get_public($pem) !== false;
}

Try / catch

try {
    $enc = $app->utils->encryptWithRsaPublicKey($field);
} catch (\EasyWeChat\Kernel\Exceptions\EncryptionFailureException $e) {
    // check: wrong PEM (merchant cert instead of platform key) or payload over OAEP limit
    throw new \RuntimeException('RSA encrypt failed - verify platform cert and payload size', 0, $e);
}

Prevention

When it happens

Trigger: Encrypting sensitive fields where platformCerts contains a certificate/private key/wrong PEM (normalize only wraps strings into PublicKey, it doesn't verify they're valid public keys), or passing a long buffer (e.g. a concatenated address or JSON blob) beyond the OAEP limit for the key size.

Common situations: Loading the merchant's own certificate instead of WeChat's platform cert/public key; loading a private key PEM; truncated cert file (partial download); encrypting a whole JSON structure instead of a single short field like a name or card number.

Related errors


AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21). Data as JSON: /api/errors/da97659266517c49. Report an issue: GitHub.