{"record":{"id":"da97659266517c49","repo":"w7corp/easywechat","slug":"encrypt-failed-da9765","errorCode":null,"errorMessage":"Encrypt failed.","messagePattern":"Encrypt failed\\.","errorType":"exception","errorClass":"EncryptionFailureException","httpStatus":null,"severity":"error","filePath":"src/Pay/Utils.php","lineNumber":168,"sourceCode":"     * @param  string|null  $serial  The serial number of the platform certificate to use for encryption. If null, the first available certificate will be used.\n     * @return string The base64-encoded encrypted text.\n     *\n     * @throws InvalidConfigException If no platform certificate is found.\n     * @throws EncryptionFailureException If the encryption process fails.\n     */\n    public function encryptWithRsaPublicKey(string $plaintext, ?string $serial = null): string\n    {\n        $platformCerts = $this->merchant->getPlatformCerts();\n        /** @var string $identifier - One of the serial number of the platform certificates OR the weixin pay's public key identifier. */\n        $identifier = $serial ?? array_key_first($platformCerts);\n        $platformCert = $this->merchant->getPlatformCert($identifier);\n\n        if (empty($platformCert)) {\n            throw new InvalidConfigException('Missing platform certificate.');\n        }\n\n        if (! openssl_public_encrypt($plaintext, $encrypted, $platformCert, OPENSSL_PKCS1_OAEP_PADDING)) {\n            throw new EncryptionFailureException('Encrypt failed.');\n        }\n\n        return base64_encode($encrypted);\n    }\n\n    /**\n     * @throws InvalidConfigException\n     */\n    public function createV2Signature(array $params): string\n    {\n        $secretKey = $this->merchant->getV2SecretKey();\n\n        if (empty($secretKey)) {\n            throw new InvalidConfigException('Missing v2 secret key.');\n        }\n\n        ksort($params);\n","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Pay/Utils.php#L150-L186","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the loaded PEM is WeChat Pay's PLATFORM public key/cert (subject = WeChat Pay), not your merchant cert or private key","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","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"],"exampleFix":"// before\n$platformCerts = [ file_get_contents('/certs/apiclient_cert.pem') ]; // merchant's own cert\n// after\n$platformCerts = [ file_get_contents('/certs/wechatpay-platform-cert.pem') ];\n// and encrypt only the short field:\n$enc = $utils->encryptWithRsaPublicKey($bankCard['account_no']);","handlingStrategy":"validation","validationCode":"$pub = openssl_pkey_get_public($pem);\nif ($pub === false) {\n    throw new \\RuntimeException('platform PEM is not a valid public key/cert');\n}\n$details = openssl_pkey_get_details($pub);\n$maxLen = $details['bits'] / 8 - 42; // OAEP overhead\nif (strlen($plaintext) > $maxLen) {\n    throw new \\InvalidArgumentException('plaintext too long for RSA-OAEP: encrypt fields separately');\n}","typeGuard":"function isUsableRsaPublicKey(string $pem): bool\n{\n    return openssl_pkey_get_public($pem) !== false;\n}","tryCatchPattern":"try {\n    $enc = $app->utils->encryptWithRsaPublicKey($field);\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\EncryptionFailureException $e) {\n    // check: wrong PEM (merchant cert instead of platform key) or payload over OAEP limit\n    throw new \\RuntimeException('RSA encrypt failed - verify platform cert and payload size', 0, $e);\n}","preventionTips":["Validate each cert with openssl_pkey_get_public at load time","Encrypt one short field per call, never serialized structures","Keep cert files immutable and checksummed after download"],"tags":["wechat-pay","rsa-encryption","openssl","platform-certificate"],"backgroundTag":"rsa-encryption-failed","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}