Codificar y decodificar una cadena
Convert trabaja con bytes, así que elige una codificación de forma explícita. Para cualquier cosa que salga de tu proceso, casi siempre será 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 es UTF-16LE y duplica el tamaño del texto ASCII. Solo es la opción correcta cuando el otro extremo espera UTF-16, por ejemplo con el formato de comando codificado de PowerShell.
Un uso real habitual es la cabecera HTTP Basic Auth:
string token = Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass"));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);
// Authorization: Basic dXNlcjpwYXNz
El generador de cabeceras Basic Auth produce el mismo valor en el navegador.
Base64 URL-safe: Base64Url en .NET 9
.NET 9 añadió System.Buffers.Text.Base64Url. Codifica sin relleno y decodifica con o sin él:
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=="); // <<???>>
Rechaza el alfabeto estándar: Base64Url.DecodeFromChars("PDw/Pz8+Pg") lanza FormatException. También hay sobrecargas basadas en spans (EncodeToChars, DecodeFromUtf8, TryDecodeFromChars) que evitan asignaciones de memoria.
En runtimes antiguos sin el paquete Microsoft.Bcl.Memory, convierte a mano:
string url = Convert.ToBase64String(d)
.TrimEnd('=').Replace('+', '-').Replace('/', '_'); // PDw_Pz8-Pg
Para decodificar hacen falta los reemplazos inversos y rellenar hasta un 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")); // <<???>>
Los proyectos ASP.NET Core pueden usar en su lugar WebEncoders.Base64UrlEncode de Microsoft.AspNetCore.WebUtilities. Más sobre los dos alfabetos en Base64 frente a Base64URL.
Validar la entrada sin excepciones
Convert.FromBase64String lanza System.FormatException con una entrada incorrecta. En .NET 9 el mensaje es el mismo en casi todos los 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.
Obtuvimos ese mensaje con PDw_Pz8-Pg== (URL-safe), aGk=!! (basura), aGk (sin relleno), a y aGk==. Acepta espacios en blanco (" aGk= " y "aGVs\nbG8K" se decodifican bien) y bits de relleno distintos de cero (aGl=).
Para evitar excepciones en las rutas críticas, usa la variante Try con un búfer, 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
El búfer debe ser lo bastante grande para la salida decodificada; si no, TryFromBase64String devuelve false incluso con una entrada válida. Dimensiónalo como (s.Length * 3) / 4. El validador Base64 y la guía de errores ayudan con las cadenas que fallan.
Saltos de línea (MIME)
Base64FormattingOptions.InsertLineBreaks corta la salida a 76 caracteres con \r\n, sin salto de línea final:
string mime = Convert.ToBase64String(
Encoding.ASCII.GetBytes(new string('x', 60)),
Base64FormattingOptions.InsertLineBreaks);
// "eHh4eHh4...eHh4" (76 chars) + "\r\n" + "eHh4"
FromBase64String vuelve a aceptar la forma con cortes sin cambios. El codificador Base64 MIME genera la misma disposición.
Codificar y decodificar un archivo
Console.WriteLine(Convert.ToBase64String(File.ReadAllBytes("hello.txt"))); // aGVsbG8K
File.WriteAllBytes("copy.txt", Convert.FromBase64String("aGVsbG8K"));
Archivos grandes con CryptoStream
ToBase64Transform y FromBase64Transform se conectan a un CryptoStream, que mantiene estable el uso de memoria. A pesar del espacio de nombres, no interviene ninguna criptografía:
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);
}
Al liberar el CryptoStream se vuelcan el último bloque y el relleno; si te lo saltas, la salida queda truncada. Con un archivo de prueba de 300 KB, las dos direcciones coincidieron con el resultado en memoria. Para una comprobación manual rápida, abre el resultado con Base64 a archivo.
Errores habituales
- Prefijos de data URI.
data:image/png;base64,contiene:y;, que provocanFormatException. Quita todo lo que haya hasta la coma. - Tokens URL-safe en
Convert. Las partes de un JWT fallan con el mensaje genérico de arriba. UsaBase64Urlo el decodificador JWT. Encoding.Default. En .NET Framework es la página de códigos ANSI; en .NET Core y posteriores es UTF-8. El código que pasa de uno a otro cambia la salida con texto no ASCII.- Base64 no es cifrado. Las cadenas de conexión «protegidas» con Base64 son texto plano para cualquiera. Consulta codificación frente a cifrado.
Notas de versión
- .NET Framework 1.0+:
Convert.ToBase64String,FromBase64String,ToBase64Transform. - .NET Core 2.1+: las sobrecargas con spans
Convert.TryFromBase64String,TryToBase64Charsy la clase UTF-8System.Buffers.Text.Base64. - .NET 8:
Base64.IsValid. - .NET 9:
Base64Url, también disponible para versiones anteriores medianteMicrosoft.Bcl.Memory.
Preguntas frecuentes
¿Cómo soluciono «The input is not a valid Base-64 string»?
Busca caracteres URL-safe (-, _), relleno que falta y prefijos de data URI. Convert.FromBase64String solo acepta el alfabeto estándar con el relleno correcto. Para tokens, usa Base64Url.DecodeFromChars en .NET 9, que acepta entradas con y sin relleno.
¿Puedo usar Base64Url en .NET 8 o .NET Framework?
Base64Url viene integrado en .NET 9 y posteriores. Para versiones anteriores, Microsoft distribuye el mismo tipo en el paquete Microsoft.Bcl.Memory. Sin él, convierte la salida estándar con TrimEnd('=') y dos llamadas a Replace.
¿Por qué Encoding.Unicode no sirve para el Base64 de un texto?
Encoding.Unicode es UTF-16LE, así que hi se convierte en aABpAA== en lugar de aGk=. Usa Encoding.UTF8 salvo que el receptor espere UTF-16, como hace el -EncodedCommand de PowerShell.