Читать специальный поток, не зная количества байтов

Прежде чем вы скажете, используйте ответ Джона Скита , я не могу. Я использую этот поток , и это здорово в начале, но сейчас я столкнулся с небольшой проблемой. Сейчас я нахожусь в точке, где я не знаю, какое количество данных я ожидаю, поэтому я подумал, что буду использовать метод, предоставленный Джоном Скитом, но, к сожалению, он ожидает packet = mPackets.Take() когда все пакеты прочитаны.

Я понятия не имею, как это исправить, поток делает то, что должен делать (в начале), но, к сожалению, это тот случай, когда я не хочу, чтобы он делал то, для чего он был сделан ...

Должен ли я попробовать переписать waitingstream или есть другой readall метод, который будет работать лучше в моем случае?

Я попытался вернуть 0, когда больше не было доступных пакетов (когда я хотел, чтобы он прочитал все, а не ждать), но затем он выдает IO end of stream exception.

Я действительно в растерянности, я понимаю, что вырыл глубокую яму для себя ...

До сих пор я не смог придумать лучшего решения, чем вычитание заголовка TLS, GCM IV и MAC из общей длины (как упомянуто ниже). Это отлично работает для 1 комплекта, который я сейчас использую, но делает не может похвастаться хорошо для будущих шифров.


Некоторый контекст относительно того, почему я делаю это:
Я использую https://github.com/bcgit/bc-csharp для создания Шифрование на основе TLS, однако Из-за ограничений я не могу назначить ему поток TCP, все, что я получаю, - это строку из уровня TCP, я не могу предоставить ей пропущенный поток TCP.

Я использую mockPskTlsServer и клиент , и я создал его так:

WaitingStream mStdin = new WaitingStream();
WaitingStream mStdout = new WaitingStream();
CryptoPskTlsClient mServer = new CryptoPskTlsClient(null);
SecureRandom secureRandom = new SecureRandom();
TlsClientProtocol TlsProtocol = new TlsServerProtocol(Stdin, Stdout, secureRandom);
TlsProtocol.Connect(mServer);

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

Все это отлично работает, могло бы быть сделано лучше (меньше .... взломано?), но оно делает то, что должно.

Я знаю способы заставить его работать, но это ХАК, и я ищу элегантный способ сделать это. Вот пример кода для одного из этих хаков:

public override string DecryptData(string ciphertext)
{
    byte[] ciphertextBuff = ASCIIEncoding.Default.GetBytes(ciphertext);
    mStdin.Write(ciphertextBuff, 0, ciphertextBuff.Length);

    Stream tlsStream = mServerProtocol.Stream;
    byte[] plaintextBuffer = new byte[ciphertextBuff.Length - 29];//filthy HACK 29 bytes bij AES-GCM want TLS packet = 5, GCM IV = 8, GCM-MAC = 16 totaal = 29.
    Streams.ReadFully(tlsStream, plaintextBuffer);

    string plaintext = ASCIIEncoding.Default.GetString(plaintextBuffer);
    return plaintext;
}

или путем добавления длины открытого текста в x зарезервированных байтах к пакету TLS и извлечения этих байтов перед расшифровкой.

но, как вы можете ясно видеть из примера кода, буфер в методе read full должен иметь длину байтов, которую я хочу извлечь, она может быть меньше, чем у потока, но не может быть больше, потому что тогда он будет ждать до бесконечности.

Когда я говорю о таких методах, как ReadAll и ReadFully я имею в виду эти методы

7 голосов | спросил Vincent 4 J0000006Europe/Moscow 2015, 10:59:30

2 ответа


0
  

все, что я получаю - это строка из уровня TCP

Это, безусловно, фатальный недостаток в ваших попытках сделать эту работу. В том, что вы пытаетесь сделать, подразумевается, что данные, передаваемые по TCP-соединению, шифруются по протоколу TLS. Который производит очень случайные байтовые значения, возможно любое значение от 0 до 255. Пакет данных, который вы получите от вызова Read () сокета, это byte [], а не строка.

Преобразование байта [] в строку требует использования класса .NET Encoding. Существует много разновидностей, среди которых ASCIIEncoding, UnicodeEncoding, UTF8Encoding. И множество пользовательских, предназначенных для работы с конкретной кодовой страницей, вы получаете их с помощью конструктора Encoding (int codePage).

Мы не знаем, какую кодировку использует «уровень TCP», с которым вам нужно работать, UTF8, вероятно, будет вероятен, но это факт, что он всегда будет выдавать поврежденные данные, когда его просят преобразовать байт [ ] с зашифрованным контентом. Некоторые байтовые значения не имеют соответствующей кодовой точки Unicode. Объект кодирования решает проблему такого рода, генерируя ? или в качестве замещающего символа. Каким бы ни было значение Encoding.EncoderFallback. Некоторые шансы, что вы можете увидеть их в отладчике, хотя частота непредсказуема.

Другими словами, зашифрованные данные неизбежно будут повреждены этими заменами. Для этого нет обходного пути, вы ничего не можете сделать, чтобы восстановить исходный байт [], так как замены были потеряны. Это должно решаться нижними уровнями, им либо нужно кодировать содержимое byte [] в строку, которая всегда может быть преобразована (base64 - стандартное решение), либо необходимо прекратить преобразование данных в строка. Вам действительно нужен необработанный байт [], чтобы сделать эту работу.

ответил Georgy 4 J0000006Europe/Moscow 2015, 13:10:32
0

Вы пытались избавиться от входного потока после записи в него?

Это должно сообщить внутреннему BlockingCollection<byte> из mStdIn что больше ничего не придет. Я не уверен, если это будет распространено на ваш tlsStream.

ответил streuspeicher 9 J0000006Europe/Moscow 2015, 13:02:29

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132