エラーメッセージ
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
16 進数の値は問題の文字を示します。`2d` は「-」、`5f` は「_」、`a` は LF、`d` は CR、`20` はスペースです。
Java (JDK) — java.util.Base64.Decoder.decode
このエラーの意味
`Base64.getDecoder()` は RFC 4648 に厳密に従うデコーダーで、`A–Z a–z 0–9 + /` と `=` によるパディングだけを受け付け、それ以外の文字が現れた時点で停止します。16 進数はその文字のコードです。`2d` は `-`(`-----BEGIN …-----` のダッシュ、または base64url のアルファベット)、`a` はラインフィード、`d` はキャリッジリターン、`20` はスペース、`5f` はアンダースコアです。通常、データ自体には問題がありません。デコーダーが想定しているのとは異なるテキスト形式で包まれているだけです。
発生する理由
PEM のヘッダーとフッターが取り除かれていない(2d)
よくあるPEM ファイル全体をデコードすると、`-----BEGIN` の最初の `-` でエラーになります。base64 なのは、アーマー行に挟まれた本文だけです。
本文内の改行(a または d)
よくあるPEM は base64 を 64 文字ごとに折り返します。基本のデコーダーは改行を拒否します。Windows で編集したファイルには、さらに `\r` も加わります。
base64url のデータを基本のデコーダーに渡している(2d または 5f)
よくあるJWT のセグメントと JWK の座標は、`+` と `/` の代わりに `-` と `_` を使います。これらには `Base64.getUrlDecoder()` が必要です。
設定から紛れ込んだスペースや引用符(20、22)
ときどきYAML、プロパティファイル、環境変数に貼り付けた鍵には、スペース、引用符、エスケープされた `\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"));