AIでBase64変換を作る方法|文字・バイト・復元結果を照合

日本語短文と2バイトの例でUTF-8、標準Base64、URL-safe、パディングを分けて検算。復元と文字解釈、受入契約の違いを確認します。

AIものさし編集部

AIが作った連携コードでBase64を使うときは、元の文字列、文字コードで変換したバイト列、Base64文字列を分けます。文字数とバイト数は同じとは限らず、Base64から戻せても、戻したバイト列がUTF-8の文章とは限りません。

この記事では、日本語を含む架空の短文と、説明用の2バイトをローカルで変換します。標準Base64とURL-safeの違い、パディング、元バイト列への復元を確かめる例です。実ファイルの送信、API接続、認証、AIサービス、画面表示は検証していません。

元の文字列と、送るバイト列を決める

文字列の例は「赤A」です。UTF-8へ変換すると、赤は3バイト、Aは1バイトで合計4バイトになります。画面上の2文字という数を、そのままデータサイズには使いません。

表は横にスクロールできます

段階値長さの意味
元文字列赤Aこの例のPython文字列では2文字
UTF-8バイト列e8 b5 a4 414バイト
標準Base646LWkQQ==ASCIIの8文字
復元したバイト列e8 b5 a4 41元の4バイトと一致
UTF-8で読んだ文字列赤A元の文字列と一致

Base64はバイト列を文字で表現する符号化です。暗号化ではなく、機密性を与えません。RFC 4648も、見た目を変えても情報を秘匿できない点を説明しています。認証情報をBase64にしたから共有できるとは扱わないでください。RFC 4648:Security Considerations(新しいタブで開く)

この例は説明用の文字列だけを使います。既存の認証値や実際の顧客データを読み取って変換する手順ではありません。

文字列はUTF-8へ変換してからBase64にする

Pythonのbase64モジュールは、バイト列をBase64へ変換し、復号時もバイト列を返します。文字として読みたい場合は、その後で文字コードを指定します。Python 3.9公式:base64(新しいタブで開く)

import base64

text = "赤A"
raw = text.encode("utf-8")
encoded = base64.b64encode(raw).decode("ascii")
restored = base64.b64decode(encoded, validate=True)
restored_text = restored.decode("utf-8")

assert raw.hex() == "e8b5a441"
assert encoded == "6LWkQQ=="
assert restored == raw
assert restored_text == text
print(len(text), len(raw), len(encoded))
print(encoded, restored.hex(), restored_text)

今回の長さは2、4、8です。復元前後を比較する対象はまずバイト列です。文字として扱う場合だけ、同じUTF-8の条件で文字列まで照合します。改行を足す、文字コードを変える、Unicodeを正規化する操作は、この往復変換に勝手に加えません。

Base64をもう一度Base64へ変換すれば、表現の階層が一段増えます。一度戻しても元の文章へ届かない場合は、何回か復号して読めるまで試す前に、入力契約と各段階の型を確認してください。

末尾のイコールと、文字数の増加を確認する

ここでは、改行のない標準Base64で、必要なパディングを付けます。元がnバイトなら文字数は4 × ceil(n / 3)です。nが0なら0文字です。元サイズの端数によって増え方が変わるため、小さい値で「常にぴったり4/3倍」と計算しません。

表は横にスクロールできます

元バイト数Base64の文字数末尾のパディング数
000
142
241
340
482

例えば1バイトのASCII文字fはZg==、2バイトのfoはZm8=、3バイトのfooはZm9vになります。これらはRFC 4648のテストベクトルでも確認できます。RFC 4648:Test Vectors(新しいタブで開く)

この文字数は、今回のBase64部分だけの長さです。JSONのキー、引用符、Data URLの接頭辞、HTTPヘッダー、改行などは含みません。アップロードや保存の制限を調べるときは、どの段階のサイズを制限しているかを確認します。

標準Base64とURL-safeを混ぜない

説明用のバイト列fb ffは、文章ではない2バイトです。標準Base64では+/8=、URL-safeでは-_8=になります。URL-safeは標準のプラスとスラッシュを、それぞれハイフンとアンダースコアへ置き換えた文字集合を使います。この例ではパディングも残します。

URL-safeという名前でも、すべての受け取り先がパディング付き・なしの両方を受け付けるとは限りません。送信先が指定する形式を先に決め、見た目だけで標準とURL-safeを自動判別する前提にしません。

fb ffをBase64から元へ戻せても、そのバイト列をUTF-8として読むとこの例ではエラーになります。Base64の復元成功と、文字コードとしての解釈成功は別の確認です。画像や圧縮データなどのバイナリを、必ず文章としてdecodeする設計にはしません。

厳格に受け取る範囲を、例の契約として決める

次は、この説明用に「標準Base64、必要なパディングあり、空白・改行なし、同じバイト列を再符号化した表記と完全一致」という契約で読む関数です。空の入力は空バイト列として受け付けます。

import base64

def decode_canonical_standard(value):
    if not isinstance(value, str):
        raise ValueError("expected an ASCII string")
    try:
        value.encode("ascii")
        raw = base64.b64decode(value, validate=True)
    except (ValueError, UnicodeError) as exc:
        raise ValueError("invalid standard Base64") from exc
    if base64.b64encode(raw).decode("ascii") != value:
        raise ValueError("noncanonical representation")
    return raw

この契約では、不要な空白を勝手に削ったり、足りないパディングを補ったりしません。受け取り先が別形式を指定している場合は、その仕様に合う処理を別に作ります。

validate=Trueで文字集合やパディングを検査しても、すべての表記の正規性を確認したことにはしません。この例のPython 3.9環境では、Zh==もfのバイトへ戻りますが、再符号化結果はZg==なので、この関数では拒否します。意味のある入力バイトの後にあるパディング用ビットの違いを、表記比較で見つける例です。

この関数は、任意の巨大入力への資源制限や、認証の正しさを検証する実装ではありません。形式を満たした文字列を受け付けたことから、その内容が信頼できるとは判断しません。

AIには、変換ごとの型と検証範囲を返させる

説明用のデータをBase64へ変換するコードを作ってください。
入力は生の文字列で、文字コードはUTF-8です。
形式は標準Base64、必要なパディングあり、改行なしです。
出力:元文字列、UTF-8バイト列の16進表記、Base64、復元バイト列、照合結果。
文字数・元バイト数・Base64文字数を分けてください。
復元したバイト列を文字列へ戻す場合は、文字コードを明記してください。
勝手な正規化、改行追加、繰り返し復号はしないでください。
Base64を暗号化や認証確認と説明しないでください。
外部へ送信せず、実行した検査と未実施の検査を分けてください。
入力:[架空の短い文字列]。

今回は掲載コード、元バイト列の保持、サイズの式、標準とURL-safeの例、文章として読めないバイト列、例の受入契約をローカルで確認しました。実APIのフィールド仕様、Data URL、ファイル送信、秘密情報の保護を検証したものではありません。

参考資料

公式資料の確認日:2026年10月20日。掲載コードはローカルのPython 3.9環境で検査しました。最新版Pythonだけの追加引数は使っていません。外部送信、認証、AIサービス、画面表示は未検証です。

質問から自分に合うAIを探す