Upload a file
  1. base64hub
  2. Base64 in Code
  3. C#
Code

Base64 in C#

System.Convert has done Base64 since .NET Framework 1.0, and .NET 9 added System.Buffers.Text.Base64Url for URL-safe strings. Outputs below come from .NET 9.

Encode and decode a string

Convert works with bytes, so pick an encoding explicitly. For anything that leaves your process, that is almost always 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 is UTF-16LE and doubles the size of ASCII text. It is the right choice only when the other side expects UTF-16, for example the PowerShell encoded command format.

A common real use is the HTTP Basic Auth header:

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

The Basic Auth header generator produces the same value in the browser.

URL-safe Base64: Base64Url in .NET 9

.NET 9 added System.Buffers.Text.Base64Url. It encodes without padding and decodes with or without it:

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

It rejects the standard alphabet: Base64Url.DecodeFromChars("PDw/Pz8+Pg") throws FormatException. There are also span-based overloads (EncodeToChars, DecodeFromUtf8, TryDecodeFromChars) that avoid allocations.

On older runtimes without the Microsoft.Bcl.Memory package, convert manually:

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

Decoding needs the reverse replacements plus padding to a multiple of 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 projects can use WebEncoders.Base64UrlEncode from Microsoft.AspNetCore.WebUtilities instead. More on the two alphabets in Base64 vs Base64URL.

Validating input without exceptions

Convert.FromBase64String throws System.FormatException on bad input. On .NET 9 the message is the same for almost every case:

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.

We got that message for PDw_Pz8-Pg== (URL-safe), aGk=!! (junk), aGk (no padding), a and aGk==. It accepts whitespace (" aGk= " and "aGVs\nbG8K" decode fine) and non-zero padding bits (aGl=).

To avoid exceptions in hot paths, use the Try variant with a buffer, or 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

The buffer must be large enough for the decoded output, or TryFromBase64String returns false even for valid input. Size it as (s.Length * 3) / 4. The Base64 validator and the errors guide help with strings that fail.

Line breaks (MIME)

Base64FormattingOptions.InsertLineBreaks wraps output at 76 characters with \r\n, without a trailing newline:

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

FromBase64String accepts the wrapped form back without changes. The MIME Base64 encoder produces the same layout.

Encode and decode a file

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

Large files with CryptoStream

ToBase64Transform and FromBase64Transform plug into a CryptoStream, which keeps memory flat. Despite the namespace, no cryptography is involved:

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

Disposing the CryptoStream flushes the final block and padding; skipping it truncates the output. On a 300 KB test file both directions matched the in-memory result. For a quick manual check, open the result with Base64 to file.

Common pitfalls

  • Data URI prefixes. data:image/png;base64, contains : and ;, which trigger FormatException. Strip everything up to the comma.
  • URL-safe tokens in Convert. JWT parts fail with the generic message above. Use Base64Url or the JWT decoder.
  • Encoding.Default. On .NET Framework it is the ANSI code page; on .NET Core and later it is UTF-8. Code moved between the two changes output for non-ASCII text.
  • Base64 is not encryption. Connection strings “protected” with Base64 are plain text to anyone. See encoding vs encryption.

Version notes

  • .NET Framework 1.0+: Convert.ToBase64String, FromBase64String, ToBase64Transform.
  • .NET Core 2.1+: span overloads Convert.TryFromBase64String, TryToBase64Chars and the UTF-8 System.Buffers.Text.Base64 class.
  • .NET 8: Base64.IsValid.
  • .NET 9: Base64Url, also available for older targets through Microsoft.Bcl.Memory.

FAQ

How do I fix 'The input is not a valid Base-64 string'?

Check for URL-safe characters (-, _), missing padding and data URI prefixes. Convert.FromBase64String accepts only the standard alphabet with correct padding. For tokens, use Base64Url.DecodeFromChars on .NET 9, which accepts both padded and unpadded input.

Can I use Base64Url on .NET 8 or .NET Framework?

Base64Url is built into .NET 9 and later. For older targets, Microsoft ships the same type in the Microsoft.Bcl.Memory package. Without it, convert the standard output with TrimEnd('=') and two Replace calls.

Why is Encoding.Unicode wrong for Base64 of text?

Encoding.Unicode is UTF-16LE, so hi becomes aABpAA== instead of aGk=. Use Encoding.UTF8 unless the receiver expects UTF-16, as PowerShell’s -EncodedCommand does.

Keep reading