前端用 RSA 加密时公钥格式不对怎么办?

夏侯金利 阅读 62

我在前端用 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');
我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
利伟
利伟 Lv1
这个问题我之前也遇到过,说下我的排查思路。

jsencrypt 实际上是可以直接接收带头尾的完整 PEM 字符串的,不需要手动去掉。你去掉头尾之后反而可能出问题,因为它内部解析时需要判断公钥类型。

报错 "Invalid PEM formatted message" 通常是这几个原因:

第一,公钥本身是无效的。你先确认下后端给的公钥是不是真的可用,可以用 openssl 验证:

# 查看公钥信息,如果有效会显示 RSA 密钥详情
openssl rsa -in public_key.pem -pubin -text -noout

# 或者直接检查格式
openssl rsa -pubin -in public_key.pem -RSAPublicKey_out -noout


如果这里都报错,那说明公钥本身就有问题,找后端重新生成。

第二,可能是编码或隐藏字符的问题。有些后端传过来的字符串里带了 BOM 头或者多余的空格。处理一下:

// 清理公钥字符串
let publicKey = 后端给的公钥字符串;

// 去掉可能的 BOM 头
publicKey = publicKey.replace(/^uFEFF/, '');

// 去掉多余空白(但保留换行)
publicKey = publicKey.trim();

// 确保是标准 PEM 格式,如果没有头尾,加上
if (!publicKey.includes('-----BEGIN PUBLIC KEY-----')) {
// 假设后端给的是纯 base64 内容,需要手动组装 PEM
// 每64个字符加一个换行
const base64 = publicKey.replace(/s/g, '');
const lines = base64.match(/.{1,64}/g) || [];
publicKey = '-----BEGIN PUBLIC KEY-----n' + lines.join('n') + 'n-----END PUBLIC KEY-----';
}

const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
const encrypted = encrypt.encrypt('test');


第三,如果后端确实给的 PKCS#8 格式的公钥,jsencrypt 应该是支持的。但有些后端实现不太规范,可能生成的是 PKCS#1 格式(开头是 -----BEGIN RSA PUBLIC KEY-----),这两种格式不一样。

你可以打印一下后端给的公钥看看具体长什么样:

console.log('公钥头:', publicKey.substring(0, 30));
console.log('公钥尾:', publicKey.substring(publicKey.length - 30));


如果是 PKCS#1 格式(头是 BEGIN RSA PUBLIC KEY),jsencrypt 不直接支持,需要转换:

# 用 openssl 把 PKCS#1 转成 PKCS#8
openssl rsa -RSAPublicKey_in -in rsa_public_key.pem -pubin -out public_key.pem


最后还有个坑,有些后端返回的公钥是 URL 编码过的,或者 JSON 序列化时被转义了,确保你拿到的是原始字符串而不是转义后的。

你先跑一下 openssl 验证命令,确认公钥本身没问题,这是第一步。
点赞
2026-03-11 21:13
书生シ慧芳
遇到这种问题太常见了,jsencrypt确实对PEM格式有点挑剔。先确认下你的公钥格式,PKCS#8的公钥应该以-----BEGIN PUBLIC KEY-----开头,而不是-----BEGIN RSA PUBLIC KEY-----

推荐的做法是确保公钥字符串完整包含头尾标记,并且换行符要正确。可以这样处理:

const publicKey = -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...(你的公钥内容)
-----END PUBLIC KEY-----
;

const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);


如果还是报错,可能是换行符问题。试试用n明确指定换行:
const publicKey = "-----BEGIN PUBLIC KEY-----nMIIBIj...n-----END PUBLIC KEY-----"

实在不行就检查下公钥内容是否完整,有时后端传过来的公钥可能被截断。我之前就遇到过因为一个空格导致的加密失败,排查了半天想打人...

另外jsencrypt的文档里明确说了需要完整的PEM格式,包括头尾标记。所以千万别手贱去掉那些标记,它们其实很重要。
点赞
2026-03-05 14:01