ファイルを選択
  1. base64hub
  2. Base64 を学ぶ
  3. よくある Base64 の接頭辞
リファレンス

よくある Base64 の接頭辞:先頭の文字でファイルを見分ける

ほとんどのファイル形式は決まったマジックバイトで始まるので、その Base64 も決まった文字で始まります。十数個の接頭辞を覚えておけば、何もデコードしないうちに PNG と PDF を見分けられます。

接頭辞の一覧表

各行は、その形式の実際のマジックバイトをエンコードして確認しました。「固定の接頭辞」は、その形式で常に変わらない部分です。その後に続く文字はファイルの残りの内容によって変わります。

Base64 の接頭辞マジックバイト(16進数)形式開くツール
iVBORw0KGgo89 50 4E 47 0D 0A 1A 0APNGBase64 から PNG へ
/9j/FF D8 FFJPEGBase64 から JPG へ
R0lGOD47 49 46 38(GIF8)GIF(R0lGODlh = GIF89a、R0lGODdh = GIF87a)Base64 から GIF へ
UklGR52 49 46 46(RIFF)WebP、WAV、AVIBase64 から WebP へ、Base64 から WAV へ
JVBERi025 50 44 46 2D(%PDF-)PDFBase64 から PDF へ
UEsDB50 4B 03 04(PK..)ZIP、DOCX、XLSX、PPTX、JAR、APK、EPUBBase64 から ZIP へ、Word、Excel
H4sI1F 8B 08gzipgzip の Base64 をデコード
eJ、eN、eF、eA78 9C、78 DA、78 5E、78 01zlibzlib と Base64
eyJ7B 22({")JSON オブジェクト、JWTBase64 から JSON へ、JWT デコーダー
PD94bWwg3C 3F 78 6D 6C 20(<?xml )XML、宣言付きの SVGBase64 から XML へ
PHN2Zy3C 73 76 67 20(<svg )宣言のない SVG(<svg の後が改行なら PHN2Zw)Base64 から SVG へ
MII30 82DER:証明書、鍵、CSR証明書デコーダー
AAAA00 00 00SSH 公開鍵のブロブ、または先頭のゼロSSH 鍵のフィンガープリント
SUQz49 44 33(ID3)ID3v2 タグ付きの MP3Base64 から MP3 へ
AAABAA00 00 01 00ICOBase64 から ICO へ
d09GMg77 4F 46 32 00(wOF2)TrueType アウトラインの WOFF2 フォント(CFF フォントは d09GMk9UVE8 で始まる)Base64 をフォントに変換
TVqQ4D 5A 90(MZ)Windows の EXE や DLL(MZP を書き出すリンカーもあり、その場合は TVpQ)Base64 をファイルに変換
f0VMR7F 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 をファイルに変換ツールはデータをデコードし、そのバイト列を多数のシグネチャと照合します。

続けて読む