파일 업로드
  1. base64hub
  2. 코드로 다루는 Base64
  3. C#
코드

C#에서 Base64 사용하기

System.Convert는 .NET Framework 1.0부터 Base64를 지원했고, .NET 9에는 URL-safe 문자열용 System.Buffers.Text.Base64Url이 추가되었습니다. 아래 출력은 .NET 9 기준입니다.

문자열 인코딩과 디코딩

Convert는 바이트를 다루므로 인코딩을 명시적으로 고르세요. 프로세스 밖으로 나가는 데이터라면 거의 언제나 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는 UTF-16LE이며 ASCII 텍스트의 크기를 두 배로 만듭니다. PowerShell 인코딩 명령 형식처럼 상대방이 UTF-16을 기대할 때만 올바른 선택입니다.

실제로 흔히 쓰는 예는 HTTP Basic Auth 헤더입니다.

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

Basic Auth 헤더 생성기는 브라우저에서 같은 값을 만들어 줍니다.

URL-safe Base64: .NET 9의 Base64Url

.NET 9에 System.Buffers.Text.Base64Url이 추가되었습니다. 인코딩할 때는 패딩을 붙이지 않고, 디코딩할 때는 패딩이 있든 없든 받습니다.

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

표준 알파벳은 거부합니다. Base64Url.DecodeFromChars("PDw/Pz8+Pg")는 FormatException을 던집니다. 할당을 피하는 span 기반 오버로드(EncodeToChars, DecodeFromUtf8, TryDecodeFromChars)도 있습니다.

Microsoft.Bcl.Memory 패키지가 없는 이전 런타임에서는 직접 변환하세요.

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

디코딩에는 반대 방향의 치환과 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 프로젝트라면 대신 Microsoft.AspNetCore.WebUtilities의 WebEncoders.Base64UrlEncode를 쓸 수 있습니다. 두 알파벳에 대한 자세한 내용은 Base64와 Base64URL 비교에 있습니다.

예외 없이 입력 검증하기

Convert.FromBase64String은 잘못된 입력에 System.FormatException을 던집니다. .NET 9에서는 거의 모든 경우에 메시지가 같습니다.

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.

PDw_Pz8-Pg==(URL-safe), aGk=!!(잡음), aGk(패딩 없음), a, aGk==에서 모두 이 메시지가 나왔습니다. 공백(" aGk= "와 "aGVs\nbG8K"는 정상적으로 디코딩됨)과 0이 아닌 패딩 비트(aGl=)는 받아들입니다.

자주 실행되는 경로에서 예외를 피하려면 버퍼와 함께 Try 변형을 쓰거나 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

버퍼는 디코딩된 출력을 담을 만큼 커야 합니다. 그렇지 않으면 올바른 입력에도 TryFromBase64String이 false를 반환합니다. 크기는 (s.Length * 3) / 4로 잡으세요. 실패하는 문자열은 Base64 검사기와 오류 가이드로 원인을 찾을 수 있습니다.

줄 바꿈 (MIME)

Base64FormattingOptions.InsertLineBreaks는 출력을 76자마다 \r\n으로 줄 바꿈하며, 끝에는 줄 바꿈을 붙이지 않습니다.

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

FromBase64String은 줄 바꿈된 형태를 수정 없이 그대로 받아들입니다. MIME Base64 인코더도 같은 배치로 출력합니다.

파일 인코딩과 디코딩

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

CryptoStream으로 큰 파일 처리하기

ToBase64Transform과 FromBase64Transform은 CryptoStream에 연결할 수 있어 메모리 사용량이 일정하게 유지됩니다. 네임스페이스와 달리 암호화는 전혀 관여하지 않습니다.

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

CryptoStream을 dispose해야 마지막 블록과 패딩이 기록됩니다. 이를 빼먹으면 출력이 잘립니다. 300 KB 테스트 파일에서 두 방향 모두 메모리 내 처리 결과와 일치했습니다. 직접 빠르게 확인하려면 결과를 Base64 파일 변환으로 열어 보세요.

흔한 함정

  • Data URI 접두사. data:image/png;base64,에는 :와 ;가 있어 FormatException을 일으킵니다. 쉼표까지 모두 잘라 내세요.
  • Convert에 URL-safe 토큰 넣기. JWT 부분은 위의 일반 메시지와 함께 실패합니다. Base64Url이나 JWT 디코더를 사용하세요.
  • Encoding.Default. .NET Framework에서는 ANSI 코드 페이지(한국어 Windows에서는 CP949)이고, .NET Core 이후에서는 UTF-8입니다. 둘 사이에서 코드를 옮기면 비 ASCII 텍스트의 출력이 달라집니다.
  • Base64는 암호화가 아닙니다. Base64로 “보호한” 연결 문자열은 누구에게나 평문입니다. 인코딩과 암호화의 차이를 참고하세요.

버전별 참고 사항

  • .NET Framework 1.0 이상: Convert.ToBase64String, FromBase64String, ToBase64Transform.
  • .NET Core 2.1 이상: span 오버로드 Convert.TryFromBase64String, TryToBase64Chars, UTF-8용 System.Buffers.Text.Base64 클래스.
  • .NET 8: Base64.IsValid.
  • .NET 9: Base64Url. 이전 대상에서도 Microsoft.Bcl.Memory를 통해 사용할 수 있습니다.

자주 묻는 질문

'The input is not a valid Base-64 string' 오류는 어떻게 고치나요?

URL-safe 문자(-, _), 누락된 패딩, Data URI 접두사가 있는지 확인하세요. Convert.FromBase64String은 패딩이 올바른 표준 알파벳만 받습니다. 토큰이라면 .NET 9의 Base64Url.DecodeFromChars를 쓰세요. 패딩이 있든 없든 받아들입니다.

.NET 8이나 .NET Framework에서도 Base64Url을 쓸 수 있나요?

Base64Url은 .NET 9 이상에 내장되어 있습니다. 이전 대상용으로는 Microsoft가 같은 타입을 Microsoft.Bcl.Memory 패키지로 제공합니다. 패키지 없이 하려면 표준 출력을 TrimEnd('=')와 Replace 호출 두 번으로 변환하세요.

텍스트를 Base64로 바꿀 때 Encoding.Unicode가 왜 잘못인가요?

Encoding.Unicode는 UTF-16LE이므로 hi가 aGk= 대신 aABpAA==가 됩니다. PowerShell의 -EncodedCommand처럼 받는 쪽이 UTF-16을 기대하는 경우가 아니라면 Encoding.UTF8을 사용하세요.

계속 읽기