可行但需严格匹配密钥格式、填充方式和长度限制:公钥须以-----begin public key-----开头,2048位密钥明文上限245字节,跨语言需统一pkcs#1填充,推荐rsa+aes混合加密。

PHP中用openssl_public_encrypt和openssl_private_decrypt完成公钥加密、私钥解密是可行的,但必须严格匹配密钥格式、填充方式和数据长度限制,否则必然失败。
密钥加载失败:openssl_pkey_get_public 返回 false
常见错误现象是调用 openssl_pkey_get_public($pubKey) 得到 false,后续加密直接报错“key param is not a valid public key”。根本原因是公钥内容不合规——比如少了首尾标记、被意外截断、混入空格或换行符、用了 PKCS#1 原始私钥格式去当公钥用。
- 确认公钥字符串以
-----BEGIN PUBLIC KEY-----开头、-----END PUBLIC KEY-----结尾,且中间 Base64 内容每行不超过 64 字符(可用chunk_split($key, 64, "\n")修复) - 不要把
-----BEGIN RSA PRIVATE KEY-----格式的私钥文件内容误传给公钥函数 - 若从文件读取,用
file_get_contents()后别做 trim() 或 str_replace(),除非明确知道哪些字符要清理 - Linux 下用
openssl rsa -in private.pem -pubout -out pub.pem生成的才是标准公钥;用openssl x509 -pubkey -noout -in cert.crt提取的也合法,但不能混用
加密失败:明文超长或填充方式不匹配
openssl_public_encrypt 对输入长度极其敏感。例如 2048 位密钥 + OPENSSL_PKCS1_PADDING(默认),最多只能加密 245 字节明文;超过就静默失败或返回 false,不会报具体原因。
- 实际可用长度 = (密钥位数 ÷ 8) − 11,2048 位对应 245 字节,4096 位对应 501 字节
- 如果原始数据是 JSON 字符串,先
json_encode()再检查strlen($data),别只看 PHP 数组大小 - 避免在加密前做 URL 编码、HTML 实体转义等额外处理,这些会无谓增加字节数
- 跨语言对接时(如 PHP ↔ Java/Go),务必统一 padding:PHP 默认是
OPENSSL_PKCS1_PADDING,Java 的RSA/ECB/PKCS1Padding才兼容;若对方用 OAEP,PHP 必须显式传OPENSSL_PKCS1_OAEP_PADDING
解密失败:base64 编码/解码不一致或私钥格式错误
典型错误是加密后做了 base64_encode(),但解密时忘了 base64_decode(),或者解码后传了空字符串给 openssl_private_decrypt,结果返回 false 且无提示。
- 私钥必须是 PEM 格式且含完整头部尾部,
-----BEGIN PRIVATE KEY-----(PKCS#8)或-----BEGIN RSA PRIVATE KEY-----(PKCS#1)都可,但不能是 DER 二进制 - 私钥若带密码保护(encrypted PEM),
openssl_pkey_get_private($pem, $passphrase)第二个参数必须传对,否则返回false - 加密端用了
OPENSSL_PKCS1_OAEP_PADDING,解密端也必须显式指定相同常量,不能依赖默认值 - 传输密文时,确保 base64 字符串未被 URL 截断(如
+变成空格、/被转义)、未被数据库字段长度截断(建议用 TEXT 类型存)
分段加解密不是“自动”的,必须手动切块与拼接
RSA 本身不支持流式或分块接口,所谓“分段”是业务层自己拆分再逐段调用 openssl_public_encrypt,解密端再逐段 openssl_private_decrypt 后合并。这不是透明过程,出错点极多。
- 单次加密上限按公式算清楚,比如 2048 位密钥下,安全起见每次只加密 ≤200 字节,留足余量
- 分块时不能简单用
str_split($data, 200),要按 UTF-8 字符边界切,否则中文可能被截断成乱码;推荐先mb_convert_encoding($data, 'UTF-8')再处理 - 每段密文需独立 base64 编码,并用唯一分隔符(如
\x00\x01)拼接,解密端再按同样规则拆开,否则无法还原原始顺序 - 更优方案是用 RSA 加密一个随机 AES 密钥,再用 AES 加密大数据——这既绕过长度限制,又保持性能,金融系统普遍这么干
最容易被忽略的是 padding 一致性与密钥格式细节:同一套密钥在不同环境生成时,PEM 头尾、换行符、空格位置稍有差异就会导致加载失败;而 padding 类型一旦错配,加密看似成功,解密却永远返回 false,且无有效错误信息。动手前先用已知正确的密钥对跑通最小闭环,比反复调试更有价值。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











