IndexOutOfRangeException при декодировании байтов base64 с включенными символами LF (>= только .NET 5)

Я обновил среду выполнения с netcoreapp3.1 до NET 5, и код, который преобразовывал байты base64, содержащие символы LF, в строку без ошибок, начал падать с IndexOutOfRangeException. Поведение одинаково для платформ Windows и Linux.

Я уже отправил отчет об ошибке, но все равно решил спросить, есть ли что-то неправильное или подверженное ошибкам с этим кодом.

На данный момент единственным обходным решением, которое я могу придумать, является добавление потока промежуточного программного обеспечения, который удалит все символы LF из ввода, потому что пробелы в base64 в любом случае чрезмерны. Стоит отметить, что исключение не происходит с разделителем CRLF.

[TestFixture]
public class Fixture
{
    [Test]
    public void Crashes_on_runtime_greater_or_equal_to_NET_5()
    {
        var txt = "YWJj\nZGVm"; // abc\ndef
        var base64Bytes = Encoding.UTF8.GetBytes(txt);
        var stream = new MemoryStream(base64Bytes);
        var base64Transform = new FromBase64Transform();
        var cryptoStream = new CryptoStream(stream, base64Transform, CryptoStreamMode.Read);

        var result = new MemoryStream();
        cryptoStream.CopyTo(result);

        Console.WriteLine(Encoding.UTF8.GetString(result.ToArray()));
    }
}
System.IndexOutOfRangeException : Index was outside the bounds of the array.
   at System.Security.Cryptography.FromBase64Transform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.CryptoStream.ReadAsyncCore(Memory`1 buffer, CancellationToken cancellationToken, Boolean useAsync)
   at System.Security.Cryptography.CryptoStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Security.Cryptography.CryptoStream.CopyTo(Stream destination, Int32 bufferSize)
   at System.IO.Stream.CopyTo(Stream destination)
   at ClassLibrary1.Fixture.Crashes_on_runtime_greater_or_equal_to_NET_5() in E:\cm_1\drive\ClassLibrary1\Class1.cs:line 20

Это не верно!!!! Вам не хватает base64Str = Convert.ToBase64String(base64Bytes)

jdweng 12.10.2022 11:54

@jdweng Нет, это не так, о чем ты говоришь?

DavidG 12.10.2022 11:56

@CodeCaster Я думаю, что они искренне пытаются помочь, но поразительно, насколько плоха эта помощь.

DavidG 12.10.2022 11:56

Этот пример упрощен для демонстрации минимального воспроизведения. В реальном сервисе у меня есть base64 ввод большого количества байтов, которые читаются из потока, поэтому я не могу просто преобразовать их на месте. У меня высоконагруженный сервис, поэтому память просто умрет, если я не буду декодировать base64 в потоковом режиме.

idementia 12.10.2022 11:59

Да, проблема в том, что я не контролирую производственную сторону, поэтому единственный вариант - изменить ввод таким образом, чтобы он не содержал разделителей LF. Или дождаться какого-нибудь патча среды выполнения или любого другого более простого обходного пути.

idementia 12.10.2022 13:26
Стоит ли изучать 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
5
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Криптострим вызывает:

int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, ...)

С входным буфером, смещение 0, счет 8 (были прочитаны два полных блока, 2*4).

FromBase64Transform сохраняет некоторое внутреннее состояние и возвращает 6 (записано шесть байтов вывода), а затем получает последний вызов:

byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)

С ('m\0\0\0', 0, 1). Это вызывает ошибку в FromBase64Transform, особенно в агрессивно встроенном методе:

private static int GetOutputSize(int bytesToTransform, Span<byte> tmpBuffer)
{
    // ...
    if (tmpBuffer[len - 2] == padding)
}

Буфер имеет длину 1, начиная с -2, что не оценивается средой выполнения.

Либо:

  • Дополните ввод длиной % 4 (включая пробелы) посторонними символами =
  • Измените ввод с помощью обертки потока
  • Дождитесь исправления

Первый вариант выглядит проще, чем второй. Возможно воспользуюсь, спасибо

idementia 12.10.2022 14:21

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