Jak kodować i dekodować ciąg base64?


885
  1. Jak zwrócić ciąg zakodowany w standardzie base64, biorąc pod uwagę ciąg?

  2. Jak zdekodować ciąg zakodowany w standardzie base64 na ciąg?


4
Jeśli jest to pytanie i odpowiedź „dzielenie się wiedzą”, myślę, że szukamy czegoś bardziej dogłębnego. Pojawia się również szybkie wyszukiwanie SO: stackoverflow.com/a/7368168/419
Kev

1
@Gnark Każdy ciąg znaków jest kodowany przez pewien podstawowy schemat kodowania bitów. Czy to ASCII, UTF7, UTF8, ... Zadane pytanie jest w najlepszym razie niepełne.
Lorenz Lo Sauer,

2
Zadaj sobie pytanie, czy naprawdę musisz to zrobić? Pamiętaj, że base64 jest przeznaczony przede wszystkim do reprezentowania danych binarnych w ASCII, do przechowywania w polu char w bazie danych lub wysyłania przez e-mail (gdzie można wstawić nowe linie). Czy naprawdę chcesz pobrać dane znakowe, przekonwertować je na bajty, a następnie przekonwertować z powrotem na dane znakowe, tym razem nieczytelne i bez cienia oryginalnego kodowania?
bbsimonbb

Dlaczego powinniśmy dbać o oryginalne kodowanie? Kodujemy ciąg znaków do bajtów za pomocą reprezentacji UTF8, która może reprezentować wszystkie możliwe znaki ciągu. Następnie serializujemy te dane, a z drugiej strony deserializujemy te dane i odtwarzamy ten sam ciąg znaków, który pierwotnie mieliśmy (obiekt ciągu i tak nie przechowuje informacji o użytym kodowaniu). Dlaczego więc istnieją jakiekolwiek obawy związane z zastosowanym kodowaniem? Możemy uznać to za zastrzeżony sposób reprezentowania serializowanych danych, co i tak nie powinno nas zainteresować.
Mladen B.

Odpowiedzi:


1665

Kodować

public static string Base64Encode(string plainText) {
  var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
  return System.Convert.ToBase64String(plainTextBytes);
}

Rozszyfrować

public static string Base64Decode(string base64EncodedData) {
  var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
  return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}

41
Null sprawdza ciągi wejściowe w obu funkcjach i rozwiązanie jest idealne :)
Sverrir Sigmundarson

22
@SverrirSigmundarson: That lub uczyń je metodami rozszerzenia.
TJ Crowder

73
@SverrirSigmundarson - Dlaczego czek zerowy? On nie jest tym, który wyłuskuje ciąg wejściowy. Czeki zerowe powinny zapobiegać NullReferenceExceptionw twoim własnym kodzie, a nie cudzym.
Ken

16
@ken A ktoś inny powie „powinieneś ujawniać tylko błędy we własnym kodzie, a nie cudzego”, powołując się na zasadę najmniejszego zaskoczenia, doprawioną „wczesnym niepowodzeniem” i „właściwym enkapsulacją”. Czasami oznacza to błędy owijania komponentów niższego poziomu, a czasem coś zupełnie innego. W tym przypadku zgodzę się, że zawinięcie błędu deref jest zdecydowanie wątpliwe (plus wszyscy powoli zgadzamy się z faktem, że zero jako koncepcja jest trochę hack na początku), ale wciąż możemy zobaczyć pewne efekty w przeciwnym razie: nazwa parametru podana w wyjątku może być niepoprawna, jeśli nie zostanie zaznaczona.
tne

6
return System.Text.Encoding.UTF8.GetString (base64EncodedBytes, 0, base64EncodedBytes.Length); dla Windows Phone 8
Steveen Zoleko

46

Udostępniam moją implementację z kilkoma ciekawymi funkcjami:

  • używa metod rozszerzenia dla klasy kodowania. Uzasadnieniem jest to, że ktoś może potrzebować obsługi różnych rodzajów kodowania (nie tylko UTF8).
  • Kolejna poprawa kończy się niepowodzeniem z wynikiem zerowym dla wpisu zerowego - jest to bardzo przydatne w rzeczywistych scenariuszach i obsługuje równoważność dla X = dekodowania (kodowania (X)).

Uwaga: Pamiętaj, że aby użyć metody rozszerzenia, musisz (!) Zaimportować przestrzeń nazw ze usingsłowem kluczowym (w tym przypadku using MyApplication.Helpers.Encoding).

Kod:

namespace MyApplication.Helpers.Encoding
{
    public static class EncodingForBase64
    {
        public static string EncodeBase64(this System.Text.Encoding encoding, string text)
        {
            if (text == null)
            {
                return null;
            }

            byte[] textAsBytes = encoding.GetBytes(text);
            return System.Convert.ToBase64String(textAsBytes);
        }

        public static string DecodeBase64(this System.Text.Encoding encoding, string encodedText)
        {
            if (encodedText == null)
            {
                return null;
            }

            byte[] textAsBytes = System.Convert.FromBase64String(encodedText);
            return encoding.GetString(textAsBytes);
        }
    }
}

Przykład użycia:

using MyApplication.Helpers.Encoding; // !!!

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Test1();
            Test2();
        }

        static void Test1()
        {
            string textEncoded = System.Text.Encoding.UTF8.EncodeBase64("test1...");
            System.Diagnostics.Debug.Assert(textEncoded == "dGVzdDEuLi4=");

            string textDecoded = System.Text.Encoding.UTF8.DecodeBase64(textEncoded);
            System.Diagnostics.Debug.Assert(textDecoded == "test1...");
        }

        static void Test2()
        {
            string textEncoded = System.Text.Encoding.UTF8.EncodeBase64(null);
            System.Diagnostics.Debug.Assert(textEncoded == null);

            string textDecoded = System.Text.Encoding.UTF8.DecodeBase64(textEncoded);
            System.Diagnostics.Debug.Assert(textDecoded == null);
        }
    }
}

5
Powrót nullw przypadku nulljest bardzo niespójnym zachowaniem. Nie robi tego żaden inny interfejs API .net współpracujący z łańcuchami.
t3chb0t

4
@ t3chb0t dostosuj go do swoich potrzeb. Sposób prezentacji został dostosowany do naszego. To nie jest publiczny interfejs API;)
andrew.fox

1
Czy nie musisz teraz wysyłać 2 zmiennych do drugiej strony w komunikacji (do której wysyłasz dane zakodowane w standardzie base64)? Musisz wysłać zarówno użyte kodowanie, jak i rzeczywiste dane base64? Czy nie jest łatwiej, jeśli użyjesz konwencji po obu stronach, aby użyć tego samego kodowania? W ten sposób będziesz musiał tylko wysyłać dane base64, prawda?
Mladen B.

38

Na podstawie odpowiedzi Andrew Foxa i Cebe odwróciłem go i utworzyłem z nich rozszerzenia ciągów zamiast rozszerzeń Base64String.

public static class StringExtensions
{
    public static string ToBase64(this string text)
    {
        return ToBase64(text, Encoding.UTF8);
    }

    public static string ToBase64(this string text, Encoding encoding)
    {
        if (string.IsNullOrEmpty(text))
        {
            return text;
        }

        byte[] textAsBytes = encoding.GetBytes(text);
        return Convert.ToBase64String(textAsBytes);
    }

    public static bool TryParseBase64(this string text, out string decodedText)
    {
        return TryParseBase64(text, Encoding.UTF8, out decodedText);
    }

    public static bool TryParseBase64(this string text, Encoding encoding, out string decodedText)
    {
        if (string.IsNullOrEmpty(text))
        {
            decodedText = text;
            return false;
        }

        try
        {
            byte[] textAsBytes = Convert.FromBase64String(text);
            decodedText = encoding.GetString(textAsBytes);
            return true;
        }
        catch (Exception)
        {
            decodedText = null;
            return false;
        }
    }
}

1
Dodałbym ParseBase64 (ten tekst ciągu, kodowanie, out dekodowany tekst) (aby wypełnić wyjątek, jeśli to konieczne, i wywołaj to na TryParseBase64
João Antunes,

22

Niewielka odmiana odpowiedzi andrew.fox, ponieważ ciąg do dekodowania może nie być poprawnym ciągiem zakodowanym w standardzie base64:

using System;

namespace Service.Support
{
    public static class Base64
    {
        public static string ToBase64(this System.Text.Encoding encoding, string text)
        {
            if (text == null)
            {
                return null;
            }

            byte[] textAsBytes = encoding.GetBytes(text);
            return Convert.ToBase64String(textAsBytes);
        }

        public static bool TryParseBase64(this System.Text.Encoding encoding, string encodedText, out string decodedText)
        {
            if (encodedText == null)
            {
                decodedText = null;
                return false;
            }

            try
            {
                byte[] textAsBytes = Convert.FromBase64String(encodedText);
                decodedText = encoding.GetString(textAsBytes);
                return true;
            }
            catch (Exception)
            {
                decodedText = null;
                return false;   
            }
        }
    }
}

13

Poniższej procedury można użyć do konwersji ciągu znaków na format base64

public static string ToBase64(string s)
{
    byte[] buffer = System.Text.Encoding.Unicode.GetBytes(s);
    return System.Convert.ToBase64String(buffer);
}

Możesz także użyć bardzo dobrego narzędzia online OnlineUtility.in do zakodowania łańcucha w formacie base64


Narzędzia online nie pomagają w tej sytuacji - pyta, jak KODOWAĆ. Często zastanawiam się, dlaczego ludzie mówią „Sprawdź to narzędzie online!”, Ponieważ OP nie poprosił o narzędzie online: D
Momoro

9
    using System;
    using System.Text;

    public static class Base64Conversions
    {
        public static string EncodeBase64(this string text, Encoding encoding = null)
        { 
            if (text == null) return null;

            encoding = encoding ?? Encoding.UTF8;
            var bytes = encoding.GetBytes(text);
            return Convert.ToBase64String(bytes);
        }

        public static string DecodeBase64(this string encodedText, Encoding encoding = null)
        {
            if (encodedText == null) return null;

            encoding = encoding ?? Encoding.UTF8;
            var bytes = Convert.FromBase64String(encodedText);
            return encoding.GetString(bytes);
        }
    }

Stosowanie

    var text = "Sample Text";
    var base64 = text.EncodeBase64();
    base64 = text.EncodeBase64(Encoding.UTF8); //or with Encoding

4

Bezpieczny adres URL Kodowanie / dekodowanie Base64

public static class Base64Url
{
    public static string Encode(string text)
    {
        return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).TrimEnd('=').Replace('+', '-')
            .Replace('/', '_');
    }

    public static string Decode(string text)
    {
        text = text.Replace('_', '/').Replace('-', '+');
        switch (text.Length % 4)
        {
            case 2:
                text += "==";
                break;
            case 3:
                text += "=";
                break;
        }
        return Encoding.UTF8.GetString(Convert.FromBase64String(text));
    }
}

1
Pytanie nie dotyczyło kodowania adresów URL, ale nadal było pomocne ...
Momoro

Ups, opublikował to pod niewłaściwym pytaniem
juliushuck

Nie ma problemu, nadal ciekawe jest, jak kodować / dekodować adres URL :)
Momoro

3

Możesz wyświetlić go w następujący sposób:

var strOriginal = richTextBox1.Text;

byte[] byt = System.Text.Encoding.ASCII.GetBytes(strOriginal);

// convert the byte array to a Base64 string
string strModified = Convert.ToBase64String(byt);

richTextBox1.Text = "" + strModified;

Teraz konwertowanie go z powrotem.

var base64EncodedBytes = System.Convert.FromBase64String(richTextBox1.Text);

richTextBox1.Text = "" + System.Text.Encoding.ASCII.GetString(base64EncodedBytes);
MessageBox.Show("Done Converting! (ASCII from base64)");

Mam nadzieję, że to pomoże!


1

Dla tych, którzy po prostu chcą kodować / dekodować poszczególne cyfry base64:

public static int DecodeBase64Digit(char digit, string digit62 = "+-.~", string digit63 = "/_,")
{
    if (digit >= 'A' && digit <= 'Z') return digit - 'A';
    if (digit >= 'a' && digit <= 'z') return digit + (26 - 'a');
    if (digit >= '0' && digit <= '9') return digit + (52 - '0');
    if (digit62.IndexOf(digit) > -1)  return 62;
    if (digit63.IndexOf(digit) > -1)  return 63;
    return -1;
}

public static char EncodeBase64Digit(int digit, char digit62 = '+', char digit63 = '/')
{
    digit &= 63;
    if (digit < 52)
        return (char)(digit < 26 ? digit + 'A' : digit + ('a' - 26));
    else if (digit < 62)
        return (char)(digit + ('0' - 52));
    else
        return digit == 62 ? digit62 : digit63;
}

Istnieją różne wersje Base64, które nie zgadzają się co do tego, co należy stosować dla cyfr 62 i 63, więc DecodeBase64Digitmoże tolerować kilka z nich.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.