文字列のエンコードとデコード
Convert はバイト列を扱うので、エンコーディングは明示的に選んでください。プロセスの外に出るデータなら、ほぼ必ず UTF-8 です。
using System.Text;
string enc = Convert.ToBase64String(Encoding.UTF8.GetBytes("héllo wörld"));
Console.WriteLine(enc); // aMOpbGxvIHfDtnJsZA==
string dec = Encoding.UTF8.GetString(Convert.FromBase64String(enc));
Console.WriteLine(dec); // héllo wörld
Encoding.Unicode は UTF-16LE で、ASCII テキストのサイズが 2 倍になります。これが正しいのは、PowerShell のエンコードされたコマンド 形式のように、相手が UTF-16 を想定している場合だけです。
実際によく使うのが、HTTP の Basic 認証ヘッダーです。
string token = Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass"));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
// Authorization: Basic dXNlcjpwYXNz
Basic Auth ヘッダージェネレーター を使えば、同じ値をブラウザで生成できます。
URLセーフな Base64:.NET 9 の Base64Url
.NET 9 で System.Buffers.Text.Base64Url が追加されました。エンコード時はパディングを付けず、デコード時はパディングの有無を問いません。
using System.Buffers.Text;
byte[] d = Encoding.UTF8.GetBytes("<<???>>");
Console.WriteLine(Base64Url.EncodeToString(d)); // PDw_Pz8-Pg
byte[] a = Base64Url.DecodeFromChars("PDw_Pz8-Pg"); // <<???>>
byte[] b = Base64Url.DecodeFromChars("PDw_Pz8-Pg=="); // <<???>>
標準アルファベットは拒否します。Base64Url.DecodeFromChars("PDw/Pz8+Pg") は FormatException をスローします。アロケーションを避けられる Span ベースのオーバーロード(EncodeToChars、DecodeFromUtf8、TryDecodeFromChars)もあります。
Microsoft.Bcl.Memory パッケージのない古いランタイムでは、手動で変換します。
string url = Convert.ToBase64String(d)
.TrimEnd('=').Replace('+', '-').Replace('/', '_'); // PDw_Pz8-Pg
デコードには逆の置き換えと、4 の倍数になるまでのパディングが必要です。
static byte[] FromBase64Url(string s)
{
s = s.Replace('-', '+').Replace('_', '/');
s = s.PadRight(s.Length + (4 - s.Length % 4) % 4, '=');
return Convert.FromBase64String(s);
}
Encoding.UTF8.GetString(FromBase64Url("PDw_Pz8-Pg")); // <<???>>
ASP.NET Core のプロジェクトなら、代わりに Microsoft.AspNetCore.WebUtilities の WebEncoders.Base64UrlEncode を使えます。2 つのアルファベットについて詳しくは Base64 と Base64URL の違い をご覧ください。
例外を使わずに入力を検証する
Convert.FromBase64String は不正な入力に対して System.FormatException をスローします。.NET 9 では、ほぼどのケースでも同じメッセージです。
The input is not a valid Base-64 string as it contains a non-base 64 character,
more than two padding characters, or an illegal character among the padding characters.
このメッセージは、PDw_Pz8-Pg==(URLセーフ)、aGk=!!(ゴミ文字)、aGk(パディングなし)、a、aGk== のいずれでも表示されました。一方、空白(" aGk= " と "aGVs\nbG8K" は問題なくデコードされます)や、0 でないパディングビット(aGl=)は受け付けます。
ホットパスで例外を避けたいなら、バッファを渡す Try 版か、Base64.IsValid(.NET 8 以降)を使ってください。
Span<byte> buf = stackalloc byte[16];
Convert.TryFromBase64String("aGk=", buf, out int n); // True, n = 2
Convert.TryFromBase64String("aGk", buf, out n); // False, n = 0
System.Buffers.Text.Base64.IsValid("aGk="); // True
System.Buffers.Text.Base64.IsValid("aGk"); // False
Base64Url.IsValid("PDw_Pz8-Pg"); // True
バッファはデコード結果が収まる大きさが必要で、足りないと有効な入力でも TryFromBase64String が false を返します。サイズは (s.Length * 3) / 4 にしてください。デコードに失敗する文字列には、Base64 バリデーター と エラーの解説 が役立ちます。
改行(MIME)
Base64FormattingOptions.InsertLineBreaks を指定すると、出力を \r\n で 76 文字ごとに折り返します。末尾には改行が付きません。
string mime = Convert.ToBase64String(
Encoding.ASCII.GetBytes(new string('x', 60)),
Base64FormattingOptions.InsertLineBreaks);
// "eHh4eHh4...eHh4" (76 chars) + "\r\n" + "eHh4"
FromBase64String は、折り返された形式をそのまま受け付けます。MIME Base64 エンコーダー も同じレイアウトで出力します。
ファイルのエンコードとデコード
Console.WriteLine(Convert.ToBase64String(File.ReadAllBytes("hello.txt"))); // aGVsbG8K
File.WriteAllBytes("copy.txt", Convert.FromBase64String("aGVsbG8K"));
CryptoStream で大きなファイルを扱う
ToBase64Transform と FromBase64Transform は CryptoStream に組み込めるので、メモリ使用量が一定に保たれます。名前空間はそれらしいですが、暗号処理は一切行われません。
using System.Security.Cryptography;
using (var input = File.OpenRead("big.bin"))
using (var output = File.Create("big.b64"))
using (var b64 = new CryptoStream(output, new ToBase64Transform(), CryptoStreamMode.Write))
{
input.CopyTo(b64);
}
using (var input = new CryptoStream(File.OpenRead("big.b64"),
new FromBase64Transform(), CryptoStreamMode.Read))
using (var output = File.Create("big.out"))
{
input.CopyTo(output);
}
CryptoStream を Dispose すると最後のブロックとパディングが書き出されます。これを省くと出力が途中で切れます。300 KB のテストファイルでは、両方向とも、メモリ上で変換した結果と一致しました。手早く確認したいときは、結果を Base64 からファイルへの変換 で開いてください。
よくある落とし穴
- Data URI の接頭辞。
data:image/png;base64,には:と;が含まれ、FormatExceptionの原因になります。カンマまでをすべて取り除いてください。 - URLセーフなトークンを
Convertに渡す。 JWT の各パートは上記の汎用メッセージで失敗します。Base64Urlか JWT デコーダー を使ってください。 Encoding.Default。 .NET Framework では ANSI コードページ、.NET Core 以降では UTF-8 です。両者の間でコードを移すと、非 ASCII テキストの出力が変わります。- Base64 は暗号化ではありません。 Base64 で「保護」された接続文字列は、誰が見ても平文と同じです。エンコードと暗号化の違い をご覧ください。
バージョンごとの注意
- .NET Framework 1.0 以降:
Convert.ToBase64String、FromBase64String、ToBase64Transform - .NET Core 2.1 以降:Span 版オーバーロードの
Convert.TryFromBase64String、TryToBase64Chars、UTF-8 用のSystem.Buffers.Text.Base64クラス - .NET 8:
Base64.IsValid - .NET 9:
Base64Url(古いターゲットでもMicrosoft.Bcl.Memory経由で利用可能)
よくある質問
「The input is not a valid Base-64 string」を直すには?
URLセーフの文字(-、_)、パディングの不足、Data URI の接頭辞がないか確認してください。Convert.FromBase64String が受け付けるのは、正しくパディングされた標準アルファベットだけです。トークンには .NET 9 の Base64Url.DecodeFromChars を使えば、パディングの有無にかかわらずデコードできます。
.NET 8 や .NET Framework でも Base64Url を使えますか?
Base64Url は .NET 9 以降に組み込まれています。それより古いターゲット向けには、Microsoft が同じ型を Microsoft.Bcl.Memory パッケージで提供しています。パッケージを使わない場合は、標準の出力を TrimEnd('=') と 2 回の Replace で変換してください。
テキストの Base64 に Encoding.Unicode を使うのが間違いなのはなぜですか?
Encoding.Unicode は UTF-16LE なので、hi が aGk= ではなく aABpAA== になります。PowerShell の -EncodedCommand のように受け取り側が UTF-16 を想定している場合を除き、Encoding.UTF8 を使ってください。