接頭辞の一覧表
各行は、その形式の実際のマジックバイトをエンコードして確認しました。「固定の接頭辞」は、その形式で常に変わらない部分です。その後に続く文字はファイルの残りの内容によって変わります。
| Base64 の接頭辞 | マジックバイト(16進数) | 形式 | 開くツール |
|---|---|---|---|
iVBORw0KGgo | 89 50 4E 47 0D 0A 1A 0A | PNG | Base64 から PNG へ |
/9j/ | FF D8 FF | JPEG | Base64 から JPG へ |
R0lGOD | 47 49 46 38(GIF8) | GIF(R0lGODlh = GIF89a、R0lGODdh = GIF87a) | Base64 から GIF へ |
UklGR | 52 49 46 46(RIFF) | WebP、WAV、AVI | Base64 から WebP へ、Base64 から WAV へ |
JVBERi0 | 25 50 44 46 2D(%PDF-) | Base64 から PDF へ | |
UEsDB | 50 4B 03 04(PK..) | ZIP、DOCX、XLSX、PPTX、JAR、APK、EPUB | Base64 から ZIP へ、Word、Excel |
H4sI | 1F 8B 08 | gzip | gzip の Base64 をデコード |
eJ、eN、eF、eA | 78 9C、78 DA、78 5E、78 01 | zlib | zlib と Base64 |
eyJ | 7B 22({") | JSON オブジェクト、JWT | Base64 から JSON へ、JWT デコーダー |
PD94bWwg | 3C 3F 78 6D 6C 20(<?xml ) | XML、宣言付きの SVG | Base64 から XML へ |
PHN2Zy | 3C 73 76 67 20(<svg ) | 宣言のない SVG(<svg の後が改行なら PHN2Zw) | Base64 から SVG へ |
MII | 30 82 | DER:証明書、鍵、CSR | 証明書デコーダー |
AAAA | 00 00 00 | SSH 公開鍵のブロブ、または先頭のゼロ | SSH 鍵のフィンガープリント |
SUQz | 49 44 33(ID3) | ID3v2 タグ付きの MP3 | Base64 から MP3 へ |
AAABAA | 00 00 01 00 | ICO | Base64 から ICO へ |
d09GMg | 77 4F 46 32 00(wOF2) | TrueType アウトラインの WOFF2 フォント(CFF フォントは d09GMk9UVE8 で始まる) | Base64 をフォントに変換 |
TVqQ | 4D 5A 90(MZ) | Windows の EXE や DLL(MZP を書き出すリンカーもあり、その場合は TVpQ) | Base64 をファイルに変換 |
f0VMR | 7F 45 4C 46(.ELF) | Linux の ELF バイナリ | Base64 をファイルに変換 |
いくつかの行には補足が必要です。
- RIFF はコンテナです。形式名はバイト 8〜11 にあり、バイト 9〜11 が 13〜16 文字目にエンコードされます。WebP(
EBP)ならRUJQ、WAV(AVE)ならQVZF、AVI(VI)ならVkkgです。形式名の最初の 1 文字はファイルサイズと同じ 3 バイトのグループに入るため、固定の文字にはなりません。 - zlib には単一の接頭辞がありません。2 バイト目に圧縮レベルが記録されるからです。Python の
zlibが書き出す場合、デフォルトのレベルならeJ、レベル 7〜9 ならeN、2〜5 ならeF、0 と 1 ならeAになります。 - JSON が
eyJで始まるのは、最初の 2 文字が空白なしの{"の場合だけです。{ "a": 1 }はeyAiで始まり、整形された{と改行はewoで始まり、配列の[はWで始まります。 - DER の構造は SEQUENCE タグ
30で始まり、これは必ずMになります。長さが 2 バイト(30 82)ならMIIになり、次の文字は長さによって変わります。RSA 2048 の公開鍵はMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA、一般的な証明書はMIIC、MIID、MIIEです。短い構造は 1 バイトの長さを使い、Ed25519 の秘密鍵はMC4C、P-256 の公開鍵はMFkwで始まります。 - SSH 公開鍵は 4 バイトのビッグエンディアンの長さで始まるので、ブロブは
AAAAで始まります。その後の文字が鍵の種類を表し、AAAAC3NzaC1lZDI1NTE5はssh-ed25519、AAAAB3NzaC1yc2Eはssh-rsa、AAAAE2VjZHNhはecdsaです。SSH 以外では、Aが続くのは単にゼロバイトが続いているという意味です。 - MP3 のうち ID3 タグのないファイルは、いきなりフレームヘッダーから始まります。その同期ビット
FF Fxによって先頭が//になり、たとえばFF FB 90は//uQです。 - Base64URL では
+と/が置き換わるので、JPEG の接頭辞は_9j_になります。表の他の接頭辞はどちらの文字も含まないので、どちらのアルファベットでも同じ見た目です。
接頭辞が変わらない理由
Base64 は 3 バイト単位で処理します。3 バイトのグループはそれぞれちょうど 4 文字になり、その 4 文字はその 3 バイトだけで決まります。ファイルの後ろの内容が前に影響することはありません。つまり、ある形式が常に同じ 3 バイトで始まるなら、その Base64 は常に同じ 4 文字で始まります。
bytes: FF D8 FF
bits: 11111111 11011000 11111111
groups: 111111 111101 100011 111111
index: 63 61 35 63
chars: / 9 j /
固定のマジックが 3 バイトの倍数でない場合、最後のグループには既知のビットとファイルの残りのビットが混ざります。5 バイトの %PDF- で考えてみましょう。最初の 3 バイトで固定の 4 文字(JVBE)、次の 2 バイトでさらに 2 文字(Ri)が決まり、7 文字目は - の下位 4 ビットとバージョン番号の上位 2 ビットが混ざります。数字はすべて 00 というビットで始まるので、実際にはこの文字は常に 0 です。JVBERi0 の後にはバージョンが現れます。JVBERi0xLjQ は %PDF-1.4、JVBERi0xLjc は %PDF-1.7、JVBERi0yLjA は %PDF-2.0 です。
PNG のシグネチャは 8 バイトなので、固定の文字は 10 文字です。11 文字目はシグネチャの最後のバイトと IHDR チャンクの長さの最初のバイトが混ざりますが、後者は常に 0 なので iVBORw0KGgo が成り立ちます。どの PNG もその後に IHDR チャンクが続くため、実際の PNG はさらに長い iVBORw0KGgoAAAANSUhEUg という接頭辞を共有しています。
接頭辞がずれる場合
接頭辞が使えるのは、マジックバイトがオフセット 0、3、6…にある場合だけです。先頭に 1 バイト加えるとすべてのグループがずれ、文字がまったく変わってしまいます。
| 入力 | Base64 の先頭 |
|---|---|
| PNG シグネチャ | iVBORw0KGgoAAAA |
| 1 バイト + PNG シグネチャ | AIlQTkcNChoKAAAA |
| 2 バイト + PNG シグネチャ | AACJUE5HDQoaCgAA |
| 3 バイト + PNG シグネチャ | AAAAiVBORw0KGgoA |
余分なバイトが 3 つならアラインメントが戻り、おなじみの接頭辞が 4 文字後ろに現れます。接頭辞がずれたり消えたりするよくある原因は次のとおりです。
- バイトオーダーマーク(BOM)。 BOM 付きの UTF-8 テキストは
77u/(EF BB BF)で始まります。BOM は 3 バイトなので、その後の JSON は77u/eyJ…のように引き続きeyJが見えます。BOM 付きの UTF-16 テキストは//4か//5(リトルエンディアン)、または/v8(ビッグエンディアン)で始まります。 - UTF-16 のテキスト。 UTF-16LE で保存したテキストは ASCII 文字ごとにゼロバイトが入るため、
Aが大量に現れます。HelloはSABlAGwAbABvAA==になります。PowerShell の-EncodedCommandはこの形です。PowerShell デコーダーか Base64 から UTF-16 へを使ってください。 - 圧縮や暗号化。 gzip で圧縮された PNG は
H4sIで始まり、暗号化されたファイルには見分けのつく接頭辞がまったくありません。 - Data URI。
data:image/png;base64,はヘッダーで、Base64 はカンマの後から始まります。Data URI パーサーで分割できます。 - 改行や空白。 バイト列はずれませんが、文字列が改行や引用符で始まっていると、
startswithによる接頭辞の検索は失敗します。先にトリムするか、Base64 の修復ツールに通してください。
コードで接頭辞を確認する
先頭の文字を文字列として照合することもできますが、デコードしたバイト列を比較するほうが間違いが起きにくくなります。マジックナンバーは各形式の仕様からそのまま取れますし、どの文字が固定かを考える必要もありません。先頭の 12 文字だけをデコードすれば最初の 9 バイトが得られ、ほとんどのシグネチャにはこれで足ります。
import base64
SIGNATURES = {
b"\x89PNG\r\n\x1a\n": "png",
b"\xff\xd8\xff": "jpeg",
b"%PDF-": "pdf",
b"PK\x03\x04": "zip",
b"\x1f\x8b": "gzip",
}
def sniff(b64: str) -> str:
head = base64.b64decode(b64.strip()[:12])
for magic, name in SIGNATURES.items():
if head.startswith(magic):
return name
return "unknown"
print(sniff("iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB")) # png
print(sniff("JVBERi0xLjcKJcfsj6IK")) # pdf
Base64 をファイルに変換ツールは、もっと長いリストで同じ確認を行い、ブラウザが表示できる形式ならプレビューも表示します。6 ビットのグループがどのように文字に対応するかは、Base64 の仕組みとアルファベット表をご覧ください。
よくある質問
iVBORw0KGgo で始まる Base64 文字列は何ですか?
PNG 画像です。iVBORw0KGgo は 8 バイトの PNG シグネチャ 89 50 4E 47 0D 0A 1A 0A を Base64 にしたものです。Base64 から PNG へに貼り付ければ画像を確認できます。
Base64 文字列の先頭にある /9j/ は何ですか?
JPEG です。すべての JPEG ファイルの先頭にあるバイト FF D8 FF は /9j/ にエンコードされます。Base64URL では、同じ接頭辞が _9j_ になります。
JWT が必ず eyJ で始まるのはなぜですか?
JWT のヘッダーは JSON オブジェクトなので {" で始まり、この 2 バイトが eyJ にエンコードされるからです。ペイロード部分が eyJ で始まるのも同じ理由です。
手元の Base64 がどの接頭辞にも当てはまりません。どうすればいいですか?
データの前に余分なバイトがある、圧縮や暗号化がされている、あるいはただのテキストである可能性があります。Base64 をファイルに変換ツールはデータをデコードし、そのバイト列を多数のシグネチャと照合します。