Skip to main content

JEP 538:密码学对象的 PEM 编码(第三次预览)

引言

有些格式如此普及,以至于我们几乎忘了它需要"被支持"。PEM 就是这样一种格式——每一个用过证书、SSH 或 HTTPS 的开发者都见过它,可 Java 的标准库偏偏一直没有正式支持读写它。于是无数项目各自造轮子。JEP 538 终于把这块拼图补进了标准库。

PEM:大家其实都在用的格式

如果你用过 HTTPS、SSH,或者任何一种证书,那你早就接触过 PEM 了——就是那些以 -----BEGIN----------END----- 包裹起来的文本块。

  • 它的结构很简单:Base64 编码的内容,外面包一层 BEGIN/END 标记。
  • 它是密钥、证书和 CRL(证书吊销列表)落到磁盘上的默认格式。
  • 几乎所有安全工具都认它:OpenSSL、Kubernetes 的 Secret、各家云厂商的密钥服务……PEM 是这个生态里事实上的通用语。
  • 可讽刺的是,**JDK 一直没有一个官方支持的、用来读写 PEM 的 API。**一个如此普遍的格式,Java 标准库却始终把它当作"别人的事"。

没有它的时候大家怎么做

没有标准 API,结果就是每个项目都在重新发明轮子——而且发明得还未必对。

典型的手工做法是:

  • 手工去掉首尾的 BEGIN/END 行,再对中间的内容做 Base64 解码。
  • 靠猜来判断解出来的 DER 数据到底是什么——是 PKCS#8 私钥?X.509 证书?还是别的什么?
  • 或者干脆仅仅为了解析几行文本,就引入 Bouncy Castle 这样的重量级第三方库。
  • 而这些临时拼凑的代码,特别容易出那种微妙、且不抛异常的错误——它跑起来不报错,但行为悄悄错了,等你发现时可能已经酿成了安全问题。

这些散落在无数代码库里的临时代码,既是重复劳动,也是隐患的温床。

这个 JEP 提供了什么

JEP 538 在标准库里提供了一对干净的 API:PEMEncoder(负责写)和 PEMDecoder(负责读)。

  • 标准库中内置 PEMEncoderPEMDecoder
  • **可以直接解码成公钥、私钥、证书、CRL,或者通用的 PEM 对象。**你告诉解码器你期望的类型,它就返回对应的 Java 对象。
  • **也能把实现了 BinaryEncodable 的对象,编码回 PEM 文本。**文本与对象之间可以干净地双向转换。
  • 加密的私钥也能处理——可以通过 PEMEncoder.of().withEncryption(password) 配置编码器。

整个过程是类型安全的、简洁的,而且完全不需要你了解 ASN.1 的内部细节。

代码示例

// Decode a PEM file to a PrivateKey
PEMDecoder decoder = PEMDecoder.of();
PrivateKey key = decoder.decode(
Files.readString(Path.of("key.pem")),
PrivateKey.class);

// Encode a certificate back to PEM
PEMEncoder encoder = PEMEncoder.of();
String pem = encoder.encodeToString(certificate);

读取一个 PEM 文件、拿到一个 PrivateKey 对象——**三行代码。**反过来,把一个证书编码回 PEM 字符串——**两行。**把它和前面那套"手工去行 + Base64 + 猜算法 + 引依赖"的老代码对比一下,差距一目了然。

前后对比

此前:

  • 手工做字符串处理,再加 Base64 解码。
  • 每种密钥算法都要选一次 KeyFactory,而且全靠猜——猜错了就出问题。
  • 为了一个 JDK 本就该理解的格式,额外引入一个第三方依赖。

此后:

  • 一次解码调用,就返回正确的对象。
  • 文本与对象之间可以干净地来回转换。
  • 信任边界(trust boundary)内不再需要第三方库。

这最后一点尤其值得强调:安全相关的第三方库,本身就是你信任边界里的一环。**少一个第三方依赖,就少一份供应链风险。**JEP 538 让你能用标准库完成这件事,把一个外部依赖从密码学的核心路径上移除了。

预览状态

这已经是第三次预览,说明 API 正在根据社区反馈持续打磨。

  • 它在 JDK 27 中作为第三次预览发布,是根据早期反馈改进而来的。
  • 使用时需要 --enable-preview 标志。
  • 它属于 JDK 安全 API 现代化的一部分——和其他一系列安全相关的改进一道,把 Java 的密码学开发体验,带到符合当代需求的水准。

结论

PEM 是几乎每一套部署都在用的格式,可 Java 开发者多年来一直在用各种临时方案来对付它——手工解析、算法靠猜、引入重型依赖。JEP 538 用一套标准库 API 补上了这个长期存在的缺口,取代了那些容易出错的手工代码和不必要的第三方依赖。一个大家早就在用的格式,终于在 Java 里得到了官方支持。