Код для декодування / кодування модифікованої URL-адреси base64


113

Я хочу базувати дані base64, щоб розмістити їх у URL-адресі, а потім розшифрувати їх у своєму HttpHandler.

Я виявив, що кодування Base64 дозволяє використовувати символ "/", який зіпсує мою відповідність UriTemplate. Потім я виявив, що існує концепція "модифікованої Base64 для URL" з Вікіпедії:

Існує модифікований варіант Base64 для варіанту URL, де не буде використовуватися прокладка '=', а символи '+' та '/' стандартної Base64 замінюються відповідно на '-' та '_', так що використовуючи кодери / декодери URL-адрес більше не є необхідним і не впливає на довжину кодованого значення, залишаючи таку ж закодовану форму недоторканою для використання у реляційних базах даних, веб-формах та ідентифікаторах об'єктів взагалі.

Використовуючи .NET, я хочу змінити свій поточний код з базового кодування base64 та декодування до використання методу "модифікованого base64 для URL". Хтось робив це?

Для розшифровки я знаю, що це починається з чогось типу:

string base64EncodedText = base64UrlEncodedText.Replace('-', '+').Replace('_', '/');

// Append '=' char(s) if necessary - how best to do this?

// My normal base64 decoding now uses encodedText

Але мені потрібно потенційно додати до кінця одну чи дві символи '=', що виглядає трохи складніше.

Моя логіка кодування повинна бути трохи простішою:

// Perform normal base64 encoding
byte[] encodedBytes = Encoding.UTF8.GetBytes(unencodedText);
string base64EncodedText = Convert.ToBase64String(encodedBytes);

// Apply URL variant
string base64UrlEncodedText = base64EncodedText.Replace("=", String.Empty).Replace('+', '-').Replace('/', '_');

Я бачив " Посібник по Base64" для запису URL StackOverflow, але він має відому довжину, і тому вони можуть жорстко кодувати кількість рівних знаків, необхідних в кінці.


@Kirk: Відкоригуйте мою відповідь тестованою математикою.
AnthonyWJones

Відповіді:


69

Це слід правильно виправити:

 base64 = base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');

11
Ба, ти мене побив. Я просто
видалю

3
Чи не додати це до трьох знаків '='? Здається, що їх буде лише 0, 1 або 2.
Кірк Лімон

1
@Kirk: Якщо до нього додано 3 символи, рядок base64 вже пошкоджений. Я думаю, було б гарною ідеєю перевірити рядок, він повинен містити лише очікувані символи та довжину% 4! = 3.
AnthonyWJones

Хммм. Спробувавши це, це не робить фокус. Ще шукаю відповіді. Кількість знаків рівності просто не змінюється належним чином.
Кірк Лімохн

2
@AnthonyWJones 'він повинен містити лише очікувані символи та довжину% 4! = 1 ', правда?
здуття

173

Також перевірте клас HttpServerUtility з UrlTokenEncode і UrlTokenDecode методами, обробні кодуванням URL безпечного Base64 і декодуванням.

Примітка 1: Результат не є дійсним рядком Base64. Замінено деякі небезпечні символи для URL-адреси.

Примітка 2: Результат відрізняється від алгоритму base64url в RFC4648.

///<summary>
/// Base 64 Encoding with URL and Filename Safe Alphabet using UTF-8 character set.
///</summary>
///<param name="str">The origianl string</param>
///<returns>The Base64 encoded string</returns>
public static string Base64ForUrlEncode(string str)
{
    byte[] encbuff = Encoding.UTF8.GetBytes(str);
    return HttpServerUtility.UrlTokenEncode(encbuff);
}
///<summary>
/// Decode Base64 encoded string with URL and Filename Safe Alphabet using UTF-8.
///</summary>
///<param name="str">Base64 code</param>
///<returns>The decoded string.</returns>
public static string Base64ForUrlDecode(string str)
{
    byte[] decbuff = HttpServerUtility.UrlTokenDecode(str);
    return Encoding.UTF8.GetString(decbuff);
}

Дякую за пораду. Я спробую це наступного разу!
Кірк Лімохн

12
Ваша порада стала славним кінцем багатогодинного пошуку волосся та відповіді. спасибі
Praesagus

Чи не використовуватиме це кодування% для кожного / + і =? Це не так ефективно, як інша відповідь
JoelFan

Ні, він замінює рівні знаки, що використовуються для прокладки в кінці, цифрою і замінює плюси та косі риски мінусом та підкресленням.
Фредрік Хаглунд

15
Зауважте, що UrlTokenEncodeце не строго base64url , оскільки він замінює накладки '=' на "0", "1" або "2" залежно від того, скільки рівних знаків було замінено.
ladenedge

28

Не вистачає балів для коментарів, але у випадку, якщо це допомагає, фрагмент коду, який знайшов Сушіл у наданому посиланні (проект ietf Web Signature JSON Web), працює при кодуванні бази 64 як параметр у URL.

Скопійований фрагмент нижче для лінивих:

    static string Base64UrlEncode(byte[] arg)
    {
        string s = Convert.ToBase64String(arg); // Regular base64 encoder
        s = s.Split('=')[0]; // Remove any trailing '='s
        s = s.Replace('+', '-'); // 62nd char of encoding
        s = s.Replace('/', '_'); // 63rd char of encoding
        return s;
    }

    static byte[] Base64UrlDecode(string arg)
    {
        string s = arg;
        s = s.Replace('-', '+'); // 62nd char of encoding
        s = s.Replace('_', '/'); // 63rd char of encoding
        switch (s.Length % 4) // Pad with trailing '='s
        {
            case 0: break; // No pad chars in this case
            case 2: s += "=="; break; // Two pad chars
            case 3: s += "="; break; // One pad char
            default: throw new System.Exception(
              "Illegal base64url string!");
        }
        return Convert.FromBase64String(s); // Standard base64 decoder
    }

це сумісно з Xamarin, оскільки він не використовує System.Web
Reza Mortazavi

Саме те, що я шукав! Дійсно хороший варіант для Xamarin, не потребуючи бібліотеки.
Sleeping_Giant

19

Я потрапляю сюди, шукаючи код для кодування / декодування для кодування base64url, який мало відрізняється від base64, як пояснено в питанні.

У цьому документі знайдено фрагмент коду c #. Проект ietf для веб-підпису JSON


2
Це єдине рішення, яке працювало для мене під час розбору повідомлення в API GMail v1 (Message.Raw)
HeyZiko,

5

У порівнянні з прийнятою відповіддю, ось як би ви принципово розшифрували URL-адресу, кодований base64, використовуючи C #:

Розшифруйте:

string codedValue = "base64encodedUrlHere";

string decoded;
byte[] buffer =  Convert.FromBase64String(codedValue);
decoded = Encoding.UTF8.GetString(buffer);

можливо, якщо ви надасте більше деталей та порівняння з прийнятою відповіддю, ви можете отримати підсумок - спасибі
Маурісіо Грація Гутьєррес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.