エンコーディング/基数検出・変換ツール

文字列を貼り付けると、このツールが考えられるエンコーディング/フォーマット(base64、hex、JWT、GUID、ハッシュ、JSON、YAMLなど)を順位付けし、安全なデコードプレビューを表示します。

インタラクティブシミュレーションを読み込んでいます...

判定が割合を返すのは、確実さが手に入らないからである

十六進の数字 — 0 から 9 と a から f — はどれも Base64 の正当な文字でもあります。ですから長さがたまたま四で割れる十六進文字列は、同時に構文として妥当な Base64 文字列でもあります。文字の集合を眺めるだけでは両者を分けられません。だからこの道具は判決ではなく確信度を返します。実際に決着をつけるのは構造と意味です。詰め文字、長さの計算、そして復号して意味のあるものが出てくるかどうか。base64Json の見本はきれいな例で、{"name":"Spock","role":"scientist","active":true} に復号されます。妥当な JSON が出てくる推測は、ほぼ確実に当たりです。

エンコードは暗号化ではない

文字列がごちゃ混ぜに見えると、解読すべき秘密だと思い込みがちです。しかし不透明なテキストの多くは、隠されているのではなく、単に形を変えられているだけです。Base64 と 16進数は完全に元へ戻せ、GUID は一意のラベルにすぎず、SHA-256 のようなハッシュは元の入力へ二度と戻せない一方向のフィンガープリントです。このツールは文字列をこれらのカテゴリに分類し、そもそもデコードが可能かどうかを教えてくれます。

Base64 はデータを小さくせず大きくする

Base64 は圧縮とよく混同されますが、実際は逆で、3バイト(24ビット)ごとに4つの印字可能文字へ変換され、データは約33%膨らみ、最後のグループは = 記号で埋められます。これには歴史的な理由があります。初期の電子メール(7ビットSMTP上のMIME)は生のバイナリを運べなかったため、添付ファイルは安全な64文字のアルファベットで表現し直す必要がありました。この名残により、画像は今日でも data: URL の中で膨らんだテキストとして運ばれています。

全プロセスの詳細解説

  1. 49文字のASCII JSONペイロードから68文字への変換と復元 5 ステップ

    入力は eyJuYW1lIjoiU3BvY2siLCJyb2xlIjoic2NpZW50aXN0IiwiYWN0aXZlIjp0cnVlfQ== であり、その下のペイロードは 49 文字の ASCII JSON {"name":"Spock","role":"scientist","active":true} です。 パネルには Characters に 68、Bytes に 68 と表示されています。エンコードされた文字列を数えずに 68 を 49 から導き出し、さらにそこから元に戻してください。

    この問題をツールで開く

    1. Base64 は基数の変更であり、暗号ではありません。64 = 26 であるため、出力の各文字は 6 ビットを保持します。入力の 3 バイトは 24 ビットを保持し、6 は 24 を割り切ることができます。フォーマットの全容はこれだけであり、3 バイトの入力に対して 4 文字が出力され、余りは出ません。

      224=644⟹L=4⌈n3⌉2^{24}=64^{4}\quad\Longrightarrow\quad L=4\left\lceil\frac{n}{3}\right\rceil
    2. 49 バイトは 16 個の完全なトリプルと余り 1 バイトからなります。トリプルの部分は単純で、16 × 4 = 64 文字となり、その一文字一文字が満額の 6 ビットを担います。

      n=49=3×16+1⟹16×4=64n=49=3\times16+1\quad\Longrightarrow\quad 16\times4=64
    3. 端数のバイトがあるからこそパディングが発生します。8 ビットは 6 の倍数ではないため、4 ビットのゼロが補われて 12 ビット(2 文字分)となり、2 つの '=' 記号がカルテットを完成させます。64 + 2 + 2 = 68 となります。各 '=' は、独自のビットを持たなかった文字位置を示しています。

      8 bits→ +4 12=2×6,p=2 ⟹ L=64+2+2=688\ \mathrm{bits}\xrightarrow{\,+4\,}12=2\times6,\qquad p=2\ \Longrightarrow\ L=64+2+2=68
    4. パネルのどちらの行も 68 と読み取れますが、その一致はこの文字列について何も物語っていません。Base64 のアルファベットは ASCII であるため、出力されるすべての文字は正確に 1 バイトです。どのような Base64 入力であっても、Bytes 行は Characters 行に追従します。

      S=L=68(ASCII)S=L=68\qquad(\mathrm{ASCII})
    5. 今度は逆に計算します。68 ÷ 4 = 17 カルテット、17 × 3 = 51 バイトのスロットから、パディングが空であると認める 2 スロットを差し引くと 49 です。単一のバイトすらデコードすることなく、ペイロードのサイズが復元されました。

      n=3L4−p=3×684−2=51−2=49n=\frac{3L}{4}-p=\frac{3\times68}{4}-2=51-2=49

    解答

    68 文字で 49 バイトであり、'=' 記号のおかげでラッパーから 49 を直接読み戻すことができます。 逆の計算ができることこそが役に立つ半分です。Base64 文字列の長さはペイロードの長さにのみ依存し、他には何も依存しないため、閲覧を許可されていないものの正確なサイズを特定できます。これは、このページのどの検出器がコンテンツについて行う言及よりも強い主張です。もう半分は代償です。4 文字につき 3 バイトという効率は決して改善しないため、極限において Base64 のコストは 4/3 になります。1 MiB のファイルは 1,398,104 文字として届き、純粋な包装だけで 341 KiB になります。この文字列は 68/49 = 1.388 とさらに効率が悪くなります。2 文字のパディングが固定の割増金であり、49 バイトではそれを薄めるには短すぎるからです。

    Ln=6849=1.388 ⟶ 43,220 B⇒L=1 398 104\frac{L}{n}=\frac{68}{49}=1.388\ \longrightarrow\ \frac43,\qquad 2^{20}\,\mathrm{B}\Rightarrow L=1\,398\,104
  2. GUID/UUID v4のランダムビットと重複までに生成される識別子 6 ステップ

    入力は 550e8400-e29b-41d4-a716-446655440000 であり、パネルでは GUID/UUID v4 と表記されると同時に Base64URL としてデコードする機能も提供されています。 実際にはいくつのビットがランダムに選択されたのか、そして重複が発生する可能性が低くなくなるまでに、このような識別子をいくつ発行できるかを計算してください。

    この問題をツールで開く

    1. まずその形状を数えます。8-4-4-4-12 の十六進桁で、グループの間に 4 つのハイフンがあるため、32 + 4 = 36 文字となり、十六進桁とハイフンはすべて ASCII なので Bytes 行も 36 で一致します。それら 4 つのハイフンが何に値するか注意してください。固定位置にあるため、それらは 0 ビットを担います。

      L=8+4+4+4+12⏟32+4=36=SL=\underbrace{8+4+4+4+12}_{32}+4=36=S
    2. 十六進の各桁は 4 ビットなので、対象となる 32 桁は 128 ビットを保持します。これが UUID について通常引用される数値ですが、この文字列に関しては高すぎます。

      32×4=128 bits32\times4=128\ \mathrm{bits}
    3. 13 番目の桁と 17 番目の桁がその理由です。13 番目の桁は 4 であり、これはバージョンフィールドです。バージョン 4 の UUID はそこに 4 を置くことが義務付けられているため、それら 4 ビットが選択肢となることはありませんでした。17 番目の桁は 'a' で、2 進数では 1010 であり、その先頭 2 ビットはバリアントタグとして 10 に固定されています。フォーマットの指定に費やされた 6 ビットを差し引くと、122 ビットが残ります。

      d13=4 (4 bits),d17=a=10102 (2 bits) ⟹ 128−6=122d_{13}=\mathtt{4}\ (4\ \mathrm{bits}),\quad d_{17}=\mathtt{a}=1010_{2}\ (2\ \mathrm{bits})\ \Longrightarrow\ 128-6=122
    4. したがって、空間の大きさは 2122、およそ 5.32 × 1036 であり、128 ビットが与えたであろう 3.40 × 1038 には達しません。

      N=2122=5.32×1036(2128=3.40×1038)N=2^{122}=5.32\times10^{36}\qquad(2^{128}=3.40\times10^{38})
    5. 重複は空間の大きさではなく、誕生日の法則に従います。n 個の識別子をランダムに抽出するとき、あるペアが一致する確率は n2/(2N) のように増加し、これを 0.5 に設定すると n = 1.177√N が得られます。カウントは平方根に伴って変化するため、6 ビットの損失(ステップ 3 で生じたもの)が 8 倍の係数となり、64 倍にはならない理由がここにあります。

      1−e−n2/2N=0.5 ⟹ n=2Nln⁡2=1.177N1-e^{-n^{2}/2N}=0.5\ \Longrightarrow\ n=\sqrt{2N\ln2}=1.177\sqrt{N}
    6. √N は 2.31 × 1018 であるため、n は 2.7 × 1018 となります。

      n=1.177×2.31×1018=2.7×1018n=1.177\times2.31\times10^{18}=2.7\times10^{18}

    解答

    122 ビットであり、2.7 × 1018 個の UUID で重複の確率が 0.5 に達します。 毎秒 109 個のペースで発行した場合、それは 86 年に相当します。そしてこれこそが、レジストリも調整もなしに各マシンに固有のものを生成させる根拠のすべてです。プロトコルではなく、単に到達不能なほど大きな数値なのです。これを最初の問題と並べると、その対比こそがこのページの目的です。Base64 は各文字に 6 ビットを詰め込みますが、この文字列は 36 文字を費やして 122 ビットを表しており、1 文字あたり 3.4 ビットとなります。そのため、同じ識別子は 21 文字の base64url に収まります。残りの 15 文字が買っているのは可読性であり、情報ではありません。そして、パネルが提供する Base64URL デコードがテキストではなくバイナリとしてフラグが立てられて返されるのは、極めて明白な理由からです。そこには見つけ出すべきエンコードされた内容など最初から存在しなかったのです。

    n1/2=1.1772122=2.7×1018,⌈1226⌉=21n_{1/2}=1.177\sqrt{2^{122}}=2.7\times10^{18},\qquad\left\lceil\frac{122}{6}\right\rceil=21
参考文献 (1)