Различия между Fprint / Fprintf против conn.Write - PullRequest
0 голосов
/ 26 февраля 2020

Я пытаюсь отправить зашифрованные данные по TCP-соединению. Fprintf отлично работает с незашифрованными данными, но, похоже, добавляет форматирование к зашифрованным данным, что приводит к прерывистой дешифровке. Я не могу отправить, используя conn.Write или, в этом отношении, writer.Writestring, за которым следует writer.Flu sh ().

    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() && err == nil {
        msg := scanner.Text()
            ciphertext := edlogic.Encrypt([]byte(msg+"\n")
            conn.Write(append(ciphertext, '\r'))
    }

    //Receiver
    scanner := bufio.NewScanner(conn)
        for scanner.Scan() {
        ciphertext := scanner.Bytes()
        plaintext := edlogic.Decrypt(ciphertext)
        fmt.Println(string(plaintext))
        }

1 Ответ

0 голосов
/ 26 февраля 2020

Здесь есть несколько моментов, которые, надеюсь, помогут вам понять, почему это не работает. Я предполагаю, что любой метод шифрования, который вы используете внутри edlogic, использует правильные ключи с обеих сторон этой транзакции, потому что мы не знаем, какую именно криптографию вы используете. Если вы не уверены, что делаете все правильно, попробуйте написать отдельную программу для шифрования некоторого известного простого текста, проверьте его, чтобы убедиться, что зашифрованный текст не похож на ваш обычный текст, расшифруйте его и сравните с исходным вводом. чтобы быть уверенным, что это соответствует. Если ваше шифрование не работает, то его передача по TCP не сможет это исправить.

Использование вашего сканера на стороне отправителя выглядит нормально, но у сканера на стороне получателя возникнут проблемы. Во-первых, все, что сказал @Adrian в своем комментарии, правильно. Вы шифруете свой \n, затем добавляете \r, а затем сканер на принимающей стороне ищет \n. Это проблематично c, и досадным решением является не просто добавить \n вместо \r. Чтобы понять почему, вам нужно узнать одну или две подробности о криптографии.

Хеширование, шифрование, дешифрование, что бы вы ни делали в современной криптографии, вы почти всегда действуете на байтах. Ввод. Вывод. Все промежуточные части вы не видите. Bytes. Существует абсолютно нулевая гарантия того, что эти байты будут содержать. Теоретически, каждый байт имеет равную вероятность содержать любое значение между 0 и 255 включительно. Нулевые байты, ASCII-выглядящие байты, может быть действительным юникодом, для всех, что вы знаете, получаются в виде десятков p oop emoji. Дело в том, что единственное безопасное предположение состоит в том, что выходные байты («зашифрованный текст», как вы правильно его обозначили, но помните, не текст в традиционном смысле) не будут выглядеть как входные байты («простой текст», также не Это должен быть текст, вы можете зашифровать двоичные файлы. Расшифрованный зашифрованный текст также называется простым текстом).

После того, как вы зашифруете свое сообщение, в необработанном выводе могут быть новые байты строки. Вы не можете использовать значение часового, например символ новой строки, в качестве разделителя. Самая простая альтернатива - закодировать байты в base64 (import "encoding/base64") и отправить их. Теперь вы можете безопасно выбрать часового, которого нет в наборе символов base64. Используйте \n и сканер, и он будет работать так, как вы ожидаете.

На стороне отправителя вы должны:

  1. Зашифровать обычный текст, чтобы получить зашифрованный текст
  2. Кодировать зашифрованный текст как base64
  3. Добавить новую строку к base64
  4. Передать данные, используя conn.Write

На другой стороне получателя вы Теперь можно:

  1. Использовать сканер для получения зашифрованного фрагмента зашифрованного текста, закодированного в base64
  2. Base64, декодировать полученные байты обратно в его зашифрованный текст
  3. Расшифровать зашифрованный текст в обычный текст
  4. Делайте все, что вы хотите сделать с простым текстом

РЕДАКТИРОВАТЬ: Я знаю, что это не отвечает на точный вопрос, на который вы ответили. Для полноты вот такой ответ:

Fprint напечатает все, что вы дадите ему Writer, но сначала попытается отформатировать другие параметры в строку. Это не хороший способ отправки байтов. fmt.Fprint(os.Stdout, []byte{1, 2, 3}) не записывает 3 байта со значениями 1, 2 и 3. Он записывает 7 байтов, строку [1 2 3], потому что именно так формататор по умолчанию fmt форматирует байтовые массивы / фрагменты.

Fprintf дает вам немного больше контроля. Вы можете использовать форматирование "глаголов" для переопределения стандартного форматера. Для байтовых массивов / срезов вы можете использовать% s, чтобы проанализировать байты как строку (не рекомендуется, если вы не знаете, что все байты являются действительными Unicode),% x и% X, чтобы напечатать байты в шестнадцатеричном виде, используя либо строчные, либо прописные буквы соответственно. и% v будет использовать форматтер по умолчанию, который будет печатать все десятичные значения байтов, разделенные пробелами, и книгу, оканчивающуюся квадратными скобками. Он по-прежнему плохо подходит для записи байтов, поскольку они являются байтами.

Я бы предположил, что conn произошел от net.Dial(...) или чего-то подобного, что, вероятно, сделало бы его интерфейсом net.Conn. Вещи, записанные в него, остаются в байтах, не проходя никакого форматирования, сопоставления или других «подделок».

О, и добро пожаловать в переполнение стека!

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