هر پروژه .NET که روی آن کار کردهام در نهایت نیاز به رمزگشایی Base64 داشته — خواندن رشتههای اتصال از Kubernetes secrets، خواندن payloadهای باینری از webhookها، یا بررسی توکنهای JWT در هنگام debug. برای رمزگشایی Base64 در C#، متد اصلی Convert.FromBase64String() است که یک byte[] برمیگرداند که سپس به Encoding.UTF8.GetString() میدهید تا متن خوانا بگیرید. برای بررسی سریع بدون نوشتن کد، رمزگشای Base64 ToolDeck همان لحظه در مرورگر انجام میدهد. این راهنما همه چیز را پوشش میدهد — ازConvert.FromBase64String() و TryFromBase64String() مبتنی بر Span تا رمزگشایی payload JWT، streaming فایلهای بزرگ با CryptoStream، و چهار اشتباهی که در code review زیاد میبینم.
- ✓Convert.FromBase64String(s) + Encoding.UTF8.GetString(bytes) یک pipeline استاندارد دو مرحلهای است — در تمام نسخههای .NET کار میکند.
- ✓Convert.TryFromBase64String() از پرتاب استثنا بر روی ورودی نامعتبر جلوگیری میکند و در یک Span<byte> مینویسد — ایدهآل برای hot pathها در .NET 5+.
- ✓System.Buffers.Text.Base64.DecodeFromUtf8() رمزگشایی بدون تخصیص حافظه را برای بافرهای بایت UTF-8 در سرویسهای حساس به کارایی ارائه میدهد.
- ✓توکنهای JWT از Base64url استفاده میکنند (- و _ به جای + و /) — باید ورودی را قبل از فراخوانی Convert.FromBase64String() نرمالسازی کنید.
- ✓CryptoStream با FromBase64Transform رمزگشایی streaming فایلهای بزرگ را بدون بارگذاری همه چیز در حافظه مدیریت میکند.
رمزگشایی Base64 چیست؟
رمزگذاری Base64 دادههای باینری را به یک الفبای 64 کاراکتری ASCII تبدیل میکند تا از کانالهای متنمحور — فیلدهای JSON، هدرهای HTTP، بدنه ایمیل، صفات XML — سالم عبور کند. هر 3 بایت ورودی به 4 کاراکتر Base64 تبدیل میشود، به همین دلیل خروجی Base64 همیشه حدود 33٪ بزرگتر از اصل است. رمزگشایی این تبدیل را معکوس میکند. padding = در انتها به دیکودر میگوید چند بایت از گروه آخر را کم کند. یک = به معنای داشتن 2 بایت در بلوک آخر است؛ == به معنای 1 بایت است. Base64 رمزنگاری نیست — هر کسی میتواند آن را معکوس کند. هدف انتقال امن از طریق کانالهایی است که باینری خام را خراب میکنند، نه محرمانگی.
redis://cache-prod.internal:6379/session-store
cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ==
Convert.FromBase64String() — متد استاندارد رمزگشایی
متد Convert.FromBase64String() از روزهای Framework 1.1 در .NET موجود بوده است. هیچ بسته NuGet یا import اضافهای فراتر از System لازم نیست — فقط آن را فراخوانی کنید و یک byte[] بگیرید. pipeline دو مرحلهای برای رمزگشایی Base64 به رشته C# همیشه یکسان است: Convert.FromBase64String() برای گرفتن بایتها، سپس Encoding.UTF8.GetString() برای تفسیر آن بایتها به عنوان متن. نکته این است که متد بایتهای خام برمیگرداند نه یک رشته. باید Encoding مناسب را برای تبدیل آن بایتها به متن انتخاب کنید، و این انتخاب بیشتر از آنچه توسعهدهندگان انتظار دارند اهمیت دارد. یک encoding اشتباه خاموشانه mojibake تولید میکند — کاراکترهای درهم برهم، بدون اینکه هیچ خطایی بدهد.
مثال ساده
using System; using System.Text; // رشته اتصال ذخیره شده به صورت Base64 در یک Kubernetes secret string encoded = "cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ=="; byte[] decodedBytes = Convert.FromBase64String(encoded); string connectionString = Encoding.UTF8.GetString(decodedBytes); Console.WriteLine(connectionString); // redis://cache-prod.internal:6379/session-store
همیشه از Encoding.UTF8 استفاده کنید مگر اینکه دلیل خاصی داشته باشید. runtime .NET رشتهها را به صورت داخلی UTF-16 نمایش میدهد، اما بیشتر دادههایی که از مرزهای سیستم عبور میکنند (پاسخهای API، فایلهای پیکربندی، secretها) با UTF-8 رمزگذاری میشوند. استفاده از Encoding.ASCII روی دادههایی که شامل کاراکترهای چندبایتی هستند بدون هیچ خطایی آنها را با ? جایگزین میکند — بدون استثنا، فقط خروجی خراب.
تأیید رفت و برگشت
using System; using System.Text; string original = "postgres://db-admin:Kx8!mQ@db-prod.us-east-1.internal:5432/orders"; // رمزگذاری string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(original)); Console.WriteLine(encoded); // cG9zdGdyZXM6Ly9kYi1hZG1pbjpLeDghbVFAZGItcHJvZC51cy1lYXN0LTEuaW50ZXJuYWw6NTQzMi9vcmRlcnM= // رمزگشایی byte[] decoded = Convert.FromBase64String(encoded); string recovered = Encoding.UTF8.GetString(decoded); Console.WriteLine(recovered == original); // True
انتخاب Encoding مناسب
Encoding که به GetString() میدهید باید با آنچه هنگام رمزگذاری اولیه دادهها استفاده شده مطابقت داشته باشد. اشتباه انتخاب کنید و کاراکترهای بیمعنی میگیرید بدون هیچ استثنایی — دیکودر بیسروصدا خروجی خراب تولید میکند. خلاصه عملی:
Encoding.UTF8— پیشفرض امن. ASCII و تمام Unicode را مدیریت میکند. از این استفاده کنید مگر اینکه دلیل خاصی داشته باشید.Encoding.ASCII— فقط برای دادههای خالص ASCII 7 بیتی. کاراکترهای چندبایتی به?تبدیل میشوند.Encoding.Unicode— این UTF-16LE در .NET است. برخی رشتههای داخلی ویندوز و خروجی PowerShell از این استفاده میکنند.Encoding.Latin1— کدگذاری قدیمی اروپای غربی. در سرویسهای SOAP قدیمی و ادغامهای mainframe ظاهر میشود.
using System;
using System.Text;
// همان بایتها، encodingهای مختلف — نتایج مختلف
byte[] decoded = Convert.FromBase64String("w7bDvMOk");
Console.WriteLine(Encoding.UTF8.GetString(decoded)); // oua (صحیح)
Console.WriteLine(Encoding.ASCII.GetString(decoded)); // ?????? (از دست رفت)
Console.WriteLine(Encoding.Latin1.GetString(decoded)); // öüä (mojibake)یک helper رمزگشایی قابل استفاده مجدد با مدیریت خطا
چون Convert.FromBase64String() روی ورودی بد استثنا پرتاب میکند و حذف فضای خالی هم کار تکراری است، در بیشتر پروژهها یک helper کوچک نگه میدارم:
using System;
using System.Text;
static class Base64Helper
{
public static string? DecodeToString(string encoded)
{
if (string.IsNullOrWhiteSpace(encoded))
return null;
// حذف فضای خالی که دیکودر .NET رد میکند
string cleaned = encoded
.Replace("
", "")
.Replace("
", "")
.Replace(" ", "")
.Trim();
try
{
byte[] bytes = Convert.FromBase64String(cleaned);
return Encoding.UTF8.GetString(bytes);
}
catch (FormatException)
{
return null; // یا یک استثنای مخصوص دامین پرتاب کنید
}
}
}
// استفاده
string? decoded = Base64Helper.DecodeToString(" cmVkaXM6Ly9jYWNoZQ==
");
Console.WriteLine(decoded); // redis://cacheConvert.FromBase64String() اگر ورودی شامل کاراکترهایی خارج از الفبای Base64 باشد — از جمله فاصله، خط جدید و کاراکترهای ایمن URL مانند - و _ — خطای FormatException پرتاب میکند. helper بالا فضای خالی را به صورت خودکار مدیریت میکند.رمزگشایی Base64 به انواع غیر استاندارد
دیکودر همیشه byte[] به شما میدهد. آنچه با آن بایتها انجام میدهید به دادههای اصلی بستگی دارد. گاهی یک GUID ذخیره شده به صورت 16 بایت خام است، گاهی یک پیام protobuf سریالیزه شده است، گاهی یک timestamp در فرمت باینری است. اینجا تبدیلهایی هستند که بیشتر استفاده میکنم.
Base64 به GUID
using System; // برخی APIها GUIDها را به عنوان Base64 22 کاراکتری به جای رشته hex 36 کاراکتری ارسال میکنند string compactGuid = "C0HqetxMckKlZw4CssPUeQ=="; byte[] guidBytes = Convert.FromBase64String(compactGuid); Guid recovered = new Guid(guidBytes); Console.WriteLine(recovered); // 7aea41c0-4cdc-4272-a567-0e02b2c3d479
Base64 به JSON سریالیزه شده با System.Text.Json
using System;
using System.Text;
using System.Text.Json;
// payload JSON با رمزگذاری Base64 از یک صف پیام
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}
// Deserialize به یک 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 به رشته hex
using System; // هش SHA-256 ذخیره شده به صورت Base64 string hashBase64 = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="; byte[] hashBytes = Convert.FromBase64String(hashBase64); string hex = Convert.ToHexString(hashBytes); Console.WriteLine(hex); // 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08
BinaryFormatter deserialize نکنید. این دارای آسیبپذیریهای اجرای کد از راه دور شناخته شده است و در .NET 8+ منسوخ شده است. اگر محتوای رمزگذاری شده از یک منبع خارجی میآید، به جای استفاده از binary serialization .NET، آن را به صورت JSON یا protobuf تجزیه کنید.مرجع متدهای رمزگشایی Base64
.NET چندین متد رمزگشایی در دو فضای نام ارائه میدهد. کلاس Convert رمزگشایی همهمنظوره را مدیریت میکند، در حالی که System.Buffers.Text.Base64 سناریوهای high-throughput را هدف قرار میدهد که در آنها با بافرهای بایت UTF-8 خام کار میکنید.
Convert.TryFromBase64String() — رمزگشایی بدون استثنا
الگوی Try در .NET برای عملیاتی که ممکن است روی ورودی کاربر شکست بخورند استاندارد است. Convert.TryFromBase64String()، موجود از .NET 5، به جای پرتاب FormatException یک bool برمیگرداند. بایتهای رمزگشایی شده را در یک Span<byte> فراهمشده توسط فراخواننده مینویسد، به این معنی که میتوانید از حافظه پشته برای payloadهای کوچک استفاده کنید و از heap کاملاً اجتناب کنید.
using System;
using System.Text;
string userInput = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=";
// برای payloadهای کوچک از پشته تخصیص دهید (کمتر از 1KB قانون امنی است)
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("Invalid Base64 input — skipping");
}این رویکرد در middleware و pipelineهای اعتبارسنجی که ورودی نامعتبر امر عادی است به خوبی کار میکند. پرتاب و catch کردن یک FormatException روی هر درخواست بد در مقیاس بار اضافی قابل اندازهگیری اضافه میکند — TryFromBase64String() از آن کاملاً اجتناب میکند.
اعتبارسنجی ورودی Base64 بدون رمزگشایی
یک الگوی رایج در API controllerها: بررسی معتبر بودن ورودی Base64 قبل از ارسال آن به downstream. میتوانید از TryFromBase64String() به عنوان validator با تخصیص یک بافر موقت استفاده کنید:
using System;
static bool IsValidBase64(string input)
{
// محاسبه حداکثر اندازه رمزگشایی شده
Span<byte> buffer = stackalloc byte[((input.Length + 3) / 4) * 3];
return Convert.TryFromBase64String(input, buffer, out _);
}
// استفاده در یک API controller
Console.WriteLine(IsValidBase64("eyJob3N0IjoiMTAuMC4xLjUwIn0=")); // True
Console.WriteLine(IsValidBase64("not!!valid!!base64")); // False
Console.WriteLine(IsValidBase64("")); // True (خالی معتبر است)TryFromBase64String() حتی زمانی که ورودی معتبر است false برمیگرداند. برای اطمینان، اندازه مورد نیاز را به صورت (inputLength / 4) * 3 محاسبه کنید.رمزگشایی Base64 از فایل و پاسخ API
خواندن یک فایل رمزگذاری شده با Base64 از دیسک
گاهی گواهینامهها، blobهای رمزگذاری شده و فایلهای صدور داده به صورت متن Base64 ارسال میشوند. الگوی معمول: فایل را به عنوان رشته بخوانید، هر فضای خالی یا شکست خطی که باعث FormatException میشود را حذف کنید، به بایت رمزگشایی کنید و خروجی باینری را بنویسید. به مدیریت خطا توجه کنید — خطاهای I/O فایل و خطاهای فرمت Base64 باید جداگانه گرفته شوند.
using System;
using System.IO;
string inputPath = "tls-cert.pem.b64";
string outputPath = "tls-cert.pem";
try
{
string encoded = File.ReadAllText(inputPath).Trim();
// حذف شکست خط — دیکودر .NET آنها را رد میکند
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}");
}رمزگشایی یک فیلد Base64 از پاسخ HTTP API
APIهای ابری (Azure Key Vault، AWS Secrets Manager، GitHub Contents API) اغلب دادههای باینری را به عنوان رشتههای Base64 جاسازی شده در JSON برمیگردانند. جریان کار همیشه یکسان است: درخواست HTTP را ارسال کنید، پاسخ JSON را تجزیه کنید، فیلد Base64 را استخراج کنید و آن را رمزگشایی کنید. مثال زیر از HttpClient و System.Text.Json استفاده میکند — هر دو در .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();
// API برمیگرداند: {"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}");
}catch خود را برای خطاهای شبکه و FormatException جداگانه نگه دارید. ترکیب آنها تشخیص اینکه آیا API داده بد برگردانده یا خود درخواست شکست خورده را دشوار میکند. در محیط تولید، مقدار Base64 خام (یا حداقل طول و 20 کاراکتر اول آن) را هنگام گرفتن FormatException لاگ کنید — این debug را به طور چشمگیری آسانتر میکند.رمزگشایی Base64 از خط فرمان
همیشه به یک پروژه کامپایل شده نیاز ندارید. ابزار dotnet-script و PowerShell هر دو رمزگشایی Base64 را با one-linerها مدیریت میکنند. برای بررسی سریع در هنگام debug، اینها سریعتر از ایجاد یک console app هستند.
# PowerShell (تعبیه شده در ویندوز، موجود در Linux/macOS)
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("eyJob3N0IjoiMTAuMC4xLjUwIn0="))
# {"host":"10.0.1.50"}
# دستور base64 بومی Linux / macOS
echo "eyJob3N0IjoiMTAuMC4xLjUwIn0=" | base64 --decode
# {"host":"10.0.1.50"}
# macOS از -D به جای --decode استفاده میکند
echo "eyJob3N0IjoiMTAuMC4xLjUwIn0=" | base64 -D
# dotnet-script (نصب: dotnet tool install -g dotnet-script)
echo 'Console.WriteLine(System.Text.Encoding.UTF8.GetString(Convert.FromBase64String("eyJob3N0IjoiMTAuMC4xLjUwIn0=")));' | dotnet-script eval
# رمزگشایی و pretty-print JSON با jq
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode | jq .اگر فقط میخواهید یک رشته را سریع توی مرورگر تست کنید، رمزگشای Base64 ToolDeck هم نوع استاندارد و هم URL-safe را بدون هیچ تنظیمی مدیریت میکند.
جایگزین پرکارایی: System.Buffers.Text.Base64
کلاس System.Buffers.Text.Base64، موجود از .NET Core 2.1، روی Spanهای بایت UTF-8 خام به جای رشتههای .NET عمل میکند. این سربار تبدیل رشته به بایت را کاملاً دور میزند — بدون تخصیص رشته میانی، بدون مرحله رمزگذاری UTF-16. در middleware ASP.NET Core که داده ورودی قبلاً یک ReadOnlySpan<byte> از بدنه درخواست است از آن استفاده میکنم. ایجاد یک string فقط برای ارسال به Convert.FromBase64String() تخصیصها را بدون دلیل دو برابر میکند. در تستهای BenchmarkDotNet روی .NET 8، مسیر مبتنی بر Span برای payloadهای زیر 1 KB تقریباً 2-3 برابر سریعتر است و این فاصله با ورودیهای بزرگتر بیشتر میشود زیرا فشار GC ثابت میماند.
using System;
using System.Buffers.Text;
using System.Text;
// شبیهسازی بایتهای UTF-8 خام از بدنه یک HTTP request
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}");
// ممکن است: InvalidData, DestinationTooSmall, NeedMoreData
}نوع برگشتی OperationStatus است — یک enum با چهار مقدار: Done، InvalidData، DestinationTooSmall، و NeedMoreData. آخری برای رمزگشایی جزئی دادههای streaming مفید است. برای صفر تخصیص مطلق، این را با ArrayPool<byte>.Shared.Rent() به جای new byte[] ترکیب کنید.
DecodeFromUtf8InPlace — بازنویسی بافر ورودی
using System;
using System.Buffers.Text;
using System.Text;
// بافر ورودی با بایتهای رمزگشایی شده بازنویسی میشود
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
}DecodeFromUtf8InPlace بافر ورودی را تغییر میدهد. اگر بعداً به رشته Base64 اصلی نیاز دارید از آن استفاده نکنید — اولین bytesWritten بایت آرایه اکنون شامل دادههای رمزگشایی شده است و بقیه زباله است.یک نکته قابل توجه: System.Buffers.Text.Base64 مستقیماً Base64 ایمن برای URL را مدیریت نمیکند. اگر ورودی از کاراکترهای - و _ استفاده میکند (توکنهای JWT، برای مثال)، همچنان باید آنها را قبل از فراخوانی این متدها با + و / جایگزین کنید. APIهای مبتنی بر Span کاملاً الفبای استاندارد RFC 4648 هستند. هیچ نوع DecodeFromUtf8Url وجود ندارد — جالب توجه است که Base64url در APIهای مدرن چقدر رایج است.
خروجی ترمینال با Syntax Highlighting
کتابخانه Spectre.Console خروجی ترمینال غنی از جمله highlighting JSON را ارائه میدهد — هنگام ساخت ابزارهای CLI که Base64 را رمزگشایی و نتیجه را نمایش میدهند مفید است. آن را با dotnet add package Spectre.Console نصب کنید.
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);
// Pretty-print با syntax highlighting در ترمینال
AnsiConsole.Write(new JsonText(json));
// خروجی JSON رنگی:
// {
// "host": "10.0.1.50",
// "port": 8443,
// "maxConn": 100
// }این به ویژه برای ابزارهای CLI که پیکربندی را از سرویسهای راه دور fetch و رمزگشایی میکنند مفید است. Base64 config را رمزگشایی کنید، به JSON deserialize کنید و خروجی highlighted را چاپ کنید — همه در چند خط. Spectre.Console همچنین رندر جدول، نوار پیشرفت و tree view دارد اگر نیاز به نمایش ساختارهای داده پیچیدهتر رمزگشایی شده در ترمینال دارید.
Streaming فایلهای Base64 بزرگ با CryptoStream
بارگذاری یک فایل Base64 500 مگابایتی با File.ReadAllText() و سپس فراخوانی Convert.FromBase64String() تقریباً 700 مگابایت در heap تخصیص میدهد: خود رشته (UTF-16، پس دو برابر حجم فایل) به اضافه آرایه بایت رمزگشایی شده. ترکیب CryptoStream + FromBase64Transform در chunk رمزگشایی میکند و مصرف حافظه را ثابت نگه میدارد.
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}");پرچم FromBase64TransformMode.IgnoreWhiteSpaces Base64 پیچیده در خطوط (فایلهای PEM، خروجیهای ایمیل) را بدون پاکسازی دستی مدیریت میکند. بدون این پرچم، شکست خط در ورودی باعث FormatException میشود. این نزدیکترین معادل .NET به getMimeDecoder() جاوا است — خاموشانه کاراکترهای فضای خالی را در حین رمزگشایی نادیده میگیرد.
نام CryptoStream گمراهکننده است — هیچ چیز رمزنگارانهای در مورد Base64 وجود ندارد. Microsoft FromBase64Transform را در فضای نام System.Security.Cryptography قرار داد زیرا ICryptoTransformرا پیادهسازی میکند، همان interface مورد استفاده برای AES و سایر تبدیلهای cipher. خود stream فقط دادهها را در chunk از طریق هر تبدیلی عبور میدهد. آن را به عنوان یک pipeline تبدیل streaming همهمنظوره در نظر بگیرید که اتفاقاً در فضای نام اشتباهی قرار گرفته.
Streaming async برای سناریوهای ASP.NET Core
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);
}
// استفاده در یک endpoint:
// await DecodeStreamAsync(Request.Body, "uploaded-file.bin");CopyTo به CopyToAsync تغییر دهید. I/O همزمان روی thread درخواست به صورت پیشفرض توسط Kestrel مسدود میشود و یک InvalidOperationException پرتاب میکند.نحوه رمزگشایی payload توکن JWT با Base64 در C#
یک JWT سه بخش رمزگذاری شده با Base64url دارد که با نقطه جدا شدهاند. بخش میانی payload است. میتوانید آن را بدون استفاده از کتابخانه JWT رمزگشایی کنید — روی . تقسیم کنید، کاراکترهای Base64url را نرمال کنید، padding را درست کنید و Convert.FromBase64String() را فراخوانی کنید. این تقریباً همه را اولین بار گیج میکند زیرا JWT از - و _ به جای + و / استفاده میکند و padding = را حذف میکند.
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}");
// payload را بردارید (بخش دوم)
string payload = parts[1];
// کاراکترهای ایمن URL را با Base64 استاندارد جایگزین کنید
payload = payload.Replace('-', '+').Replace('_', '/');
// به مضربی از 4 padding اضافه کنید
switch (payload.Length % 4)
{
case 2: payload += "=="; break;
case 3: payload += "="; break;
}
byte[] bytes = Convert.FromBase64String(payload);
return Encoding.UTF8.GetString(bytes);
}
// تست با یک توکن واقعی
string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
+ ".eyJzdWIiOiJ1c3ItNjcyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIsImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJiaWxsaW5nIl19"
+ ".SIGNATURE_PLACEHOLDER";
Console.WriteLine(DecodeJwtPayload(token));
// {"sub":"usr-672","iss":"auth.example.com","exp":1741956800,"roles":["admin","billing"]}نکته سریع: این فقط payload را میخواند. امضا را تأیید نمیکند. برای اعتبارسنجی auth در محیط تولید، از یک کتابخانه مناسب مانند Microsoft.IdentityModel.JsonWebTokens استفاده کنید. اما برای debug، لاگگیری و تأیید در تست، این رویکرد دستی کافی است.
تجزیه payload JWT رمزگشایی شده به یک شیء typed
وقتی رشته JSON را دارید، آن را با System.Text.Json deserialize کنید تا بدون دستکاری رشته به claimهای جداگانه دسترسی داشته باشید:
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
);
// بعد از DecodeJwtPayload() بالا
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اشتباهات رایج
همه اینها را در سرویسهای C# تولیدی تجربه کردهام. دو مورد اول مسئول اکثر باگهای مرتبط با Base64 هستند که در بازبینی کد میبینم. هر اشتباه به تنهایی واضح به نظر میرسد، اما وقتی درگیر یک feature بزرگتر هستید و رمزگشایی Base64 فقط یک مرحله در pipeline است، به راحتی از دست میرود.
مشکل: رشتههای Base64 خوانده شده از فایلهای پیکربندی، متغیرهای محیطی یا ورودی کاربر اغلب خط جدید trailing دارند. Convert.FromBase64String() هر کاراکتری خارج از الفبای Base64 از جمله \r\n را رد میکند.
راهحل: قبل از رمزگشایی .Trim() یا .Replace() فراخوانی کنید تا فضای خالی حذف شود.
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));// متغیر محیطی یک خط جدید trailing دارد
string encoded = Environment.GetEnvironmentVariable("DB_PASS_B64")!;
byte[] decoded = Convert.FromBase64String(encoded);
// FormatException: The input is not a valid Base-64 stringمشکل: توکنهای JWT و برخی payloadهای API از - و _ (الفبای ایمن URL) استفاده میکنند. دیکودر استاندارد فقط + و / میپذیرد — روی اولین کاراکتر - خطای FormatException پرتاب میکند.
راهحل: قبل از رمزگشایی - را با + و _ را با / جایگزین کنید. همچنین padding را درست کنید.
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"}// payload JWT — از Base64 ایمن برای URL استفاده میکند string payload = "eyJzdWIiOiJ1c3ItNjcyIn0"; byte[] decoded = Convert.FromBase64String(payload); // FormatException
مشکل: فراخوانی Encoding.UTF8.GetString() روی بایتهای تصویر یا protobuf رمزگشایی شده زباله تولید میکند. بدتر، تبدیل مجدد آن رشته به بایتها بدون اخطار دادهها را خراب میکند زیرا دنبالههای UTF-8 نامعتبر جایگزین میشوند.
راهحل: دادههای باینری را در تمام pipeline به صورت byte[] نگه دارید. فقط زمانی GetString() فراخوانی کنید که مطمئن هستید محتوا متن است.
byte[] decoded = Convert.FromBase64String(pngBase64);
// بایتها را مستقیماً بنویسید — بدون تبدیل رشته
File.WriteAllBytes("image.png", decoded);byte[] decoded = Convert.FromBase64String(pngBase64);
string imageStr = Encoding.UTF8.GetString(decoded); // باینری را خراب میکند
File.WriteAllText("image.png", imageStr); // فایل شکستهمشکل: برخی APIهای قدیمی .NET Framework به صورت پیشفرض از code page ANSI فعلی سیستم استفاده میکنند که بین ماشینها متفاوت است. یک سرور ویندوز با code page 1252 و یک container لینوکس با UTF-8 از همان بایتها رشتههای مختلف تولید میکنند.
راهحل: همیشه Encoding.UTF8 را به صراحت مشخص کنید. هرگز به پیشفرض پلتفرم تکیه نکنید.
byte[] decoded = Convert.FromBase64String(encoded); string result = Encoding.UTF8.GetString(decoded); // یکسان در ویندوز، لینوکس، macOS
byte[] decoded = Convert.FromBase64String(encoded); // Encoding.Default بین پلتفرمها متفاوت است string result = Encoding.Default.GetString(decoded);
مقایسه متدها
.NET متدهای رمزگشایی Base64 بیشتری از آنچه اکثر توسعهدهندگان میدانند ارائه میدهد. جدول زیر هر گزینه داخلی به اضافه دو جایگزین رایج third-party را پوشش میدهد. ستون «تخصیص حافظه» در سرویسهای high-throughput بیشترین اهمیت را دارد — متدی که در هر فراخوانی یک byte[] جدید تخصیص میدهد در حلقههای tight فشار روی GC ایجاد میکند.
برای کار روزمره: Convert.FromBase64String(). برای hot pathها که ورودی کاربر را اعتبارسنجی میکنید: TryFromBase64String(). برای middleware ASP.NET Core که روی بایتهای خام درخواست عمل میکند: Base64.DecodeFromUtf8(). برای فایلهای بزرگ: CryptoStream + FromBase64Transform. BouncyCastle فقط منطقی است اگر قبلاً برای عملیات رمزنگاری دیگر در dependency tree شما باشد.
برای تأیید سریع بدون کامپایل هیچ چیزی، رمزگشای Base64 آنلاین از نوشتن یک console app یکباره سریعتر است.
سوالات متداول
چطور یک رشته Base64 را در C# به متن تبدیل کنم؟
متد Convert.FromBase64String() را فراخوانی کنید تا آرایه بایت بگیرید، سپس آن را به Encoding.UTF8.GetString() بدهید. کدگذاری باید با آنچه هنگام رمزگذاری استفاده شده مطابقت داشته باشد — UTF-8 پیشفرض امن برای تقریباً تمام سیستمهای مدرن است. اگر ورودی ممکن است شامل فضای خالی یا شکست خط باشد، قبل از رمزگشایی .Trim() فراخوانی کنید یا آنها را حذف کنید.
using System; using System.Text; string encoded = "cG9zdGdyZXM6eGs5bVAycVI="; byte[] bytes = Convert.FromBase64String(encoded); string result = Encoding.UTF8.GetString(bytes); Console.WriteLine(result); // postgres:xk9mP2qR
تفاوت Convert.FromBase64String() و Convert.TryFromBase64String() چیست؟
متد FromBase64String() در صورت ورودی نامعتبر یک FormatException پرتاب میکند. TryFromBase64String() یک bool برمیگرداند و نتیجه را در یک Span<byte> فراهمشده توسط فراخواننده مینویسد، که آن را برای مسیرهای پرکارایی که میخواهید از سربار استثنا جلوگیری کنید مناسب میکند. TryFromBase64String() نیازمند .NET 5 یا بالاتر است.
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");چطور یک payload JWT با Base64url را در C# رمزگشایی کنم؟
توکن را با نقطه تقسیم کنید، بخش دوم را بردارید، - را با + و _ را با / جایگزین کنید، با = به مضربی از 4 padding اضافه کنید، سپس Convert.FromBase64String() فراخوانی کنید. توکنهای JWT از الفبای Base64 ایمن برای URL استفاده میکنند که دیکودر استاندارد .NET مستقیماً آن را مدیریت نمیکند.
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"}چطور Encoding مناسب را هنگام رمزگشایی Base64 در C# انتخاب کنم؟
از Encoding.UTF8 به عنوان پیشفرض استفاده کنید — کاراکترهای ASCII و Unicode چندبایتی را مدیریت میکند. Encoding.ASCII را فقط زمانی استفاده کنید که مطمئن هستید دادهها کاملاً ASCII 7 بیتی هستند. Encoding.Unicode (که UTF-16LE در .NET است) را فقط زمانی استفاده کنید که دادههای اصلی به صورت UTF-16 رمزگذاری شدهاند، که گاهی در رشتههای داخلی ویندوز و خروجی PowerShell اتفاق میافتد.
چرا Convert.FromBase64String() خطای FormatException میدهد؟
سه دلیل رایج وجود دارد: ورودی شامل فضای خالی یا شکست خط است (قبل از رمزگشایی آنها را حذف کنید)، ورودی از کاراکترهای ایمن URL مانند - و _ استفاده میکند (آنها را به ترتیب با + و / جایگزین کنید)، یا padding ناقص یا اشتباه است (طول کل باید پس از padding مضربی از 4 باشد). برخلاف Java، .NET دیکودر MIME داخلی که فضای خالی را تحمل کند ندارد — باید ورودی را خودتان پاک کنید یا از CryptoStream با FromBase64Transform در حالت IgnoreWhiteSpaces استفاده کنید.
// رفع مشکل فضای خالی
string cleaned = rawInput.Replace("\n", "").Replace("\r", "").Trim();
byte[] decoded = Convert.FromBase64String(cleaned);آیا میتوانم دادههای Base64 بزرگ را به صورت streaming در C# رمزگشایی کنم؟
بله. از CryptoStream با FromBase64Transform از System.Security.Cryptography استفاده کنید. این در هنگام خواندن به صورت chunk رمزگشایی میکند، بنابراین مصرف حافظه صرف نظر از حجم فایل ثابت میماند. اگر ورودی شامل شکست خط است FromBase64TransformMode.IgnoreWhiteSpaces را پاس دهید. در .NET 6+ میتوانید از الگوی IAsyncEnumerable با Base64.DecodeFromUtf8() برای پردازش chunked دستی استفاده کنید، هرچند CryptoStream برای رمزگشایی فایل به فایل سادهتر است.
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);ابزارهای مرتبط
- Base64 Encoder — متن یا دادههای باینری را در مرورگر به Base64 رمزگذاری کنید، برای تولید test fixtureها برای الصاق در unit testهای C# شما مفید است.
- JWT Decoder — هر سه بخش JWT را یکجا رمزگشایی و بررسی کنید، با بررسی field به field payload — وقتی فقط نیاز به خواندن یک توکن دارید از نوشتن یک helper C# سریعتر است.
- URL Decoder — رشتههای URL-encoded را percent-decode کنید، هنگامی که پاسخهای API دادههای Base64url را با پارامترهای query با percent-encoding مخلوط میکنند مفید است.
- JSON Formatter — بعد از رمزگشایی payload JWT Base64 یا پیکربندی API، JSON را اینجا بچسبانید تا ساختار را pretty-print و اعتبارسنجی کنید.