Enviar um arquivo
  1. base64hub
  2. Base64 no código
  3. C#
Código

Base64 em C#

O System.Convert faz Base64 desde o .NET Framework 1.0, e o .NET 9 acrescentou o System.Buffers.Text.Base64Url para strings URL-safe. As saídas abaixo vêm do .NET 9.

Codificar e decodificar uma string

O Convert trabalha com bytes, então escolha uma codificação de forma explícita. Para qualquer coisa que saia do seu processo, ela quase sempre é 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 e dobra o tamanho de texto ASCII. Só é a escolha certa quando o outro lado espera UTF-16, por exemplo no formato de comando codificado do PowerShell.

Um uso real comum é o header HTTP Basic Auth:

string token = Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass"));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
// Authorization: Basic dXNlcjpwYXNz

O gerador de header Basic Auth gera o mesmo valor no navegador.

Base64 URL-safe: Base64Url no .NET 9

O .NET 9 acrescentou o System.Buffers.Text.Base64Url. Ele codifica sem preenchimento e decodifica com ou sem ele:

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==");      // <<???>>

Ele rejeita o alfabeto padrão: Base64Url.DecodeFromChars("PDw/Pz8+Pg") lança FormatException. Também há sobrecargas com spans (EncodeToChars, DecodeFromUtf8, TryDecodeFromChars) que evitam alocações.

Em runtimes mais antigos sem o pacote Microsoft.Bcl.Memory, converta à mão:

string url = Convert.ToBase64String(d)
    .TrimEnd('=').Replace('+', '-').Replace('/', '_');    // PDw_Pz8-Pg

Para decodificar, é preciso fazer as trocas inversas e completar com preenchimento até um múltiplo de 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"));   // <<???>>

Projetos ASP.NET Core podem usar o WebEncoders.Base64UrlEncode do Microsoft.AspNetCore.WebUtilities. Mais sobre os dois alfabetos em Base64 vs Base64URL.

Validar a entrada sem exceções

O Convert.FromBase64String lança System.FormatException para entrada inválida. No .NET 9, a mensagem é a mesma em quase todos os casos:

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.

Recebemos essa mensagem para PDw_Pz8-Pg== (URL-safe), aGk=!! (lixo), aGk (sem preenchimento), a e aGk==. Ele aceita espaços em branco (" aGk= " e "aGVs\nbG8K" decodificam normalmente) e bits de preenchimento diferentes de zero (aGl=).

Para evitar exceções em trechos críticos de desempenho, use a variante Try com um buffer, ou o 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

O buffer precisa ser grande o bastante para a saída decodificada, senão o TryFromBase64String retorna false mesmo para entrada válida. Dimensione-o como (s.Length * 3) / 4. O validador de Base64 e o guia de erros ajudam com strings que falham.

Quebras de linha (MIME)

O Base64FormattingOptions.InsertLineBreaks quebra a saída a cada 76 caracteres com \r\n, sem quebra de linha no final:

string mime = Convert.ToBase64String(
    Encoding.ASCII.GetBytes(new string('x', 60)),
    Base64FormattingOptions.InsertLineBreaks);
// "eHh4eHh4...eHh4" (76 chars) + "\r\n" + "eHh4"

O FromBase64String aceita a forma quebrada de volta sem alterações. O codificador Base64 MIME gera o mesmo layout.

Codificar e decodificar um arquivo

Console.WriteLine(Convert.ToBase64String(File.ReadAllBytes("hello.txt")));  // aGVsbG8K
File.WriteAllBytes("copy.txt", Convert.FromBase64String("aGVsbG8K"));

Arquivos grandes com CryptoStream

O ToBase64Transform e o FromBase64Transform se encaixam num CryptoStream, que mantém o uso de memória estável. Apesar do namespace, não há criptografia envolvida:

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);
}

Descartar o CryptoStream (Dispose) grava o último bloco e o preenchimento; sem isso, a saída fica truncada. Num arquivo de teste de 300 KB, as duas direções bateram com o resultado em memória. Para uma conferência manual rápida, abra o resultado com Base64 para arquivo.

Armadilhas comuns

  • Prefixos de data URI. data:image/png;base64, contém : e ;, que disparam FormatException. Remova tudo até a vírgula.
  • Tokens URL-safe no Convert. Partes de JWT falham com a mensagem genérica acima. Use o Base64Url ou o decodificador de JWT.
  • Encoding.Default. No .NET Framework é a code page ANSI; no .NET Core e posteriores é UTF-8. Código levado de um para o outro muda a saída para texto não ASCII.
  • Base64 não é criptografia. Connection strings “protegidas” com Base64 são texto puro para qualquer pessoa. Veja codificação vs criptografia.

Notas de versão

  • .NET Framework 1.0+: Convert.ToBase64String, FromBase64String, ToBase64Transform.
  • .NET Core 2.1+: sobrecargas com spans Convert.TryFromBase64String, TryToBase64Chars e a classe System.Buffers.Text.Base64 para UTF-8.
  • .NET 8: Base64.IsValid.
  • .NET 9: Base64Url, também disponível para versões mais antigas pelo Microsoft.Bcl.Memory.

Perguntas frequentes

Como resolver 'The input is not a valid Base-64 string'?

Procure caracteres URL-safe (-, _), preenchimento ausente e prefixos de data URI. O Convert.FromBase64String só aceita o alfabeto padrão com o preenchimento correto. Para tokens, use Base64Url.DecodeFromChars no .NET 9, que aceita entrada com e sem preenchimento.

Dá para usar o Base64Url no .NET 8 ou no .NET Framework?

O Base64Url vem embutido no .NET 9 e posteriores. Para versões mais antigas, a Microsoft distribui o mesmo tipo no pacote Microsoft.Bcl.Memory. Sem ele, converta a saída padrão com TrimEnd('=') e duas chamadas de Replace.

Por que Encoding.Unicode está errado para Base64 de texto?

Encoding.Unicode é UTF-16LE, então hi vira aABpAA== em vez de aGk=. Use Encoding.UTF8, a menos que o destinatário espere UTF-16, como faz o -EncodedCommand do PowerShell.

Continue lendo