(В вашем протоколе нет Диффи-Хеллмана, только RSA и симметричное шифрование.)
Первое основное замечание - ваш протокол уязвим для активных атак. «Человек посередине» - это классика (злоумышленник перехватывает открытый ключ, заменяя его своим собственным). Кроме того, у вас есть только симметричное шифрование, но нет MAC. Давайте предположим, что ваша модель атаки касается только пассивных атакующих; в большинстве случаев это, по меньшей мере, очень смелое предположение. На самом деле, мне трудно представить себе ситуацию, когда это применимо: подслушивающий, который может просматривать переданные байты, но не может отправлять свои собственные сообщения. Если вы не запускаете все это в аутентифицированном туннеле с проверками целостности (в SSL есть режим для этого, но это своего рода победа).
Вы шифруете IV, который не нужен (IV не является ключом, иначе он будет называться «ключом», а не IV). Что вам нужно от IV - это генерировать случайным образом для каждого зашифрованного сообщения. Предполагая, что вы используете режим CBC, допустимо, чтобы последний зашифрованный блок из сообщения использовался как IV для следующего сообщения. Однако было бы смертельно опасно повторно использовать IV для двух разных сообщений с одним и тем же симметричным ключом шифрования. Поскольку Bouncy Castle не имеет класса с именем AESCipher
, ваш пример кода не сообщает нам, используете ли вы AES с правильным режимом цепочки и правильным управлением IV. Также обратите внимание, что повторное использование последнего зашифрованного блока из предыдущего сообщения работает только до тех пор, пока сообщения отправляются последовательно, а сообщения не теряются. Более надежное решение:
- выбрать новый случайный IV (через криптографически сильный ГСЧ, например,
java.security.SecureRandom
) для каждого сообщения;
- отправляет объединение IV и зашифрованные данные в виде закодированного сообщения.
Это позволяет получателю восстановить IV (как первый блок сообщения), а затем обработать сообщение независимо от того, были ли отправлены и получены предыдущие сообщения. И в этом случае активный злоумышленник может нанести ущерб этой схеме, хотя бы только с помощью простых «атак воспроизведения» (злоумышленник отправляет копию ранее отправленного сообщения).
В качестве примечания, String.getBytes()
и new String(byte[])
используют кодировку платформы по умолчанию, которая может различаться для клиента и сервера. Вам было бы лучше использовать явную кодировку, например UTF-8: message.getBytes("UTF-8")
и new String(decoded_message, "UTF-8")
.
Вообще говоря, безопасность и гордыня плохо сочетаются. Будьте готовы отказаться от вашего кода. Основная причина, по которой вы действительно должны использовать стандартные протоколы, такие как SSL / TLS, заключается в том, что безопасность не может быть доказана. Что бы вы сказали кому-то (например, вашему начальнику), спросив вас, что заставляет вас думать, что протокол безопасен? «Какой-то парень в Stack Overflow сказал мне об этом»?