Skip to content

Base64 Encode / Decode — C# source

Encode text to Base64 or decode it back. UTF-8 safe, runs entirely in your browser, with a shareable link to your exact input.

This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.

// base64 — UTF-8 safe Base64 encode/decode.
//
// Language: C# (C# 12 / .NET 8, standard library only — System.Convert is
//           the RFC 4648 codec, the same role the base64 module plays in
//           this tool's python.py)
// Source:   CosmoDev polyglot showcase port of the `base64` tool, ported
//           from src/lib/base64.ts (the canonical TypeScript implementation).
// License:  display source — part of CosmoDev's polyglot tool pages.
//
// Two details keep the stdlib route faithful to the TS contract:
//   - whitespace is stripped with the same \s+ regex the TS port uses before
//     decoding, so line-wrapped Base64 decodes cleanly;
//   - decoded bytes must form valid UTF-8: a strict UTF8Encoding with
//     throwOnInvalidUTF8Bytes: true, because Encoding.UTF8.GetString would
//     silently substitute U+FFFD for malformed sequences.
//
// Build: csc csharp.cs && base64.exe   (or drop into any .NET 8 console)

using System;
using System.Text;
using System.Text.RegularExpressions;

namespace CosmoDev.Polyglot;

/// <summary>UTF-8 safe Base64 encode/decode — pure logic, no I/O.</summary>
public static class Base64Tool
{
    /// <summary>Matches the TS port's \s+ — every run of whitespace collapses to nothing.</summary>
    private static readonly Regex WhitespaceRun = new(@"\s+", RegexOptions.Compiled);

    /// <summary>
    /// Strict UTF-8: throws DecoderFallbackException on malformed bytes instead
    /// of silently substituting U+FFFD.
    /// </summary>
    private static readonly UTF8Encoding StrictUtf8 = new(
        encoderShouldEmitUTF8Identifier: false, throwOnInvalidUTF8Bytes: true);

    /// <summary>
    /// Encode a Unicode string to standard (padded) Base64. The string is
    /// first encoded to UTF-8 bytes so characters outside Latin-1 (emoji,
    /// accents, CJK, ...) survive the round trip.
    /// </summary>
    public static string B64Encode(string text) =>
        Convert.ToBase64String(StrictUtf8.GetBytes(text));

    /// <summary>
    /// Decode standard Base64 back to the original Unicode text. Whitespace
    /// is stripped first; Convert.FromBase64String then rejects illegal
    /// characters and bad padding; finally the decoded bytes must be valid
    /// UTF-8. Any of those failures throws ArgumentException, matching the
    /// TS port's "throw on invalid input" contract.
    /// </summary>
    public static string B64Decode(string b64)
    {
        string cleaned = WhitespaceRun.Replace(b64, string.Empty);

        byte[] raw;
        try
        {
            raw = Convert.FromBase64String(cleaned);
        }
        catch (FormatException e)
        {
            throw new ArgumentException($"invalid Base64 input: {e.Message}", e);
        }

        try
        {
            return StrictUtf8.GetString(raw);
        }
        catch (DecoderFallbackException)
        {
            throw new ArgumentException("decoded bytes are not valid UTF-8");
        }
    }

    private static void Main()
    {
        Console.WriteLine(B64Encode("Hello, world!"));        // SGVsbG8sIHdvcmxkIQ==

        Console.WriteLine(B64Decode("aGVs\nbG8g d29ybGQ="));  // hello world

        Console.WriteLine(B64Decode(B64Encode("héllo 🌍")));   // multi-byte UTF-8 survives

        try { B64Decode("SGVsbG8*"); }
        catch (ArgumentException e) { Console.WriteLine(e.Message); }

        // "/w==" decodes to the single byte 0xFF, which is not valid UTF-8.
        try { B64Decode("/w=="); }
        catch (ArgumentException e) { Console.WriteLine(e.Message); }
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →