Java (JDK)Java
错误信息
java.lang.IllegalArgumentException: Illegal base64 character 2d
也可能输出为
- java.lang.IllegalArgumentException: Illegal base64 character a
- java.lang.IllegalArgumentException: Illegal base64 character d
- java.lang.IllegalArgumentException: Illegal base64 character 5f
- java.lang.IllegalArgumentException: Illegal base64 character 20
这个十六进制值指出了出问题的字符:`2d` 是“-”,`5f` 是“_”,`a` 是 LF,`d` 是 CR,`20` 是空格。
Java (JDK) — java.util.Base64.Decoder.decode
含义
`Base64.getDecoder()` 是严格的 RFC 4648 解码器:它只接受 `A–Z a–z 0–9 + /` 和 `=` 填充,遇到第一个其他字符就停止。那个十六进制数就是该字符的编码:`2d` 是 `-`(`-----BEGIN …-----` 中的短横线,或 base64url 字母表中的字符),`a` 是换行符,`d` 是回车符,`20` 是空格,`5f` 是下划线。数据本身通常没有问题——只是它的文本包装方式与这个解码器要求的不一样。
原因
PEM 头尾行没有去掉(2d)
常见对整个 PEM 文件解码,会碰到 `-----BEGIN` 中的第一个 `-`。只有头尾封装行之间的正文才是 base64。
正文中有换行符(a 或 d)
常见PEM 每 64 个字符对 base64 换一次行。基本解码器会拒绝换行符;在 Windows 上编辑过的文件还会多出 `\r`。
把 base64url 数据交给了基本解码器(2d 或 5f)
常见JWT 的各段和 JWK 坐标使用 `-` 和 `_`,而不是 `+` 和 `/`。它们需要用 `Base64.getUrlDecoder()` 解码。
配置中带入的空格或引号(20、22)
偶见粘贴到 YAML、properties 文件或环境变量中的密钥,可能会混入空格、引号或转义的 `\n` 序列。
修复方法
- 1.
去掉封装行,并使用 MIME 解码器
`Base64.getMimeDecoder()` 会跳过行分隔符,这正是 PEM 正文所需要的。
java String body = pem.replaceAll("-----(BEGIN|END) [A-Z ]+-----", ""); byte[] der = Base64.getMimeDecoder().decode(body); // ignores line separators and other non-alphabet characters - 2.
JOSE 数据使用 URL 解码器
JWT 和 JWK 中的所有内容都是 base64url;URL 解码器也接受省略了填充的数据。
java // JWT segments and JWK fields ("x", "y", "n", "e") use base64url without padding. byte[] header = Base64.getUrlDecoder().decode(jwt.split("\\.")[0]); byte[] x = Base64.getUrlDecoder().decode(jwk.get("x"));