Код для декодирования / кодирования измененного URL-адреса base64

Я хочу, чтобы данные в кодировке base64 помещались в URL-адрес, а затем декодировались в моем HttpHandler.

Я обнаружил, что Base64 Encoding допускает использование символа '/', который испортит мое соответствие 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('/', '_');

Я видел запись в StackOverflow Guid to Base64 для URL, но ее длина известна. и поэтому они могут жестко запрограммировать необходимое количество знаков равенства в конце.


person Kirk Liemohn    schedule 04.08.2009    source источник


Ответы (5)


Это должно правильно заполнить его: -

 base64 = base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');
person AnthonyWJones    schedule 04.08.2009
comment
Ба, ты победил меня. Я просто удалю свой пост, потому что похоже, что я тебя скопировал :) - person AaronLS; 04.08.2009
comment
Разве это не добавит до трех символов "="? Похоже, их будет только 0, 1 или 2. - person Kirk Liemohn; 04.08.2009
comment
@Kirk: Если он добавляет 3 символа, то строка base64 уже повреждена. Я думаю, было бы неплохо проверить строку, она должна содержать только ожидаемые символы и длину% 4! = 3. - person AnthonyWJones; 04.08.2009
comment
Хм. Попытка этого не сработает. Все еще ищу ответы. Количество знаков равенства просто не совпадает с правильным. - person Kirk Liemohn; 04.08.2009
comment
Ой, нужно инвертировать по модулю. - person AnthonyWJones; 05.08.2009
comment
в этом примере что такое base64? Если это System.String, то я не уверен, как это будет работать, потому что то, что у вас получится, зависит от кодировки, используемой для получения байтов. В этом конкретном примере вам может сойти с рук, потому что он использует UTF8, но с Unicode это не сработает. - person Ben Collins; 14.07.2011
comment
@Ben: Да, переменная base64 в этом примере имеет строковый тип. Я думаю, вы можете быть немного сбиты с толку, в какой момент Unicode проблема? Имейте в виду, что приведенный выше пример кода предназначен исключительно для включения соответствующего дополнения = до конца строки, чтобы гарантировать его правильное декодирование. - person AnthonyWJones; 15.07.2011
comment
@AnthonyWJones: Unicode (или любая многобайтовая кодировка) представляет собой проблему, потому что вы добавляете неправильное количество байтов. Вы можете сказать это при осмотре, но я обнаружил это после того, как попробовал ваше решение. Я не мог заставить вышеуказанное работать, когда я использовал Encoding.Unicode для получения байтов. Чтобы решить проблему независимым от кодирования способом, вы должны заполнить массив байтов, который вы передаете в Convert.ToBase64String, а не исходную строку. - person Ben Collins; 15.07.2011
comment
@Ben: Мой код заполнения появляется после а) исходная строка была преобразована в байты и б) после того, как эти байты были преобразованы в форму Base64. На это указывает входная переменная, называемая base64, и характер вопроса. На самом деле этот вопрос сводится к следующему: как дополнить строку определенным символом, чтобы длина его символа была кратной указанному целому числу. Так уж случилось, что контекст использует = для дополнения строки base64-esq кратным 4. - person AnthonyWJones; 18.07.2011
comment
@AnthonyWJones Хорошо, спасибо за разъяснения. До сих пор мне было непонятно, что вы заполняете уже закодированную строку. Проблема, над которой я работал, заключалась в заполнении строки перед кодированием, чтобы избежать наличия символов '=' в закодированном результате. - person Ben Collins; 18.07.2011
comment
@AnthonyWJones 'он должен содержать только ожидаемые символы и длину% 4! = 1', верно? - person blueling; 27.09.2013

Также проверьте класс 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);
}
person Fredrik Haglund    schedule 24.11.2009
comment
Ваш совет был великолепным завершением многочасового поиска ответа. Благодарность - person Praesagus; 13.02.2010
comment
Разве это не будет использовать кодировку% для каждого / + и =? Это не так эффективно, как другой ответ - person JoelFan; 01.06.2012
comment
Нет, он заменяет знаки равенства, используемые для заполнения в конце, числом, а плюс и косую черту заменяет минусом и подчеркиванием. - person Fredrik Haglund; 17.06.2012
comment
Обратите внимание, что UrlTokenEncode не строго base64url, поскольку он заменяет заполнение '=' с '0', '1' или '2' в зависимости от того, сколько знаков равенства он заменил. - person ladenedge; 14.08.2012

Недостаточно точек для комментария, но в случае, если это помогает, фрагмент кода, который Сушил нашел в предоставленной ссылке (проект ietf веб-подписи JSON), работает при кодировании Base 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
    }
person Stefan Zvonar    schedule 13.10.2015
comment
это совместимо с Xamarin, чтобы не использовать System.Web - person Reza Mortazavi; 02.11.2017
comment
Именно то, что я искал! Действительно хороший вариант для Xamarin без необходимости тянуть библиотеку. - person Sleeping_Giant; 02.08.2018

Я нажимаю здесь, ища код для кодирования / декодирования для кодировки base64url, которая мало отличается от base64, как описано в вопросе.

В этом документе обнаружен фрагмент кода C #. Проект ietf веб-подписи JSON

person Sushil    schedule 16.01.2013
comment
Это было единственное решение, которое сработало для меня при разборе сообщения в GMail API v1 (Message.Raw) - person HeyZiko; 18.04.2015

По сравнению с принятым ответом, вот как вы бы в основном декодировали URL-адрес в кодировке base64, используя C #:

Декодировать:

string codedValue = "base64encodedUrlHere";

string decoded;
byte[] buffer =  Convert.FromBase64String(codedValue);
decoded = Encoding.UTF8.GetString(buffer);
person Chris Halcrow    schedule 07.01.2016
comment
возможно, если вы предоставите более подробную информацию и сравните с принятым ответом, вы сможете получить положительный голос - спасибо - person Mauricio Gracia Gutierrez; 07.01.2016
comment
Это не URL-адрес в кодировке base64, а данные в кодировке base64url. - person TimTim Wong; 12.04.2021