開発者ツール · Base64 エンコーダーおよびデコーダー
RFC 4648 の説明: Base64、base32、base16 を定義する標準
· 背景
base64 エンコード
RFC 4648 は、あらゆる Base64 実装の背後にある短くて読みやすい文書です。この投稿では、何を指定するのか、何を意図的に未公開のままにするのか、そして実装が依然として異なる理由について説明します。
2 つのライブラリ、同じ文字列に対する 2 つの答え — 標準のみが解決する真の相互運用性パズル
2 つの JavaScript ライブラリは、同じ文字列に対して異なる Base64 を返し、それぞれが正確であると主張します。 RFC 4648 は、このような意見の相違を解決するための読みやすい 12 ページの文書ですが、RFC は意図的に特定の決定をアプリケーションに委ねているため、実装は依然として異なります。この記事では、RFC 4648 が何を指定しているのか、意図的に呼び出し元に何を委任しているのか、そしてなぜこの規格を一度読むと実際の相互運用性の謎がほとんど解決するのかについて説明します。 Base64 エンコーダおよびデコーダ ツールには RFC 4648 テスト ベクトルが含まれているため、信頼できるサンプルに対して実装を検証できます。
RFC 4648 は、以前のいくつかのドキュメントを置き換えて統合しました。MIME の Base64 (RFC 2045)、Privacy-Enhanced Mail (RFC 1421) の Base64、S/MIME (RFC 2630) の Base32、およびさまざまなソースの Base16 です。 MIME と PEM にはそれぞれ独自のアルファベットとルールがあり、MIME 行の折り返しが PEM の 64 列ブロックと競合するため、統合が必要でした。 RFC 4648 は、base64、base64url、base32、base32hex、base16 の 5 つのエンコード ファミリを 1 か所で定義しており、それぞれに独自のアルファベット、パディング ルール、テスト ベクトルの例が含まれています。 Base64 アルファベットは、A-Z、a-z、0-9、プラス、スラッシュの順です。
実装およびテスト ベクトルで確立されるもの - 標準および URL セーフのアルファベット、パディングおよび空白の処理
各文字は 6 ビットを表します。 3 つの入力バイト (24 ビット) は 4 つの出力文字にマップされます。アルファベットは任意ではありません。EBCDIC と ASCII の間で異なる文字を避け、C 文字列リテラルでエスケープする必要がある制御文字、引用符、バックスラッシュを避けます。 Base64url バリアントでは、URL とファイル名に予約文字が含まれないように、プラスをダッシュに、スラッシュをアンダースコアに置き換えます。どちらのバリアントも同様に有効です。 RFC 4648 セクション 2 は Base64 を指定し、セクション 5 は Base64url を指定します。アプリケーションはどちらを使用するかを指定する必要があります。
等号文字でパディングすると、出力は 4 文字の倍数になります。入力が 1 バイト (8 ビット) の場合、出力は 2 文字と 2 つの等号です。入力が 2 バイト (16 ビット) の場合、出力は 3 文字と 1 つの等号です。入力が 3 バイトの倍数である場合、パディングは必要ありません。アプリケーションによっては、パディングを省略したり、デコード時にパディングの欠落を許可したりすることがあります。 RFC 4648 セクション 3.2 では、正規エンコーディングを常にパディングされるものとして定義していますが、セクション 3.3 では、互換性のためにデコーダがパディングの欠落を受け入れる可能性があることに注意しています。
このツールが実装するアルファベット — 標準の Base64 および Base64url。他の基地はその範囲外のままです
パディングの違いは、実装間で意見が一致しない理由です。厳密なデコーダは欠落している等号を拒否しますが、寛容なデコーダはそれを受け入れます。 RFC 4648 には、URL で使用される場合、埋め込み文字の等号は通常パーセントでエンコードされるため、base64url 出力が URL パラメーターで直接使用される場合、埋め込みは必要ないため、省略する必要があると明示的に述べられています。この文は、URL セーフ モードとパディング省略が独立した選択であるにもかかわらず、しばしばペアになる理由の 1 つです。セクション 5 (base64url) はパディングを禁止していません。それは単に一般的な慣行をメモしているだけです。
Base64url を選択する呼び出し元は、受信側システムにパディングが必要かどうかを決定する必要があります。入力内のアルファベット以外の文字は、デコーダーによって処理方法が異なります。 RFC 4648 セクション 3.1 には次のように記載されています: 基本アルファベット以外の文字が含まれる場合、実装はエンコーディングを拒否しなければなりません。ただし、セクション 3.3 では、MIME Base64 (RFC 2045) では 76 文字の折り返しの改行が許可されており、MIME のデコーダーは空白をスキップする必要があると述べています。 RFC は、厳密なデコード (アルファベット以外のすべてを拒否) と MIME 互換のデコード (空白をスキップし、他の文字を拒否) を区別します。
パディング、非アルファベット文字、正規エンコーディング - デコーダの不一致のほとんどを説明するセクション
アプリケーションは、どのルールに従うかを選択する必要があります。標準では両方が定義されています。 Base32 は、A ~ Z および 2 ~ 7 (合計 32 文字) を使用し、5 つの入力バイト (40 ビット) を 8 つの出力文字にエンコードします。 Base32hex は、アルファベット文字を 0-9 および a-v に置き換えます。これは、小文字が優先されるコンテキストで役立ちます。
Base16 は 16 進数です: 0-9 および a ~ f。 Base32 と Base32hex には、セクション 6 と 7 に独自のパディング ルールがあり、RFC はアルファベットごとに個別のテスト ベクトルを提供します。ほとんどの開発者は、base64 と Base64url のみを必要とします。 Base32、base32hex、base16 は、完全性を確保するため、また TOTP シークレット (RFC 4226) や DNS エンコーディングなどのアプリケーションのために RFC に含まれています。
この実装で表示されるアプリケーションの選択肢 - 行の折り返し、厳密なテキストのデコード、およびエラー処理
RFC 4648 のテスト ベクトルは、実装をチェックするためのグラウンド トゥルースです。文字列 f、fo、foo、foob、foaba、および foobar をエンコードすると、特定の Base64 出力 (Zg==、Zm8=、Zm9v、Zm9vYg==、Zm9vYmE=、および Zm9vYmFy) が生成されます。これらの文字列に対して異なる出力を生成する実装は正しくありません。 RFC は、base32、base32hex、base16 に相当するテスト ベクトルを提供します。 Base64 エンコーダおよびデコーダ ツールにはこれらのベクトルが含まれているため、その出力を標準と比較して検証できます。行の折り返しは MIME の問題であり、base64 の問題ではありません。
RFC 2045 は 76 文字行を指定します。 RFC 4648 セクション 3.1 では、MIME のコンテキストでこれについて言及していますが、base64 自体の要件にはしていません。一部のアプリケーションは 64 文字 (元の PEM 標準) で折り返されます。他のものはまったくラップしません。厳密な RFC 4648 Base64 デコーダーは、アルファベットとパディングのみで動作します。 MIME 互換デコーダは改行 (CR、LF、CRLF) をスキップする必要があります。 MIME の外部で Base64 を使用するアプリケーションは、受信側システムが改行を要求しない限り、改行を追加しないでください。 RFC では行折り返しを Base64 の一部として定義していません。
実用的な例: RFC 独自のテスト ベクトル — 「foobar」プレフィックスをエンコードし、ブラウザでチェックする
空白の処理も実装の相違点の 1 つです。 RFC 4648 では、厳密なデコーダはアルファベット以外の文字を拒否しなければならないと述べています。 MIME ラップされた Base64 (RFC 2045 Base64) では、フォーマットに空白を使用できます。 2 つの標準は、出力バイトがどうあるべきかについては一致していますが、どの入力が有効であるかについては異なります。ほとんどの JavaScript 実装では、MIME 互換性を選択し、空白をスキップします。厳密なルールがブラウザーで使用されることはほとんどありません。 Base64 エンコーダとデコーダは、空白を含む (MIME) 入力と厳密な入力の両方を受け入れ、区別を明確にします。正規デコードと寛容デコードが最後の大きな違いです。
正規デコードは、RFC 4648 セクション 3.2 に従います。不正な形式のパディングを拒否し、欠落しているパディングを拒否し、非アルファベット文字を拒否します。 Web 標準で使用される寛容デコード (HTML 仕様では forgiving-base64 と呼ばれています) では、標準の Base64 モードでも空白スペースの無視、不足しているパディングの受け入れ、ダッシュとアンダースコアをプラスのスラッシュに相当するものとして許可するというルールが追加されます。 JavaScript の atob() は寛容です。厳密な RFC 4648 デコーダーはより厳密です。どちらも間違いではありません。それらは異なるコンテキストに対応します。ユーザーまたはネットワークからデータを読み取るアプリケーションは、相手側がどのルールを期待しているかを知っている必要があります。
これでカバーされないもの — MIME および PEM ドキュメント自体、および言語固有の API
RFC では、アプリケーションに 9 つの選択肢が残されています。つまり、5 つのアルファベットのうちどれを使用するか、パディングを要求するか許可するか、ホワイトスペースを要求するか許可するか、ダッシュアンダースコアをプラススラッシュと同等のものとして扱うかどうか、エラーを報告する方法、入力終了を処理する方法、パディングの欠落を受け入れるかどうか、割り当てる出力バイト数、およびサイズ制限を通知する方法です。これらの選択は、2 つの RFC 4648 実装が同じ入力に対して一致しない理由を説明しています。 RFC を一度読んでください。実装をテスト ベクトルに対してチェックします。アプリケーションがどのオプションを使用するかを述べます。仮定ではなく、実際のピアとの相互運用性をテストします。
RFC 4648 を理解すると、ほとんどの Base64 紛争が解決します。これは、意見の相違は通常、RFC 自体に関するものではなく、双方がどのオプションを選択したかに関するものであるためです。 RFC は 1 時間以内にエンドツーエンドで読めるほど簡潔です。この規格では、アルファベットを定義し、テスト ベクトルを提供し、実装がどこで決定する必要があるかを警告します。 Base64 エンコーダおよびデコーダ ツールを使用すると、テスト ベクトルを実験し、標準アルファベットが動作しているのを確認できます。 Base64 を日常的に使用する場合、ほとんどの場合、RFC の深い知識は必要ありません。ただし、エンコードの不一致をデバッグしたり、馴染みのない API と統合したりする場合は、標準を一度読むことで推測に頼る必要がなくなります。
要点: 標準を一度読んでください — Base64 エンコーダとデコーダが標準アルファベットのテスト ベクトルを簡単にチェックする方法を提供する方法
RFC 4648 は、数十年にわたるアドホックベースエンコーディングの実践を 1 つの読みやすい仕様に統合したものです。 Base64 をいつ使用するかは定義されていません (MIME、PEM、JWT、データ URI などにはそれぞれ独自の仕様があります)。それはbase64が何であるかを定義します。 RFC では、5 つのエンコーディング ファミリを定義し、どのオプションが正規であるかを示すことで、実装が正しいかどうかをチェックできるようになります。権威あるテスト ベクトルが出発点です。実装が foobar をエンコードし、Zm9vYmFy 以外のものを生成する場合、RFC は実装が間違っていると主張します。
その権限を検証チェックポイントとして使用します。各 RFC テスト ベクトルをエンコードし、正確な文字を比較し、結果をデコードして、元のバイトが変更されずに返されることを確認します。このブラウザベースのチェックでは、ライブラリ ラベルに依存するのではなく標準自体を参照として維持しながら、アルファベットまたはパディングの間違いを統合内の他の場所の問題から分離します。