Разные результаты после кодирования/декодирования base64

У меня есть следующая строка base64:

R1NNQiBBZ2VuY3kgR21iSCAvIFdlYmRlc2lnbiBBZ2VudHVyIFVsbSAvIE9ubGluZXNob3AgQWdlbnR1ciAvIEFwcCBBZ2VudHVyIFVsbSwgR2VybWFueS==

И используя онлайн-декодер base64, я получаю следующий результат:

GSMB Agency GmbH / Webdesign Agentur Ulm / Onlineshop Agentur / App Agentur Ulm, Germany

Все хорошо, верно? Но теперь, если я попытаюсь преобразовать этот текст обратно в base64, результат станет

R1NNQiBBZ2VuY3kgR21iSCAvIFdlYmRlc2lnbiBBZ2VudHVyIFVsbSAvIE9ubGluZXNob3AgQWdlbnR1ciAvIEFwcCBBZ2VudHVyIFVsbSwgR2VybWFueQ==

Есть идеи?

Это код С#, который я использую для декодирования:

string basestring = "R1NNQiBBZ2VuY3kgR21iSCAvIFdlYmRlc2lnbiBBZ2VudHVyIFVsbSAvIE9ubGluZXNob3AgQWdlbnR1ciAvIEFwcCBBZ2VudHVyIFVsbSwgR2VybWFueS= = ";

string output = Encoding.UTF8.GetString(Convert.FromBase64String(basestring));

return output;

И вот часть кодирования

string basestring = "GSMB Agency GmbH / Webdesign Agentur Ulm / Onlineshop Agentur / App Agentur Ulm, Germany";

string output = Convert.ToBase64String(Encoding.UTF8.GetBytes(basestring));

return output;

Связанный, возможный дубликат: Является ли строка в кодировке base64 уникальной?

Brian 30.01.2023 01:45

Я удалил тег шифрования, потому что этот вопрос не имеет ничего общего с шифрованием.

Brian 30.01.2023 01:49

Похоже, что один из этих кодировщиков использует неинициализированную переменную. Но на практике это не должно иметь значения.

Jeremy Lakeman 30.01.2023 02:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На самом деле это артефакт перехода от 8-битной кодировки (UTF8) к 6-битной кодировке (Base64).
В качестве справки, вот таблица кодировки Base64

Возьмем пример строки "AB"; A и B являются символами (65 и 66) соответственно. В 8-битной двоичной группе 65/66 равны 01000001/01000010.

Кодирование

При кодировании в Base64 одни и те же биты вашей строки разделяются на группы по 6 вместо 8. Таким образом, та же 16-битная последовательность выше разбивается на 010000/010100/0010 (тот же битовый шаблон, просто сгруппированный по-другому).

Итак, первые две группы просты. Вы посмотрите таблицу кодирования, указанную выше, и увидите, что 010000 = Q / 010100 = U. Затем у вас есть последняя группа только с 4 битами вместо ожидаемых 6. Здесь все становится интереснее.

При кодировании конец обычно дополняется нулями, чтобы получить 6 бит. Таким образом, ваше 0010 становится 001000, то есть I. Итак, "AB" при кодировании в Base64 становится "QUI = ". = не является обязательным, он нужен только для того, чтобы число символов было кратно 4.

Расшифровка

Помните, когда ваша последняя группа 0010 была дополнена до 6 бит? Вот самое интересное: они не обязательно должны быть нулями. 16-бит (2x8) в исходной строке стали 18-битами (3x6) из-за заполнения. Поскольку 18 не кратно 8 (битам), кодер/декодер знает достаточно, чтобы отбросить лишние биты. Таким образом, двухбитное заполнение может быть любым, и они все равно будут правильно декодироваться.

0010 при заполнении может быть 001000, 001001, 001010 или 001011, что переводится как I, J, K, or L. Поднимите любой декодер и попробуйте расшифровать QUI, QUJ, QUK и QUL. Все они будут расшифрованы в "AB"

Ваша строка

Теперь ваша строка при разделении 6-битных групп выглядит следующим образом (см. fiddle):

var basestring = "GSMB Agency GmbH / Webdesign Agentur Ulm / Onlineshop Agentur / App Agentur Ulm, Germany";
var sixBitGroups = Encoding.UTF8.GetBytes(basestring)
  .SelectMany(b => $"{Convert.ToString(b, 2).PadLeft(8,'0')}")
  .Chunk(6)
  .Select(c => new string(c.ToArray()));
string.Join("/", sixBitGroups).Dump();

Вы заметите, что оно заканчивается на ../01. Это 01 нужно дополнить 4 дополнительными битами. Опять же, обычно это нули, что делает 010000 то есть Q. Итак, вы увидите, что ваша закодированная строка заканчивается на ..FueQ==. Но когда вы поймете, что они не обязательно должны быть все нулями, вы увидите в таблице , что 01xxxx охватывает все, начиная с Q,R,S, .. i,j. Это объясняет, почему ваш base64 ..FueS== все еще декодирует ту же самую строку.

Хорошо, спасибо за такой подробный ответ, это определенно будет полезно знать в будущем!

Tomas Dovidavičius 30.01.2023 14:43

Просто примечание: этими битами заполнения можно злоупотреблять для отправки скрытой информации, если можно сгенерировать и отправить большое количество строк base64.

Oliver 30.01.2023 14:47

Другие вопросы по теме