Как использовать потоковый шифр для шифрования данных TCP?
Я пытаюсь использовать шифрование chacha20 в своем сетевом программном обеспечении, но у меня возникла проблема
если я зашифрую 4 байта данных: 0x01 0x02 0x03 0x04
на сервере
и получить зашифрованный текст: 0xd2 0xd3 0xc4 0xd5
, а затем отправить его клиенту
клиент может получить <= 4 байта за раз
при условии, что клиент только recv 0xd2 0xd3
вначале,
он может правильно расшифровать данные и получить открытый текст 0x01 0x02
но когда клиент получает последние 2 байта 0xc4 0xd5
кажется, что данные не могут быть расшифрованы с использованием того же одноразового номера и ключа
так есть ли способ решить проблему
Добавление данных длины в качестве префикса перед отправкой - решение, но это странно, потому что я использую потоковый шифр.
2 ответа
Вместо перезапуска экземпляра шифра ChaCha20 (или, более общего, контекста) вы должны сохранить его.
Большинство криптографических API-интерфейсов позволит вам выполнять частичное шифрование / дешифрование. Это обычно означает вызов update
метод для первой части и второй части, обычно сопровождаемый final
метод, когда обнаружен конец открытого / зашифрованного текста. В зависимости от API вы должны ожидать вывода для каждого из этих методов.
Только если ваш API не позволяет вам правильно обрабатывать поток, вам следует объединить зашифрованный текст и выполнить расшифровку полного зашифрованного текста.
ChaCha20 генерирует поток, используя ключ и одноразовый номер. Позволять (S0, S1, S2, S3)
первые байты потока и (M0, M1, M2, M3)
первые 4 байта вашего сообщения.
Зашифрованный текст будет вычислен как (M0⊕S0, M1⊕S1, M2⊕S2, M3⊕S3)
, Это если у вас есть M0...M3
легко доступны.
Если вы шифруете (M0, M1)
затем (M2, M3)
используя тот же ключ и nonce, вы получите (M0⊕S0, M1⊕S1)
а также (M2⊕S0, M3⊕S1)
, Который не может быть расшифрован с помощью (C0⊕S0, C1⊕S1, C2⊕S2, C3⊕S3)
,
Еще хуже, так как S0
а также S1
были повторно использованы с различными сообщениями, злоумышленник может восстановить их, зная любое сообщение.
Чтобы избежать этого, проще всего выполнить буферизацию данных до достижения размера блока, а затем зашифровать весь блок вместо попытки зашифровать частичные блоки.