Base64 とは⁠|3 バイトを 4 文字にする仕組み

回 1-6 道 1 数と論理と計算量

Base64 とは、どんなバイト列も英字と数字と + と / の 64 種類の字だけで書き表す符号化 (データの書き方の決まり) です。3 バイト (24 ビット) を 6 ビットずつ 4 つに切り、それぞれを 64 字の表の 1 字に置き換えるので、長さは元の約 4/3 になります。鍵を使わず誰でも元に戻せるので、暗号の代わりにはなりません。

データを運べる形に書き直すことと、データを隠すことを切り分けられるようになります。

なぜ Base64 が要るのか

Base64 が要るのは、文字しか通らない道に、画像や鍵のような文字でないバイト列を通したいからです。

Web の頁には、画像を data:image/png;base64, に続く英数字の長い列として直接書き込めます。メールの添付ファイルも、送るときは英数字の列に書き直されています。どちらも中身は画像やファイルのバイト列なのに、なぜわざわざ文字に書き直すのでしょうか。

手がかりは、電子メールや URL、JSON のように「決まった文字だけが通る」道が多いことです。バイト列には、改行や目に見えない制御の字に当たる値も混ざるので、そのまま流すと途中で壊れたり切れたりします。そこで、どんなバイト列も安全な 64 字だけで書き直してから運び、受け取った側で元に戻します。

文字は番号のバイト列で保存され、あ は UTF-8 で E3 81 82 の 3 バイトになる図

メールの決まりの RFC 2045 は、Base64 で書いた行を 1 行 76 字までと定めています。Base64 は、メールに添付ファイルを載せるための決まりとして広まりました。

Base64 はどう書き直すのか

Base64 は、バイト列を 6 ビットずつに切り直し、6 ビットで表せる 64 通りの値を、64 字の表の 1 字ずつに置き換えます。決まりは RFC 4648 に書いてあります。

64 字の表

6 ビットは 2 の 6 乗で 64 通りなので、64 字の表があれば、どの 6 ビットも 1 字で書けます。表は次の通りで、どれもメールや JSON の中で壊れない字です。

値字
0〜25A〜Z
26〜51a〜z
52〜610〜9
62+
63/

3 バイトを 4 字に

1 バイトは 8 ビット、1 字は 6 ビット分です。8 と 6 の最小公倍数の 24 ビット、つまり 3 バイトを 1 つの束にすると、ちょうど 4 字に切れます。

束ビットの数数え方
入る側248 ビット × 3 バイト
出る側246 ビット × 4 字

文字列の Man なら、M と a と n の 3 バイトの 24 ビットを 6 ビットずつ 4 つに切り、表で TWFu の 4 字になります。下の「動かして確かめる」で 1 段ずつ追います。

余りは = で詰める

バイト列の長さが 3 で割り切れないと、最後の束が足りません。足りない所は 0 のビットで埋めて字にし、それでも空いた字の場所を = で詰めて、いつも 4 字ずつにそろえます。

最後の束出る字= の数
3 バイト4 字0
2 バイト3 字 + =1
1 バイト2 字 + ==2

= の数を見れば、最後の束が何バイトだったかが分かります。だから読む側は、元のバイト数を正しく戻せます。

長さが約 4/3 になる理由

3 バイトが 4 字になるので、長さは 4/3 倍、約 1.33 倍になります。半端な束も 4 字分の場所を取るので、n バイトは 4 × (n ÷ 3 の切り上げ) 字です。下の図でつまみを動かすと、入るバイトを 1 つ増やしても字の数が変わらない所と、4 字いっぺんに増える所が交互に来ます。

3 バイトで 4 文字

URL とファイルの名前に使う版

標準の表の + と / は、URL では特別な意味を持ち、/ はファイルの名前にも使えません。そこで RFC 4648 は、+ を -、/ を _ に替えた版 (Base64URL) も決めています。値の 62 と 63 に当てる字が違うだけで、ほかは同じです。

動かして確かめる

Man の 3 バイトを、手で Base64 にしてみます。64 字の表を作り、24 ビットを 6 ビットずつ切って、表を引きます。

動かす Man を 6 ビットずつに切る

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

010011010110000101101110
010011 19 T
010110 22 W
000101 5 F
101110 46 u
TWFu

24 ビットを 6 ビットずつ切ると 19、22、5、46 になり、表で T、W、F、u です。8 ビットの境目と 6 ビットの境目はずれていますが、3 バイトでちょうど揃います。

次に、Python の標準の道具 base64 で、RFC 4648 の試験の値を変換します。長さが 1 から 6 バイトまでの文字列です。

動かす 長さごとの = の数

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

1 4 Zg==
2 4 Zm8=
3 4 Zm9v
4 8 Zm9vYg==
5 8 Zm9vYmE=
6 8 Zm9vYmFy

1 バイトでも 4 字になり、= が 2 つ付きました。2 バイトなら = が 1 つ、3 バイトなら = は無しです。4 バイトになると束が 2 つになり、8 字に増えます。RFC 4648 の 10 節の試験の値と、1 字も違いません。

日本語も、文字をバイト列にしてから Base64 にします。UTF-8 では「あ」が 3 バイトなので、ちょうど 4 字です。

動かす 日本語を Base64 にして戻す

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

e3 81 82
b'44GC'
あ
12 b'44KG44KB44GV44GP'

「あ」の E3 81 82 は 44GC になり、b64decode で元の「あ」に戻りました。4 字の「ゆめさく」は 12 バイトで、16 字になります。Base64 が書き直すのは文字ではなくバイト列なので、先に文字コードを決めてバイト列にすることが要ります。

最後に、長さが 4/3 に近づく様子を数えます。

動かす 長さは約 4/3 になる

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

1 4 4 4.0
2 4 4 2.0
3 4 4 1.333
4 8 8 2.0
100 136 136 1.36
1000 1336 1336 1.336

どの行も、実際の長さと式の 4 × (n ÷ 3 の切り上げ) が一致しました。短いデータでは半端な束の分だけ割合が大きく、1000 バイトでは 1.336 倍で、4/3 の 1.333 にほぼ近づきます。

Base64 を使うとどこで崩れるのか

Base64 は運ぶための書き直しで、隠す道具でも、壊れを見つける道具でもありません。この取り違えが、よくある事故の元です。

誰でも元に戻せる

Base64 には鍵が無いので、書いた字を見た人は誰でも元に戻せます。RFC 4648 も、パスワードのような情報を目からは隠すが、計算の上での秘密は何も守らない、と書いています。

動かす Base64 は誰でも戻せる

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

dXNlcjpwYXNzMTIzNA==
b'user:pass1234'

見た目は暗号のようでも、1 行で名前とパスワードが出てきました。HTTP の Basic 認証 (ブラウザが出す名前とパスワードの窓) は、まさにこの形で送ります。RFC 7617 は、Basic 認証の名前とパスワードは平文 (誰でも読める文) と同じだと書いています。

URL の中の + は空白に化ける

標準の Base64 を URL の問い合わせの部分に入れると、+ が空白に読まれます。

動かす URL の中の + と /

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

+/+/ -_-_
' / /' False
True

FB FF BF の 3 バイトは、標準の表では +/+/ になります。URL の問い合わせとして読むと + が空白に替わり、元の字と一致しません。URL 用の版の -_-_ なら、そのまま元のバイトに戻りました。

1 字の化けは、黙って別のデータになる

Base64 の字が 1 字化けても、多くの場合はエラーにならず、別のバイト列として読めてしまいます。

動かす 1 字の化けは気づけない

python実行可能
出力

▶ 実行ボタンを押すと結果がここに表示されます

実行すると、次の通りに出ます

b'aGVsbG8=' b'bGVsbG8='
b'lello'
b'hello'
907060870
3280994374

頭の 1 字を変えただけで、hello が lello になりました。3 行目は逆の向きの落とし穴で、最後の字が違う aGVsbG9= も同じ hello に戻ります。= の前の余りのビットは使われないからで、RFC 4648 は、これが文字列の比べをすり抜ける元になると注意しています。

壊れに気づくには、元のデータからチェックサム (データから計算する短い確かめの値) を作って一緒に送ります。下の 2 行の CRC32 (よく使うチェックサムの 1 つ) は、hello と lello で値が違うので、化けたことが分かります。

崩れる前提をまとめると、次の通りです。

  • 字が読めなければ中身は守られる、という前提。Base64 は鍵無しで誰でも戻せる
  • 英数字なら URL にそのまま入る、という前提。+ と / は URL で別の意味になる
  • 戻せたなら中身は正しい、という前提。1 字の化けは黙って別のデータになる

仕事でどう確かめるか

仕事では、戻して比べる試験と、置き場に合った版を選んだかの確かめをします。

1 つ目は、書いて戻して比べる試験です。長さが 0、1、2、3、4 バイトのデータと、日本語や 0xFF を含むデータで、b64decode(b64encode(x)) == x を確かめます。= の数が変わる境目を全部通るからです。

2 つ目は、置き場で版を選ぶことです。URL やファイルの名前、JWT (ログインの状態を運ぶ札) のような所では Base64URL を使い、メールのように 76 字で折り返す決まりがある所では、それに合う道具を使います。

3 つ目は、秘密を Base64 だけで置いていないかの点検です。設定のファイルや Kubernetes の Secret (パスワードなどをしまう置き場) の値は Base64 で書かれますが、Kubernetes の公式文書は、Secret は既定では暗号化されずに保存されると書いています。秘密は暗号化や置き場の権限で守り、Base64 は運ぶための形と考えます。

関わる実例

Base64 を暗号の代わりにした例は、脆弱性 (守りの穴) として公に記録されています。

IBM WebSphere の設定の書き出し CVE-2003-1447 (NVD の公開 2003 年 12 月 31 日)

米国の脆弱性データベース NVD によると、IBM WebSphere Advanced Server Edition 4.0.4 は、設定のファイルを XML に書き出すとき、パスワードを XOR (鍵とビットごとに混ぜる単純な計算) と Base64 の組み合わせで守っていました。この方法は弱く、書き出したファイルを読める利用者がパスワードを戻せるおそれがありました。

崩れた前提は「読めない字にすれば、守ったことになる」です。Base64 は鍵を持たない書き直しで、XOR を足しても、決まった手順で戻せる限り秘密にはなりません。RFC 4648 が注意の節で書いているのも、同じ取り違えです。

よくある問い

なぜ Base64 という名前なのですか

64 種類の字だけを使って書き表すので Base64 と呼びます。6 ビットで表せる値がちょうど 64 通りだからです。同じ考えで、32 種類の字を使う Base32 や、16 種類の字を使う Base16 (16 進数) も RFC 4648 に決まっています。

Base64 は危険ですか

Base64 で書くこと自体に危険はありませんが、秘密を守れると思って使うのは危険です。鍵が無いので、見た人は誰でも元に戻せます。パスワードやトークン (ログインの鍵) を Base64 にしただけで画面やログに出すと、そのまま漏れたのと同じです。

Base64 と Base64URL の違いは何ですか

違うのは 62 番と 63 番の字で、標準の Base64 は + と /、Base64URL は - と _ を使います。URL やファイルの名前の中で特別な意味を持たない字に替えた版です。JWT のように URL に載せる物では、= の詰め物も省くことが多くあります。

JavaScript ではどう変換しますか

ブラウザの JavaScript では、btoa で Base64 に書き、atob で戻します。ただし btoa は 1 字が 1 バイトに収まる字しか受け付けず、日本語を渡すと InvalidCharacterError で止まります。日本語は先に TextEncoder で UTF-8 のバイト列にしてから変換します。

ファイルを Base64 にするにはどうしますか

ファイルをバイト列として読み、それを Base64 に書き直します。Python なら open(名前, "rb") で読んだバイト列を base64.b64encode に渡します。Mac や Linux の端末なら base64 という命令でも変換できます。

確認クイズ

答えだと思う選択肢を押すと、その場で正誤と理由が開きます。4 問すべてに正しく答えると、この回は修了で、石が緑に変わります (この端末のブラウザに残ります)。間違えた問いは、あとから解き直せます。

1 問目

3 バイトのデータを Base64 で書くと、何字になりますか。

2 問目

このコードを動かすと何が出ますか。

fo を Base64 に

import base64
print(base64.b64encode(b"fo"))

3 問目

Base64 について正しいのはどれですか。

4 問目

Base64 で書いた値を URL の問い合わせの部分に入れるとき、よい方法はどれですか。

説明課題

次のことを、自分の言葉で 3 行にまとめてください。書いたら、下の模範解答を開いて比べてください。

  • Base64 で長さが約 4/3 になる理由を、ビットの数で
  • Base64 で秘密を守れない理由

模範解答

自分の説明を書いてから開いて、比べてください。

この回の先の一歩

画像の埋め込み、メールの添付、認証の値など、Base64 は Web の仕事でよく目にし、隠す仕組みではないと知っていることが守りにつながります。いまの自分が転職までの道のどの段にいるかは、転職診断で確かめられます。

もっと深く

この回の続きを、ゆめさくのコースの章や道具で深められます。頁の中の確認クイズに答えたあと、手を動かす量を増やしたいときに使ってください。

一次資料

どれも 2026年10月26日に開いて、題と中身を確かめました。

次へ

道 1 数と論理と計算量の回

  1. 1-12 進数と 16 進数桁の重み、変換、表せる範囲頁で読む
  2. 1-2文字コードと文字化けUnicode、UTF-8、Shift_JIS、BOM頁で読む
  3. 1-3計算量を数えるBig-O、ループの回数頁で読む
  4. 1-4論理と真理値表AND、OR、NOT、ド・モルガン準備中
  5. 1-5リトルエンディアンとビッグエンディアンバイトの並び順、ネットワーク、ファイル頁で読む
  6. 1-6Base64 の仕組み64 字の表、= の詰め物、長さ 4/3この回
  7. 1-7情報量とハフマン符号化ビット、確からしさ、圧縮頁で読む
  8. 1-8チューリングマシンと停止問題テープ、状態、計算できない問題頁で読む

道 1 の頁へ戻るほかの道を見る