本記事では RFC 4648 仕様の Base32 エンコードについて説明します。
参考「RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
1. Base32 エンコードの仕組み
データを長さ 5 ビットずつに区切り、それぞれの値 (0–31) を「Base32 文字」に割り当てて置き換えます。
長さ 5 ビットずつで割り切れずに残る (長さが 5 ビット未満の) データは後ろに値が 0 のパディングビットを追加して長さ 5 ビットとして扱います。
実際に使用されている「Base32 文字」にはいくつか種類がありますが、例えば RFC 4648 で定義されているものは以下の通りです。
ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
参考「RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
参考「Base32 - Wikipedia」
Base64 や Base32 エンコードされたデータの長さが切りが良くなるようにパディング文字 =
を追加します (Base64 は 4 の倍数、Base32 は 8 の倍数の長さ) 。
パディング文字 =
がなくてもエンコード済みのデータが正しければデコード可能ですが、特定の状況では必要になり、RFC 4648 の仕様に準拠するならパディング文字 =
は必須です。
参考「3.2. Padding of Encoded Data - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
Base32 デコードする際に場合によっては 0
と O
のような紛らわしい文字を置き換えることがありますが、RFC 4648 では「デフォルトの動作にすべきでない」とされています。
参考「3.4. Choosing the Alphabet - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
2. Base32 エンコーダおよびデコーダ実装時のセキュリティ上の注意点
Base32 エンコーダやデコーダを実装するときに脆弱性や不具合の原因になる可能性があるため、以下の注意点があります:
- エンコード時に Base32 文字以外の文字 (改行や空白等を含む) を追加してはいけない (例外あり)
- デコード時に Base32 文字以外の文字 (改行や空白等を含む) を無視せずエラーにしなければならない (例外あり)
- エンコード時に適切なパディング文字
=
を含めなければならない - デコード時に末尾のパディング文字
=
を無視しても良い - エンコード時にパディングビットを 0 にしなければならない
- デコード時にパディングビットが 0 でない場合はエラーにしても良い
上記の内容に反する仕様にすると、本来のデータは同一でも Base32 エンコードした文字列が同一でなくなり、予期しない動作を引き起こす場合があります。
ただし、「Base32 自体の仕様」としてでなく、「Base32 を扱う他の仕様」として「改行等を無視する」ような仕様 (例えば、「PEM 形式で Base64 エンコードを利用する際に 64 文字ごとに改行して扱う」等) にすることは可能です。
参考「3.1. Line Feeds in Encoded Data - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」(改行の扱い)
参考「3.3. Interpretation of Non-Alphabet Characters in Encoded Data - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」(Base32 文字以外の扱い)
参考「3.5. Canonical Encoding - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」(パディングビットの扱い)
参考「12. Security Considerations - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
また、RFC 4648 に直接は書かれていませんが、パディングビットの仕様から以下のことも言えると思います:
- エンコード時にパディングビットの長さを 5 ビット未満にしなければならない
- デコード時にパディングビットの長さが 5 ビット以上 (かつ 8 ビット未満) の場合はエラーにしても良い
参考「6. Base 32 Encoding - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
3. Base32 デコード時に大文字と小文字を区別するかどうかについて
結論から言うと、Base32 の大文字と小文字の区別の扱いは以下のようになると思います:
- エンコーダは Base32 文字を大文字とする
- デコーダは Base32 文字の大文字と小文字を区別しない
- デコーダ利用時に Base32 文字の大文字と小文字に注意する
Base32 自体の説明では「Base32 は大文字と小文字を区別しない必要がある場合用に設計されている」という内容が書かれています。
エンコーダは (RFC 4648 の仕様上は) Base32 文字に「大文字を使う」ことになっています。
参考「6. Base 32 Encoding - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
RFC 4648 のセキュリティに関する項目では、「Base32 で大文字と小文字を区別しないときに脆弱性や不具合に注意すべき」ようなことが書かれています (英語で if
でなく when
が使われているため、「Base32 で大文字と小文字を区別しない」ことは前提とみなしている) 。
以下は RFC 4648 より引用:
Similarly, when the base 16 and base 32 alphabets are handled case insensitively, alteration of case can be used to leak information or make string equality comparisons fail.
参考「12. Security Considerations - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
RFC 4648 では「大文字と小文字の区別」と同様の話として 「Base32 文字以外の文字の扱い」についても触れており、そちらでは「例外を除いて無視せずエラーとしなければならない」「無視せずエラーとすることを推奨」「もしエラーとせず無視するのであればそれは非推奨な実装方法であると分かっているべき」と書かれており、セキュリティ上安全でない実装方法も許容するが基本的には非推奨とする扱いになっています。
「大文字と小文字の区別」を「Base32 文字以外の文字の扱い」と同じように見るなら、セキュリティ上安全である「大文字と小文字を区別する」実装方法が良いようにも思えますが、RFC 4648 に書いてることを文字通り読むと「Base32 デコーダは大文字と小文字を区別しないが、デコーダ利用時は脆弱性や不具合に注意する」ということになるかと思います。
参考「3.3. Interpretation of Non-Alphabet Characters in Encoded Data - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」
参考「12. Security Considerations - RFC 4648 - The Base16, Base32, and Base64 Data Encodings」