Закодировать и декодировать строку
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-текста. Он подходит, только когда другая сторона ждёт UTF-16, например в формате закодированной команды PowerShell.
Частый практический случай: заголовок HTTP Basic Auth.
string token = Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass"));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
// Authorization: Basic dXNlcjpwYXNz
Генератор заголовка Basic Auth выдаёт такое же значение прямо в браузере.
URL-safe Base64: Base64Url в .NET 9
В .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 можно вместо этого взять WebEncoders.Base64UrlEncode из Microsoft.AspNetCore.WebUtilities. Подробнее о двух алфавитах в статье 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-safe), aGk=!! (мусор), aGk (нет дополнения), a и aGk==. Пробелы метод допускает (" aGk= " и "aGVs\nbG8K" декодируются нормально), как и ненулевые биты дополнения (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 переносит вывод через каждые 76 символов с \r\n, без перевода строки в конце:
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 сбрасывает последний блок и дополнение; без него вывод окажется обрезанным. На тестовом файле в 300 КБ оба направления совпали с результатом преобразования в памяти. Для быстрой ручной проверки откройте результат инструментом Base64 в файл.
Частые подводные камни
- Префиксы data URI. В
data:image/png;base64,есть:и;, на которых возникаетFormatException. Отрежьте всё до запятой включительно. - URL-safe токены в
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и классSystem.Buffers.Text.Base64для UTF-8. - .NET 8:
Base64.IsValid. - .NET 9:
Base64Url, для старых платформ также доступен черезMicrosoft.Bcl.Memory.
Вопросы и ответы
Как исправить ошибку «The input is not a valid Base-64 string»?
Проверьте, нет ли во входных данных URL-safe символов (-, _), не пропущено ли дополнение и нет ли префикса data URI. Convert.FromBase64String принимает только стандартный алфавит с правильным дополнением. Для токенов в .NET 9 берите Base64Url.DecodeFromChars: он принимает строки и с дополнением, и без.
Можно ли использовать Base64Url в .NET 8 или .NET Framework?
Base64Url встроен в .NET 9 и новее. Для более старых платформ Microsoft поставляет тот же тип в пакете Microsoft.Bcl.Memory. Без него преобразуйте стандартный результат через TrimEnd('=') и два вызова Replace.
Почему Encoding.Unicode не подходит для Base64 от текста?
Encoding.Unicode – это UTF-16LE, поэтому hi превращается в aABpAA== вместо aGk=. Используйте Encoding.UTF8, если только получатель не ждёт UTF-16, как -EncodedCommand в PowerShell.