前端用 RSA 加密时公钥格式不对怎么办?
我在前端用 jsencrypt 做 RSA 加密,后端给的公钥是 PEM 格式的,但直接传进去加密失败了。
试过把公钥头尾的 -----BEGIN PUBLIC KEY----- 和 -----END PUBLIC KEY----- 去掉,还是不行,控制台报错说“Invalid PEM formatted message”。
后端说是标准的 PKCS#8 公钥,我该怎么处理才能让 jsencrypt 正确识别?
const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey); // 这里 publicKey 是后端给的完整 PEM 字符串
const encrypted = encrypt.encrypt('test');
jsencrypt 实际上是可以直接接收带头尾的完整 PEM 字符串的,不需要手动去掉。你去掉头尾之后反而可能出问题,因为它内部解析时需要判断公钥类型。
报错 "Invalid PEM formatted message" 通常是这几个原因:
第一,公钥本身是无效的。你先确认下后端给的公钥是不是真的可用,可以用 openssl 验证:
如果这里都报错,那说明公钥本身就有问题,找后端重新生成。
第二,可能是编码或隐藏字符的问题。有些后端传过来的字符串里带了 BOM 头或者多余的空格。处理一下:
第三,如果后端确实给的 PKCS#8 格式的公钥,jsencrypt 应该是支持的。但有些后端实现不太规范,可能生成的是 PKCS#1 格式(开头是 -----BEGIN RSA PUBLIC KEY-----),这两种格式不一样。
你可以打印一下后端给的公钥看看具体长什么样:
如果是 PKCS#1 格式(头是 BEGIN RSA PUBLIC KEY),jsencrypt 不直接支持,需要转换:
最后还有个坑,有些后端返回的公钥是 URL 编码过的,或者 JSON 序列化时被转义了,确保你拿到的是原始字符串而不是转义后的。
你先跑一下 openssl 验证命令,确认公钥本身没问题,这是第一步。
-----BEGIN PUBLIC KEY-----开头,而不是-----BEGIN RSA PUBLIC KEY-----。推荐的做法是确保公钥字符串完整包含头尾标记,并且换行符要正确。可以这样处理:
如果还是报错,可能是换行符问题。试试用
n明确指定换行:const publicKey = "-----BEGIN PUBLIC KEY-----nMIIBIj...n-----END PUBLIC KEY-----"实在不行就检查下公钥内容是否完整,有时后端传过来的公钥可能被截断。我之前就遇到过因为一个空格导致的加密失败,排查了半天想打人...
另外jsencrypt的文档里明确说了需要完整的PEM格式,包括头尾标记。所以千万别手贱去掉那些标记,它们其实很重要。