Base64 Decode C# — Guide Convert.FromBase64String()

·Game Developer & Unity Engineer·Révisé parEmma Richardson·Publié

Utilisez le Décodeur Base64 en ligne gratuit directement dans votre navigateur — sans installation.

Essayer Décodeur Base64 en ligne en ligne →

Dans chaque projet .NET sur lequel j'ai travaillé, il a fallu à un moment décoder du Base64 — extraire des chaînes de connexion depuis des secrets Kubernetes, lire des payloads binaires provenant de webhooks, ou inspecter des tokens JWT en session de débogage. Pour décoder du Base64 en C#, la méthode principale est Convert.FromBase64String(), qui retourne un byte[] que tu passes ensuite à Encoding.UTF8.GetString() pour obtenir du texte lisible. Pour une vérification rapide sans écrire de code, le décodeur Base64 de ToolDeck le fait instantanément dans le navigateur. Ce guide couvre Convert.FromBase64String(), le TryFromBase64String()basé sur les spans pour .NET 5+, l'API haute performance System.Buffers.Text.Base64, l'extraction de payload JWT, le décodage de fichiers et de réponses API, le streaming avec CryptoStream, et les quatre erreurs qui piègent le plus souvent les développeurs C#.

  • Convert.FromBase64String(s) + Encoding.UTF8.GetString(bytes) est le pipeline standard en deux étapes — fonctionne sur toutes les versions .NET.
  • Convert.TryFromBase64String() évite les exceptions sur une entrée invalide et écrit dans un Span<byte> — idéal pour les chemins critiques sur .NET 5+.
  • System.Buffers.Text.Base64.DecodeFromUtf8() offre un décodage sans allocation pour les tampons d'octets UTF-8 dans les services à haute performance.
  • Les tokens JWT utilisent Base64url (- et _ au lieu de + et /) — tu dois normaliser l'entrée avant d'appeler Convert.FromBase64String().
  • CryptoStream avec FromBase64Transform gère le décodage en streaming pour les grands fichiers sans tout charger en mémoire.

Qu'est-ce que le décodage Base64 ?

L'encodage Base64 convertit des données binaires en un alphabet ASCII de 64 caractères pour qu'elles survivent aux transports texte uniquement — champs JSON, en-têtes HTTP, corps d'e-mails, attributs XML. Chaque groupe de 3 octets d'entrée devient 4 caractères Base64, d'où le fait que la sortie Base64 est toujours environ 33 % plus grande que l'original. Le décodage inverse cette transformation. Le caractère =de padding en fin de chaîne indique au décodeur combien d'octets retrancher du dernier groupe. Un seul = signifie que le dernier bloc avait 2 octets ; ==signifie qu'il en avait 1. Base64 n'est pas du chiffrement — n'importe qui peut l'inverser. L'objectif est le transport sûr à travers des canaux qui altèrent le binaire brut, pas la confidentialité.

Before · text
After · text
cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ==
redis://cache-prod.internal:6379/session-store

Convert.FromBase64String() — La méthode de décodage standard

La méthode Convert.FromBase64String()existe dans .NET depuis les premiers jours du Framework 1.1. Pas de package NuGet, pas d'import supplémentaire au-delà de System— il suffit de l'appeler pour récupérer un byte[]. Le pipeline en deux étapes pour décoder du Base64 en chaîne C# est toujours le même : Convert.FromBase64String() pour obtenir les octets, puis Encoding.UTF8.GetString() pour interpréter ces octets comme du texte. Le point délicat est que la méthode retourne des octets bruts, pas une chaîne. Tu dois choisir le bon Encodingpour convertir ces octets en texte, et ce choix compte plus que la plupart des gens ne le pensent. Un encodage mal assorti produit silencieusement du mojibake — des caractères corrompus sans exception pour t'en avertir.

Exemple minimal fonctionnel

C# (.NET 6+)
using System;
using System.Text;

// Chaîne de connexion stockée en Base64 dans un secret Kubernetes
string encoded = "cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ==";

byte[] decodedBytes = Convert.FromBase64String(encoded);
string connectionString = Encoding.UTF8.GetString(decodedBytes);

Console.WriteLine(connectionString);
// redis://cache-prod.internal:6379/session-store

Utilise toujours Encoding.UTF8 sauf si tu as une raison précise de ne pas le faire. Le runtime .NET représente les chaînes en UTF-16 en interne, mais la plupart des données qui traversent les frontières système (réponses API, fichiers de config, secrets) sont encodées en UTF-8. Utiliser Encoding.ASCII sur des données contenant des caractères multi-octets les remplace silencieusement par des ?— pas d'exception, juste une sortie corrompue.

Vérification aller-retour

C# (.NET 6+)
using System;
using System.Text;

string original = "postgres://db-admin:Kx8!mQ@db-prod.us-east-1.internal:5432/orders";

// Encodage
string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(original));
Console.WriteLine(encoded);
// cG9zdGdyZXM6Ly9kYi1hZG1pbjpLeDghbVFAZGItcHJvZC51cy1lYXN0LTEuaW50ZXJuYWw6NTQzMi9vcmRlcnM=

// Décodage
byte[] decoded = Convert.FromBase64String(encoded);
string recovered = Encoding.UTF8.GetString(decoded);

Console.WriteLine(recovered == original); // True

Choisir le bon Encoding

L'Encoding que tu passes à GetString()doit correspondre à celui utilisé lors de l'encodage initial des données. Choisis le mauvais et tu obtiens des caractères parasites sans aucune exception — le décodeur produit joyeusement du charabia. Voici le résumé pratique :

  • Encoding.UTF8 — valeur par défaut sûre. Gère ASCII et tout Unicode. À utiliser sauf indication contraire.
  • Encoding.ASCII — uniquement pour les données ASCII 7-bit pures. Les caractères multi-octets deviennent des ?.
  • Encoding.Unicode — c'est UTF-16LE dans .NET. Certaines chaînes internes Windows et exports PowerShell l'utilisent.
  • Encoding.Latin1 — encodage Europe occidentale hérité. On le rencontre dans d'anciens services SOAP et des intégrations mainframe.
C# (.NET 6+)
using System;
using System.Text;

// Mêmes octets, encodages différents — résultats différents
byte[] decoded = Convert.FromBase64String("w7bDvMOk");

Console.WriteLine(Encoding.UTF8.GetString(decoded));    // öüä  (correct)
Console.WriteLine(Encoding.ASCII.GetString(decoded));   // ??????  (perdu)
Console.WriteLine(Encoding.Latin1.GetString(decoded));  // öüä  (mojibake)

Un helper de décodage réutilisable avec gestion des erreurs

Puisque Convert.FromBase64String() lève une exception sur une entrée invalide et que la suppression des espaces revient constamment, je garde un petit helper dans la plupart de mes projets :

C# (.NET 6+)
using System;
using System.Text;

static class Base64Helper
{
    public static string? DecodeToString(string encoded)
    {
        if (string.IsNullOrWhiteSpace(encoded))
            return null;

        // Supprimer les espaces que le décodeur .NET rejette
        string cleaned = encoded
            .Replace("
", "")
            .Replace("
", "")
            .Replace(" ", "")
            .Trim();

        try
        {
            byte[] bytes = Convert.FromBase64String(cleaned);
            return Encoding.UTF8.GetString(bytes);
        }
        catch (FormatException)
        {
            return null; // ou lever une exception spécifique au domaine
        }
    }
}

// Utilisation
string? decoded = Base64Helper.DecodeToString("  cmVkaXM6Ly9jYWNoZQ==  \n");
Console.WriteLine(decoded); // redis://cache
Remarque :Convert.FromBase64String() lève FormatExceptionsi l'entrée contient des caractères hors de l'alphabet Base64 — y compris les espaces, les sauts de ligne, et les caractères URL-safe comme - et _. Le helper ci-dessus gère automatiquement les espaces.

Décoder Base64 vers des types non standard

Le décodeur te donne toujours un byte[]. Ce que tu fais de ces octets dépend des données d'origine. Parfois c'est un GUID stocké en 16 octets bruts, parfois c'est un message protobuf sérialisé, parfois c'est un timestamp en format binaire. Voici les conversions que j'utilise le plus souvent.

Base64 vers GUID

C# (.NET 6+)
using System;

// Certaines API envoient les GUIDs en Base64 sur 22 chars au lieu de hex sur 36 chars
string compactGuid = "C0HqetxMckKlZw4CssPUeQ==";
byte[] guidBytes = Convert.FromBase64String(compactGuid);
Guid recovered = new Guid(guidBytes);

Console.WriteLine(recovered);
// 7aea41c0-4cdc-4272-a567-0e02b2c3d479

Base64 vers JSON désérialisé avec System.Text.Json

C# (.NET 6+)
using System;
using System.Text;
using System.Text.Json;

// Payload JSON encodé en Base64 provenant d'une file de messages
string encoded = "eyJzZXJ2aWNlIjoicGF5bWVudC1nYXRld2F5IiwicmVnaW9uIjoiZXUtd2VzdC0xIiwicmVwbGljYXMiOjR9";

byte[] jsonBytes = Convert.FromBase64String(encoded);
string json = Encoding.UTF8.GetString(jsonBytes);
Console.WriteLine(json);
// {"service":"payment-gateway","region":"eu-west-1","replicas":4}

// Désérialiser dans un record
var deployEvent = JsonSerializer.Deserialize<DeployEvent>(jsonBytes);
Console.WriteLine($"{deployEvent!.Service} in {deployEvent.Region}");
// payment-gateway in eu-west-1

record DeployEvent(string Service, string Region, int Replicas);

Base64 vers chaîne hexadécimale

C# (.NET 5+)
using System;

// Hash SHA-256 stocké en Base64
string hashBase64 = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=";
byte[] hashBytes = Convert.FromBase64String(hashBase64);
string hex = Convert.ToHexString(hashBytes);

Console.WriteLine(hex);
// 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08
Avertissement :Ne désérialise jamais des données Base64 non fiables avec BinaryFormatter. Il présente des vulnérabilités d'exécution de code à distance connues et est obsolète dans .NET 8+. Si le contenu encodé provient d'une source externe, parse-le en JSON ou protobuf plutôt qu'avec la sérialisation binaire .NET.

Référence des méthodes de décodage Base64

.NET propose plusieurs méthodes de décodage réparties dans deux espaces de noms. La classe Convert gère le décodage général, tandis que System.Buffers.Text.Base64 cible les scénarios à haut débit où tu travailles déjà avec des tampons d'octets UTF-8 bruts.

Méthode
Retourne
Type d'entrée
Description
Convert.FromBase64String(string)
byte[]
string
Décode une chaîne Base64 standard en tableau d'octets ; lève FormatException si l'entrée est invalide
Convert.TryFromBase64String(string, Span<byte>, out int)
bool
string + Span<byte>
Tente le décodage dans un Span fourni par l'appelant ; retourne false en cas d'échec au lieu de lever une exception (.NET 5+)
Convert.FromBase64CharArray(char[], int, int)
byte[]
char[] + offset + longueur
Décode un segment d'un tableau de char ; utile pour analyser des tampons sans créer de sous-chaînes
Convert.TryFromBase64Chars(ReadOnlySpan<char>, Span<byte>, out int)
bool
ReadOnlySpan<char> + Span<byte>
Décodage sans allocation basé sur Span à partir d'un char span (.NET 5+)
System.Buffers.Text.Base64.DecodeFromUtf8(ROSpan<byte>, Span<byte>, out int, out int, bool)
OperationStatus
ReadOnlySpan<byte> + Span<byte>
Décodage UTF-8 haute performance ; retourne l'enum OperationStatus (.NET Core 2.1+)
System.Buffers.Text.Base64.DecodeFromUtf8InPlace(Span<byte>, out int)
OperationStatus
Span<byte>
Décode en place, en écrasant le tampon d'entrée ; zéro allocation supplémentaire (.NET Core 2.1+)

Convert.TryFromBase64String() — Décodage sans exception

Le modèle Tryest standard dans .NET pour les opérations susceptibles d'échouer sur une entrée utilisateur. Convert.TryFromBase64String(), disponible depuis .NET 5, retourne un bool au lieu de lever FormatException. Il écrit les octets décodés dans un Span<byte>fourni par l'appelant, ce qui permet d'utiliser de la mémoire allouée sur la pile pour les petites charges et d'éviter complètement le tas.

C# (.NET 5+)
using System;
using System.Text;

string userInput = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=";

// Allouer sur la pile pour les petites charges (< 1 Ko est une règle de base sûre)
Span<byte> buffer = stackalloc byte[256];

if (Convert.TryFromBase64String(userInput, buffer, out int bytesWritten))
{
    string result = Encoding.UTF8.GetString(buffer[..bytesWritten]);
    Console.WriteLine(result);
    // {"host":"10.0.1.50","port":8443}
}
else
{
    Console.WriteLine("Entrée Base64 invalide — ignorée");
}

Cette approche est particulièrement efficace dans les middlewares de requête ou les pipelines de validation où une entrée invalide est attendue, non exceptionnelle. Lever et attraper une FormatException à chaque requête malformée ajoute un surcoût mesurable à grande échelle — TryFromBase64String()l'évite complètement.

Valider une entrée Base64 sans décoder

Un modèle courant dans les contrôleurs API : vérifier si l'entrée est du Base64 valide avant de la transmettre en aval. Tu peux utiliser TryFromBase64String() comme validateur en allouant un tampon jetable :

C# (.NET 5+)
using System;

static bool IsValidBase64(string input)
{
    // Calculer la taille maximale décodée
    Span<byte> buffer = stackalloc byte[((input.Length + 3) / 4) * 3];
    return Convert.TryFromBase64String(input, buffer, out _);
}

// Utilisation dans un contrôleur API
Console.WriteLine(IsValidBase64("eyJob3N0IjoiMTAuMC4xLjUwIn0=")); // True
Console.WriteLine(IsValidBase64("not!!valid!!base64"));              // False
Console.WriteLine(IsValidBase64(""));                                // True (vide est valide)
Remarque :Le tampon de sortie doit être suffisamment grand. S'il est trop petit, TryFromBase64String() retourne falsemême si l'entrée est valide. Calcule la taille requise avec (inputLength / 4) * 3 pour être tranquille.

Décoder Base64 depuis un fichier et une réponse API

Lire un fichier encodé en Base64 depuis le disque

Les certificats, les blobs chiffrés et les fichiers d'export de données sont parfois livrés sous forme de texte Base64. Le modèle typique : lire le fichier comme une chaîne, supprimer les espaces ou sauts de ligne qui provoqueraient une FormatException, décoder en octets, et écrire la sortie binaire. Fais attention à la gestion des erreurs — les erreurs d'E/S fichier et les erreurs de format Base64 doivent être capturées séparément.

C# (.NET 6+)
using System;
using System.IO;

string inputPath = "tls-cert.pem.b64";
string outputPath = "tls-cert.pem";

try
{
    string encoded = File.ReadAllText(inputPath).Trim();
    // Supprimer les sauts de ligne — le décodeur .NET les rejette
    encoded = encoded.Replace("
", "").Replace("
", "");

    byte[] decoded = Convert.FromBase64String(encoded);
    File.WriteAllBytes(outputPath, decoded);

    Console.WriteLine($"Decoded {decoded.Length} bytes -> {outputPath}");
}
catch (IOException ex)
{
    Console.Error.WriteLine($"File error: {ex.Message}");
}
catch (FormatException ex)
{
    Console.Error.WriteLine($"Invalid Base64: {ex.Message}");
}

Décoder un champ Base64 d'une réponse API HTTP

Les API cloud (Azure Key Vault, AWS Secrets Manager, GitHub Contents API) retournent fréquemment des données binaires sous forme de chaînes Base64 intégrées dans du JSON. Le flux de travail est toujours le même : effectuer la requête HTTP, analyser la réponse JSON, extraire le champ Base64, et le décoder. L'exemple ci-dessous utilise HttpClient et System.Text.Json — tous deux intégrés dans .NET 6+.

C# (.NET 6+)
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk-prod-9f8e7d6c");

try
{
    var response = await client.GetAsync("https://api.example.com/secrets/db-password");
    response.EnsureSuccessStatusCode();

    string body = await response.Content.ReadAsStringAsync();

    // L'API retourne : {"name":"db-password","value":"cG9zdGdyZXM6eGs5bVAycVI=","version":3}
    using var doc = JsonDocument.Parse(body);
    string encodedValue = doc.RootElement.GetProperty("value").GetString()!;

    byte[] decoded = Convert.FromBase64String(encodedValue);
    string secret = Encoding.UTF8.GetString(decoded);

    Console.WriteLine($"Secret: {secret}");
    // Secret: postgres:xk9mP2qR
}
catch (HttpRequestException ex)
{
    Console.Error.WriteLine($"HTTP error: {ex.Message}");
}
catch (FormatException ex)
{
    Console.Error.WriteLine($"Base64 decode failed: {ex.Message}");
}
Remarque :Sépare tes blocs catch pour les erreurs réseau et les FormatException. Les regrouper rend difficile de distinguer si l'API a retourné de mauvaises données ou si la requête elle-même a échoué. En production, journalise la valeur Base64 brute (ou au moins sa longueur et ses 20 premiers caractères) quand tu captures une FormatException — ça facilite considérablement le débogage.

Décodage Base64 en ligne de commande

Tu n'as pas toujours besoin d'un projet compilé. L'outil dotnet-scriptet PowerShell gèrent tous deux le décodage Base64 en une ligne. Pour une inspection rapide en débogage, c'est plus rapide que de créer une application console.

bash
# PowerShell (intégré à Windows, disponible sur Linux/macOS)
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("eyJob3N0IjoiMTAuMC4xLjUwIn0="))
# {"host":"10.0.1.50"}

# Commande base64 native Linux / macOS
echo "eyJob3N0IjoiMTAuMC4xLjUwIn0=" | base64 --decode
# {"host":"10.0.1.50"}

# macOS utilise -D à la place de --decode
echo "eyJob3N0IjoiMTAuMC4xLjUwIn0=" | base64 -D

# dotnet-script (installation : dotnet tool install -g dotnet-script)
echo 'Console.WriteLine(System.Text.Encoding.UTF8.GetString(Convert.FromBase64String("eyJob3N0IjoiMTAuMC4xLjUwIn0=")));' | dotnet-script eval

# Décoder et formater le JSON avec jq
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode | jq .

Pour coller directement des chaînes encodées dans un navigateur, le décodeur Base64 de ToolDeck gère les variantes standard et URL-safe sans aucune configuration.

Alternative haute performance : System.Buffers.Text.Base64

La classe System.Buffers.Text.Base64, disponible depuis .NET Core 2.1, opère sur des spans d'octets UTF-8 bruts au lieu des chaînes .NET. Cela contourne entièrement le surcoût de conversion chaîne vers octets — pas d'allocation intermédiaire de chaîne, pas d'étape d'encodage UTF-16. Je l'utilise dans les middlewares ASP.NET Core où les données entrantes sont déjà un ReadOnlySpan<byte> provenant du corps de la requête. Créer une string juste pour la passer à Convert.FromBase64String() double les allocations sans aucun bénéfice. Dans les tests BenchmarkDotNet sur .NET 8, le chemin basé sur les spans est environ 2 à 3 fois plus rapide pour des charges inférieures à 1 Ko, et l'écart se creuse avec des entrées plus grandes car la pression sur le GC reste stable.

C# (.NET 6+)
using System;
using System.Buffers.Text;
using System.Text;

// Simuler des octets UTF-8 bruts provenant d'un corps de requête HTTP
byte[] utf8Input = Encoding.UTF8.GetBytes("eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=");

byte[] output = new byte[Base64.GetMaxDecodedFromUtf8Length(utf8Input.Length)];

OperationStatus status = Base64.DecodeFromUtf8(
    utf8Input, output, out int bytesConsumed, out int bytesWritten);

if (status == OperationStatus.Done)
{
    string result = Encoding.UTF8.GetString(output.AsSpan(0, bytesWritten));
    Console.WriteLine(result);
    // {"host":"10.0.1.50","port":8443}
    Console.WriteLine($"Consumed: {bytesConsumed}, Written: {bytesWritten}");
    // Consumed: 44, Written: 31
}
else
{
    Console.WriteLine($"Decode failed: {status}");
    // Possibles : InvalidData, DestinationTooSmall, NeedMoreData
}

Le type de retour est OperationStatus — un enum à quatre valeurs : Done, InvalidData, DestinationTooSmall, et NeedMoreData. La dernière est utile pour le décodage partiel de données en streaming. Pour zéro allocation absolue, associe cela avec ArrayPool<byte>.Shared.Rent() au lieu de new byte[].

DecodeFromUtf8InPlace — écraser le tampon d'entrée

C# (.NET 6+)
using System;
using System.Buffers.Text;
using System.Text;

// Le tampon d'entrée est écrasé par les octets décodés
byte[] data = Encoding.UTF8.GetBytes("c2VydmVyLWNvbmZpZw==");

OperationStatus status = Base64.DecodeFromUtf8InPlace(data, out int bytesWritten);

if (status == OperationStatus.Done)
{
    Console.WriteLine(Encoding.UTF8.GetString(data.AsSpan(0, bytesWritten)));
    // server-config
}
Remarque :DecodeFromUtf8InPlacemodifie le tampon d'entrée. Ne l'utilise pas si tu as besoin de la chaîne Base64 d'origine après coup — les premiers bytesWritten octets du tableau contiennent maintenant les données décodées, et le reste est du garbage.

Un point à garder en tête : System.Buffers.Text.Base64ne gère pas le Base64 URL-safe directement. Si l'entrée utilise des caractères - et _ (tokens JWT, par exemple), tu dois toujours les remplacer par + et /avant d'appeler ces méthodes. Les API basées sur les spans sont strictement l'alphabet standard RFC 4648. Il n'existe pas de variante DecodeFromUtf8Url — une lacune surprenante étant donné la fréquence de Base64url dans les API modernes.

Sortie terminal avec coloration syntaxique

La bibliothèque Spectre.Console te donne une sortie terminal riche incluant la coloration JSON — utile pour créer des outils CLI qui décodent du Base64 et affichent le résultat. Installe-la avec dotnet add package Spectre.Console.

C# (.NET 6+)
using System;
using System.Text;
using Spectre.Console;
using Spectre.Console.Json;

string encoded = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0MywibWF4Q29ubiI6MTAwfQ==";
byte[] decoded = Convert.FromBase64String(encoded);
string json = Encoding.UTF8.GetString(decoded);

// Affichage formaté avec coloration syntaxique dans le terminal
AnsiConsole.Write(new JsonText(json));
// Affiche du JSON coloré :
// {
//   "host": "10.0.1.50",
//   "port": 8443,
//   "maxConn": 100
// }

C'est particulièrement pratique pour les outils CLI qui récupèrent et décodent des configurations depuis des services distants. Décoder la config Base64, désérialiser en JSON, et afficher le résultat coloré — le tout en quelques lignes. Spectre.Console propose aussi le rendu de tableaux, des barres de progression et des arborescences si tu dois afficher des structures de données décodées plus complexes dans le terminal.

Avertissement :La sortie Spectre.Console contient des séquences d'échappement ANSI. Ne la redirige pas vers un fichier ni ne la retourne depuis une API — utilise-la uniquement pour l'affichage terminal.

Streaming de grands fichiers Base64 avec CryptoStream

Charger un fichier Base64 de 500 Mo avec File.ReadAllText() puis appeler Convert.FromBase64String()alloue environ 700 Mo de tas : la chaîne elle-même (UTF-16, donc le double de la taille du fichier) plus le tableau d'octets décodé. La combinaison CryptoStream + FromBase64Transform décode par blocs, maintenant une utilisation mémoire constante.

C# (.NET 6+)
using System.IO;
using System.Security.Cryptography;

string inputPath = "database-export.sql.b64";
string outputPath = "database-export.sql";

using var inputStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
using var transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces);
using var base64Stream = new CryptoStream(inputStream, transform, CryptoStreamMode.Read);
using var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write);

base64Stream.CopyTo(outputStream);

Console.WriteLine($"Decoded {new FileInfo(outputPath).Length} bytes -> {outputPath}");

Le flag FromBase64TransformMode.IgnoreWhiteSpacesgère le Base64 avec retours à la ligne (fichiers PEM, exports e-mail) sans nettoyage manuel. Sans ce flag, les sauts de ligne dans l'entrée provoquent une FormatException. C'est l'équivalent .NET le plus proche du getMimeDecoder() de Java — il ignore silencieusement les espaces pendant le décodage.

Le nom CryptoStreamest trompeur — Base64 n'a rien de cryptographique. Microsoft a placé FromBase64Transform dans l'espace de noms System.Security.Cryptography parce qu'il implémente ICryptoTransform, la même interface utilisée pour AES et autres transformations de chiffrement. Le flux lui-même ne fait que faire passer les données par n'importe quelle transformation par blocs. Considère-le comme un pipeline de transformation en streaming générique qui se retrouve par hasard dans le mauvais espace de noms.

Streaming asynchrone pour les scénarios ASP.NET Core

C# (.NET 6+)
using System.IO;
using System.Security.Cryptography;

async Task DecodeStreamAsync(Stream inputStream, string outputPath)
{
    using var transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces);
    using var base64Stream = new CryptoStream(inputStream, transform, CryptoStreamMode.Read);
    await using var outputStream = new FileStream(
        outputPath, FileMode.Create, FileAccess.Write, FileShare.None,
        bufferSize: 81920, useAsync: true);

    await base64Stream.CopyToAsync(outputStream);
}

// Utilisation dans un endpoint :
// await DecodeStreamAsync(Request.Body, "uploaded-file.bin");
Remarque :Utilise CopyToAsync à la place de CopyTodans les gestionnaires ASP.NET Core. L'E/S synchrone sur le thread de requête est bloquée par défaut dans Kestrel et lève une InvalidOperationException.

Comment décoder le payload d'un token JWT Base64 en C#

Un JWT comporte trois segments encodés en Base64url séparés par des points. Le segment central est le payload. Tu peux le décoder sans bibliothèque JWT — divise sur ., normalise les caractères Base64url, corrige le padding, et appelle Convert.FromBase64String(). Cela piège presque tout le monde la première fois car JWT utilise - et _ au lieu de + et /, et supprime le padding =.

C# (.NET 6+)
using System;
using System.Text;

static string DecodeJwtPayload(string token)
{
    string[] parts = token.Split('.');
    if (parts.Length != 3)
        throw new ArgumentException($"Invalid JWT: expected 3 segments, got {parts.Length}");

    // Prendre le payload (deuxième segment)
    string payload = parts[1];

    // Remplacer les caractères URL-safe par le Base64 standard
    payload = payload.Replace('-', '+').Replace('_', '/');

    // Compléter jusqu'à un multiple de 4
    switch (payload.Length % 4)
    {
        case 2: payload += "=="; break;
        case 3: payload += "=";  break;
    }

    byte[] bytes = Convert.FromBase64String(payload);
    return Encoding.UTF8.GetString(bytes);
}

// Test avec un token de forme réelle
string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
    + ".eyJzdWIiOiJ1c3ItNjcyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIsImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJiaWxsaW5nIl19"
    + ".SIGNATURE_PLACEHOLDER";

Console.WriteLine(DecodeJwtPayload(token));
// {"sub":"usr-672","iss":"auth.example.com","exp":1741956800,"roles":["admin","billing"]}

Remarque rapide : cela ne fait que lire le payload. Cela ne vérifie pas la signature. Pour la validation d'authentification en production, utilise une bibliothèque dédiée comme Microsoft.IdentityModel.JsonWebTokens. Mais pour le débogage, la journalisation et les assertions de tests, cette approche manuelle est tout ce dont tu as besoin.

Parser le payload JWT décodé dans un objet typé

Une fois que tu as la chaîne JSON, désérialise-la avec System.Text.Json pour accéder aux claims individuels sans manipulation de chaînes :

C# (.NET 6+)
using System;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

record JwtPayload(
    [property: JsonPropertyName("sub")] string Subject,
    [property: JsonPropertyName("iss")] string Issuer,
    [property: JsonPropertyName("exp")] long Expiration,
    [property: JsonPropertyName("roles")] string[] Roles
);

// Après DecodeJwtPayload() ci-dessus
string json = DecodeJwtPayload(token);
var claims = JsonSerializer.Deserialize<JwtPayload>(json)!;

Console.WriteLine($"User: {claims.Subject}");
Console.WriteLine($"Issuer: {claims.Issuer}");
Console.WriteLine($"Expires: {DateTimeOffset.FromUnixTimeSeconds(claims.Expiration):u}");
Console.WriteLine($"Roles: {string.Join(", ", claims.Roles)}");
// User: usr-672
// Issuer: auth.example.com
// Expires: 2025-03-14 12:00:00Z
// Roles: admin, billing

Erreurs courantes

J'ai rencontré chacune de ces erreurs dans des services C# en production. Les deux premières sont responsables de la majorité des bugs liés à Base64 que je vois lors des revues de code. Chaque erreur semble évidente isolément, mais elles sont faciles à rater quand tu es plongé dans une fonctionnalité plus large et que le décodage Base64 n'est qu'une étape parmi d'autres dans le pipeline.

Oublier de supprimer les espaces de l'entrée

Problème : Les chaînes Base64 lues depuis des fichiers de config, des variables d'environnement ou des entrées utilisateur ont souvent des sauts de ligne en fin. Convert.FromBase64String() rejette tout caractère hors de l'alphabet Base64, y compris \r\n.

Solution : Appelle .Trim() ou .Replace() pour supprimer les espaces avant de décoder.

Before · C#
After · C#
// La variable d'environnement a un saut de ligne en fin
string encoded = Environment.GetEnvironmentVariable("DB_PASS_B64")!;
byte[] decoded = Convert.FromBase64String(encoded);
// FormatException: The input is not a valid Base-64 string
string encoded = Environment.GetEnvironmentVariable("DB_PASS_B64")!;
string cleaned = encoded.Replace("\n", "").Replace("\r", "").Trim();
byte[] decoded = Convert.FromBase64String(cleaned);
Console.WriteLine(Encoding.UTF8.GetString(decoded));
Utiliser Convert.FromBase64String() sur du Base64 URL-safe

Problème : Les tokens JWT et certains payloads API utilisent - et _ (alphabet URL-safe). Le décodeur standard n'accepte que + et / — il lève FormatException au premier caractère -.

Solution : Remplace - par + et _ par / avant de décoder. Corrige aussi le padding.

Before · C#
After · C#
// Payload JWT — utilise Base64 URL-safe
string payload = "eyJzdWIiOiJ1c3ItNjcyIn0";
byte[] decoded = Convert.FromBase64String(payload);
// FormatException
string payload = "eyJzdWIiOiJ1c3ItNjcyIn0";
payload = payload.Replace('-', '+').Replace('_', '/');
switch (payload.Length % 4)
{
    case 2: payload += "=="; break;
    case 3: payload += "="; break;
}
byte[] decoded = Convert.FromBase64String(payload);
Console.WriteLine(Encoding.UTF8.GetString(decoded));
// {"sub":"usr-672"}
Convertir des données binaires en chaîne

Problème : Appeler Encoding.UTF8.GetString() sur des octets décodés d'image ou de protobuf produit du garbage. Pire, reconvertir cette chaîne en octets corrompt silencieusement les données car les séquences UTF-8 invalides sont remplacées.

Solution : Garde les données binaires en byte[] tout au long du pipeline. N'appelle GetString() que lorsque tu sais que le contenu est du texte.

Before · C#
After · C#
byte[] decoded = Convert.FromBase64String(pngBase64);
string imageStr = Encoding.UTF8.GetString(decoded); // corrompt le binaire
File.WriteAllText("image.png", imageStr); // fichier cassé
byte[] decoded = Convert.FromBase64String(pngBase64);
// Écrire les octets directement — pas de conversion en chaîne
File.WriteAllBytes("image.png", decoded);
Ne pas spécifier l'encodage (comportement par défaut selon la plateforme)

Problème : Certaines anciennes API .NET Framework utilisent par défaut la page de codes ANSI du système, qui varie selon les machines. Un serveur Windows avec la page de codes 1252 et un conteneur Linux en UTF-8 produisent des chaînes différentes à partir des mêmes octets.

Solution : Spécifie toujours Encoding.UTF8 explicitement. Ne te fie jamais à la valeur par défaut de la plateforme.

Before · C#
After · C#
byte[] decoded = Convert.FromBase64String(encoded);
// Encoding.Default varie selon les plateformes
string result = Encoding.Default.GetString(decoded);
byte[] decoded = Convert.FromBase64String(encoded);
string result = Encoding.UTF8.GetString(decoded);
// cohérent sur Windows, Linux, macOS

Comparaison des méthodes

.NET propose plus de méthodes de décodage Base64 que la plupart des développeurs ne le réalisent. Le tableau ci-dessous couvre toutes les options intégrées ainsi que les deux alternatives tierces les plus courantes. La colonne "Allocation" est la plus importante dans les services à haut débit — une méthode qui alloue un nouveau byte[] à chaque appel met le GC sous pression dans les boucles serrées.

Méthode
Allocation
Gestion des erreurs
Streaming
Types personnalisés
Installation requise
Convert.FromBase64String()
Nouveau byte[]
FormatException
Non
Non
Non (.NET Framework 1.1+)
Convert.TryFromBase64String()
Span de l'appelant
Retourne false
Non
Non
Non (.NET 5+)
Convert.FromBase64CharArray()
Nouveau byte[]
FormatException
Non
Non
Non (.NET Framework 1.1+)
Base64.DecodeFromUtf8()
Span de l'appelant
OperationStatus
Partiel
Non
Non (.NET Core 2.1+)
Base64.DecodeFromUtf8InPlace()
En place
OperationStatus
Non
Non
Non (.NET Core 2.1+)
CryptoStream + FromBase64Transform
Tampon streaming
Exception
Oui
Non
Non (.NET Framework 2.0+)
BouncyCastle Base64
Nouveau byte[]
Exception
Oui
Non
Oui (NuGet)

Pour le travail courant : Convert.FromBase64String(). Pour les chemins critiques où tu valides des entrées utilisateur : TryFromBase64String(). Pour le middleware ASP.NET Core opérant sur des octets de requête bruts : Base64.DecodeFromUtf8(). Pour les grands fichiers : CryptoStream + FromBase64Transform. BouncyCastle n'a de sens que s'il est déjà dans ton arbre de dépendances pour d'autres opérations cryptographiques.

Pour une vérification rapide sans rien compiler, le décodeur Base64 en ligne est plus rapide que d'écrire une application console jetable.

Questions fréquentes

Comment décoder une chaîne Base64 en texte en C# ?

Appelle Convert.FromBase64String() pour obtenir un tableau d'octets, puis passe-le à Encoding.UTF8.GetString(). L'encodage doit correspondre à celui utilisé lors de l'encodage — UTF-8 est la valeur par défaut sûre pour presque tous les systèmes modernes. Si l'entrée peut contenir des espaces ou des sauts de ligne, appelle .Trim() ou supprime-les avant de décoder.

C# (.NET 6+)
using System;
using System.Text;

string encoded = "cG9zdGdyZXM6eGs5bVAycVI=";
byte[] bytes = Convert.FromBase64String(encoded);
string result = Encoding.UTF8.GetString(bytes);
Console.WriteLine(result);
// postgres:xk9mP2qR

Quelle est la différence entre Convert.FromBase64String() et Convert.TryFromBase64String() ?

FromBase64String() lève une FormatException sur une entrée invalide. TryFromBase64String() retourne un bool et écrit le résultat dans un Span<byte> fourni par l'appelant, ce qui le rend adapté aux chemins critiques où l'on veut éviter le surcoût des exceptions. TryFromBase64String() nécessite .NET 5 ou ultérieur.

C# (.NET 6+)
using System;

string input = "maybe-not-valid-base64!!";
Span<byte> buffer = stackalloc byte[256];

if (Convert.TryFromBase64String(input, buffer, out int written))
    Console.WriteLine($"Decoded {written} bytes");
else
    Console.WriteLine("Invalid Base64 input");

Comment décoder le payload Base64url d'un JWT en C# ?

Divise le token par des points, prends le deuxième segment, remplace - par + et _ par /, complète avec = jusqu'à un multiple de 4, puis appelle Convert.FromBase64String(). Les tokens JWT utilisent l'alphabet Base64 URL-safe, que le décodeur standard de .NET ne gère pas directement.

C# (.NET 6+)
string token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3ItNjcyIn0.SIG";
string payload = token.Split('.')[1];
payload = payload.Replace('-', '+').Replace('_', '/');
switch (payload.Length % 4)
{
    case 2: payload += "=="; break;
    case 3: payload += "="; break;
}
byte[] bytes = Convert.FromBase64String(payload);
Console.WriteLine(Encoding.UTF8.GetString(bytes));
// {"sub":"usr-672"}

Comment choisir le bon Encoding pour décoder Base64 en C# ?

Utilise Encoding.UTF8 par défaut — il gère les caractères ASCII et Unicode multi-octets. Utilise Encoding.ASCII uniquement si tu es certain que les données sont du pur ASCII 7-bit. Utilise Encoding.Unicode (qui est UTF-16LE dans .NET) uniquement lorsque les données d'origine ont été encodées en UTF-16, ce qui arrive parfois avec les chaînes internes Windows et les exports PowerShell.

Pourquoi Convert.FromBase64String() lève-t-il FormatException ?

Trois causes fréquentes : l'entrée contient des espaces ou des sauts de ligne (supprime-les avant de décoder), l'entrée utilise des caractères URL-safe comme - et _ (remplace-les respectivement par + et /), ou le padding est absent ou incorrect (la longueur totale doit être un multiple de 4 après padding). Contrairement à Java, .NET n'a pas de décodeur MIME intégré qui tolère les espaces — tu dois nettoyer l'entrée toi-même ou utiliser CryptoStream avec FromBase64Transform en mode IgnoreWhiteSpaces.

C# (.NET 6+)
// Corriger les espaces
string cleaned = rawInput.Replace("\n", "").Replace("\r", "").Trim();
byte[] decoded = Convert.FromBase64String(cleaned);

Peut-on décoder en streaming de grandes données Base64 en C# ?

Oui. Utilise un CryptoStream avec FromBase64Transform de System.Security.Cryptography. Cela décode par blocs au fur et à mesure de la lecture, donc la mémoire reste constante quelle que soit la taille du fichier. Passe FromBase64TransformMode.IgnoreWhiteSpaces si l'entrée contient des sauts de ligne. Sur .NET 6+, tu peux également utiliser le modèle IAsyncEnumerable avec Base64.DecodeFromUtf8() pour un traitement manuel par morceaux, bien que CryptoStream soit plus simple pour le décodage fichier vers fichier.

C# (.NET 6+)
using System.IO;
using System.Security.Cryptography;

using var input = File.OpenRead("payload.b64");
using var transform = new FromBase64Transform();
using var cryptoStream = new CryptoStream(input, transform, CryptoStreamMode.Read);
using var output = File.Create("payload.bin");
cryptoStream.CopyTo(output);

Outils associés

  • Base64 Encoder — encode du texte ou des données binaires en Base64 dans le navigateur, utile pour générer des fixtures de test à coller dans tes tests unitaires C#.
  • JWT Decoder — décode et inspecte les trois segments d'un JWT en une fois, avec inspection champ par champ du payload — plus rapide qu'écrire un helper C# quand tu as juste besoin de lire un token.
  • URL Decoder — décode les chaînes encodées en percent-encoding, utile quand les réponses API mélangent des données Base64url avec des paramètres de requête encodés en percent-encoding.
  • JSON Formatter — après avoir décodé un payload JWT ou une config API en Base64, colle le JSON ici pour le formater et valider la structure.
Aussi disponible en :JavaScriptPythonGoJava
AP
Alexei PetrovGame Developer & Unity Engineer

Alexei is a game developer who has shipped multiple titles using Unity and C#. He focuses on gameplay systems, runtime performance, and the serialisation and data-management patterns unique to game development. He writes about Unity scripting, C# async/await in game contexts, asset serialisation, binary data handling, and the intersection of game engineering and general software craftsmanship.

ER
Emma RichardsonRéviseur technique

Emma is a .NET developer and cloud engineer who builds production APIs and backend services with ASP.NET Core and Azure. She has worked on everything from microservice migrations to real-time SignalR applications. She writes about C# language features, the System.Text.Json and Newtonsoft.Json ecosystems, Azure integrations, and the architectural patterns that make .NET services scalable and maintainable.