エンコーディング基礎
所要時間: 45分
はじめに
「エンコーディング」という言葉は様々な場面で使われますが、本質的に はデータをある形式から別の形式に変換することです。
認証・認可の世界では、以下のエンコーディングが頻繁に登場します:
| エンコーディング | 用途例 |
|---|---|
| Base64 | JWT、Basic認証、バイナリデータ送信 |
| Base64URL | JWT(URL安全な形式) |
| URLエンコーディング | redirect_uri、クエリパラメータ |
| 文字エンコーディング(UTF-8) | ユーザー入力、多言語対応 |
| Hex(16進数) | ハッシュ値、デバッグ出力 |
1. Base64
Base64とは
バイナリデータをテキスト(ASCII文字)で表現するエンコーディング方式です。
┌─────────────────────────────────────────────────────────────────────┐
│ Base64 の目的 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 問題: バイナリデータ(画像、暗号文など)をテキストで送りたい │
│ │
│ 例: メールはテキストプロトコル(7bit ASCII) │
│ → バイナリをそのまま送ると文字化けや破損 │
│ │
│ 解決: バイナリを「安全な64文字」で表現 │
│ A-Z, a-z, 0-9, +, / (と padding の =) │
│ │
└────────── ───────────────────────────────────────────────────────────┘
エンコード方法
┌─────────────────────────────────────────────────────────────────────┐
│ なぜ「Base64」という名前なのか │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Base64 = 64種類の文字を使うエンコーディング │
│ │
│ 6ビットで表現できる値: 2^6 = 64 種類(0〜63) │
│ │
│ 64文字 = A-Z (26) + a-z (26) + 0-9 (10) + 記号2つ (+, /) │
│ = 26 + 26 + 10 + 2 = 64 │
│ │
│ → 6ビット = 1文字 という対応関係 │
│ → 全て印刷可能なASCII文字で安全に転送できる │
│ │
│ ※ 同様に Base32(5ビット = 32文字)、Base16(4ビット = 16文字) │
│ なども存在する │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────── ──────────┐
│ 3バイト → 4文字 の理由 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 入力: 3バイト = 24ビット │
│ 出力: 24ビット ÷ 6ビット = 4文字 │
│ │
│ ┌────────┬────────┬────────┐ │
│ │ 8ビット │ 8ビット │ 8ビット │ ← 入力 3バイト │
│ └────────┴────────┴────────┘ │
│ ↓ ↓ ↓ │
│ ┌──────┬──────┬──────┬──────┐ │
│ │6ビット│6ビット│6ビット│6ビット│ ← 出力 4文字 │
│ └──────┴──────┴──────┴──────┘ │
│ │
│ データサイズ: 約33%増加(3バイト → 4バイト) │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ Base64 エンコードの仕組み │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 入力データを 3バイト(24ビット)ずつに分割 │
│ │
│ 2. 24ビットを 6ビット × 4 に分割 │
│ │
│ 3. 各6ビット(0-63)を対応する文字に変換 │
│ │
│ 例: "Man" をエンコード │
│ │
│ M a n │
│ 01001101 01100001 01101110 (ASCII バイト値) │
│ ├──────┼┼──────┼┼──────┼┤ │
│ 010011 010110 000101 101110 (6ビットずつ分割) │
│ 19 22 5 46 (10進数) │
│ T W F u (Base64文字) │
│ │
│ 結果: "Man" → "TWFu" │
│ │
└─────────────────────────────────────────────────────────────────────┘
Base64文字テーブル
値: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
文字: A B C D E F G H I J K L M N O P
値: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
文字: Q R S T U V W X Y Z a b c d e f
値: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
文字: g h i j k l m n o p q r s t u v
値: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
文字: w x y z 0 1 2 3 4 5 6 7 8 9 + /
パディング(=)
入力が3バイトの倍数でない場合、= でパディングします。
┌─────────────────────────────────────────────────────────────────────┐
│ パディングの例 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 入力: "Ma"(2バイト = 16ビット) │
│ │
│ M a (不足) │
│ 01001101 01100001 00000000 ← 0で埋める │
│ │
│ 010011 010110 000100 (不完全) │
│ T W E = ← 1文字分不完全なので = 1つ │
│ │
│ 結果: "Ma" → "TWE=" │
│ │
│ --- │
│ │
│ 入力: "M"(1バイト = 8ビット) │
│ │
│ 結果: "M" → "TQ==" ← 2文字分不完全なので = 2つ │
│ │
└─────────────────────────────────────────────────────────────────────┘
実践例
# エンコード
$ echo -n "Hello, World!" | base64
SGVsbG8sIFdvcmxkIQ==
# デコード
$ echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d
Hello, World!
// Java
import java.util.Base64;
// エンコード
String encoded = Base64.getEncoder().encodeToString("Hello".getBytes());
// "SGVsbG8="
// デコード
byte[] decoded = Base64.getDecoder().decode("SGVsbG8=");
String text = new String(decoded); // "Hello"
認証・認可での使用例
┌─────────────────────────────────────────────────────────────────────┐
│ Base64 の使用例 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Basic認証 │
│ Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ= │
│ └─ "username:password" の Base64 │
│ │
│ 2. JWT(後述のBase64URLを使用) │
│ eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIn0.xxxxx │
│ └─ ヘッダー └─ ペイロード │
│ │
│ 3. client_secret_basic │
│ Authorization: Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ= │
│ └─ "client_id:client_secret" の Base64 │
│ │
│ 4. PKCE code_verifier から code_challenge 生成 │
│ code_challenge = BASE64URL(SHA256(code_verifier)) │
│ │
└─────────────────────────────────────────────────────────────────────┘
2. Base64URL
標準Base64の問題
標準のBase64には + と / が含まれますが、これらはURLで特別な意味を持ちます。
+ → URLでは空白(スペース)として解釈される
/ → URLではパス区切りとして解釈される
= → URLでは特別な意味を持つ可能性
Base64URL の違い
┌─────────────────────────────────────────────────────────────────────┐
│ Base64 vs Base64URL │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 標準 Base64: A-Z, a-z, 0-9, +, / (パディング: =) │
│ Base64URL: A-Z, a-z, 0-9, -, _ (パディング: 省略可) │
│ │
│ 変換ルール: │
│ + → - │
│ / → _ │
│ = → 削除(または保持) │
│ │
│ 例: │
│ 標準: "abc+/==" │
│ URL安全: "abc-_" │
│ │
└─────────────────────────────────────────────────────────────────────┘