Это первая страница, которая появляется через Google, и уязвимости безопасности во всех реализациях заставляют меня съеживаться, поэтому я публикую это, чтобы добавить информацию, касающуюся шифрования для других, как это было 7 лет от первоначального поста. Я получил степень магистра в области вычислительной техники и провел много времени, изучая и изучая криптографию, поэтому я бросаю два цента, чтобы сделать Интернет более безопасным.
Кроме того, обратите внимание, что многие реализации могут быть безопасными для данной ситуации, но зачем использовать их и потенциально случайно совершить ошибку? Используйте самые сильные инструменты, которые у вас есть, если у вас нет особых причин не делать этого. В целом, я настоятельно советую использовать библиотеку и держаться подальше от мельчайших деталей, если можете.
ОБНОВЛЕНИЕ 5/5/18: Я переписал некоторые части, чтобы их было проще понять, и изменил рекомендованную библиотеку с Jasypt на новую библиотеку Google Tink. Я бы рекомендовал полностью удалить Jasypt из существующей установки.
предисловие
Ниже я опишу основы безопасной симметричной криптографии и укажу на распространенные ошибки, которые я вижу в Интернете, когда люди самостоятельно внедряют криптографию со стандартной библиотекой Java. Если вы хотите просто пропустить все детали, перейдите в новую библиотеку Google. Импортируйте Tink в ваш проект и используйте режим AES-GCM для всех ваших шифрований, и вы будете в безопасности.
Теперь, если вы хотите узнать подробности о том, как зашифровать в Java, читайте дальше :)
Блочные шифры
Первым делом сначала нужно выбрать симметричный ключ Block Cipher. Блочный шифр - это компьютерная функция / программа, используемая для создания псевдослучайности. Псевдослучайность - это ложная случайность, которую ни один компьютер, кроме Квантового Компьютера, не сможет отличить от реальной случайности. Блочный шифр подобен строительному блоку для криптографии, и при использовании с различными режимами или схемами мы можем создавать шифрование.
Что касается алгоритмов блочного шифрования, доступных сегодня, убедитесь, что НИКОГДА , я повторяю, НИКОГДА не используйте DES , я бы даже сказал, НИКОГДА не используйте 3DES . Единственный блочный шифр, который даже в выпуске NSA Сноудена смог подтвердить, что он действительно настолько близок к псевдослучайному, насколько это возможно, - это AES 256 . Там также существует AES 128; Разница в том, что AES 256 работает в 256-битных блоках, а AES 128 работает в 128 блоках. В целом, AES 128 считается безопасным, хотя некоторые недостатки были обнаружены, но 256 настолько же надежен, насколько это возможно.
Забавный факт DES был взломан АНБ еще в то время, когда он был основан и фактически держал в секрете несколько лет. Хотя некоторые люди все еще утверждают, что 3DES безопасен, существует довольно много исследовательских работ, которые обнаружили и проанализировали слабые стороны 3DES .
Режимы шифрования
Шифрование создается, когда вы берете блочный шифр и используете определенную схему, так что случайность сочетается с ключом для создания чего-то, что является обратимым, пока вы знаете ключ. Это называется режимом шифрования.
Вот пример режима шифрования и простейшего режима, известного как ECB, чтобы вы могли визуально понять, что происходит:
Режимы шифрования, которые вы чаще всего видите в Интернете, следующие:
ECB CTR, CBC, GCM
Существуют и другие способы, помимо перечисленных, и исследователи всегда работают над новыми способами, чтобы улучшить существующие проблемы.
Теперь давайте перейдем к реализации и что является безопасным. НИКОГДА не используйте ECB, это плохо для сокрытия повторяющихся данных, как показал знаменитый пингвин Linux .
При реализации в Java обратите внимание, что если вы используете следующий код, режим ECB устанавливается по умолчанию:
Cipher cipher = Cipher.getInstance("AES");
... ОПАСНОСТЬ ЭТО УЯЗВИМОСТЬ! и, к сожалению, это видно по всему StackOverflow и онлайн в учебниках и примерах.
Одноразовые и IVs
В ответ на проблему, обнаруженную в режиме ECB, были созданы существительные, также известные как IV. Идея состоит в том, что мы генерируем новую случайную переменную и прикрепляем ее к каждому шифрованию, чтобы при шифровании двух одинаковых сообщений они получались разными. Красота этого заключается в том, что IV или nonce - это общедоступное знание. Это означает, что злоумышленник может получить доступ к этому, но пока у него нет вашего ключа, он ничего не может сделать с этим знанием.
Общие проблемы, которые я увижу, состоят в том, что люди будут устанавливать IV в качестве статического значения, такого же фиксированного значения в своем коде. И вот ловушка для IV в тот момент, когда вы повторяете одно, вы фактически подвергаете риску всю безопасность вашего шифрования.
Генерация случайного IV
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
Примечание: SHA1 не работает, но я не мог найти, как правильно внедрить SHA256 в этот вариант использования, поэтому, если кто-то захочет воспользоваться этим и обновить его, это будет здорово! Также атаки SHA1 все еще являются нетрадиционными, поскольку для взлома огромного кластера может потребоваться несколько лет. Проверьте детали здесь.
Реализация CTR
Для режима CTR заполнение не требуется.
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
Реализация CBC
Если вы решили реализовать режим CBC, сделайте это с PKCS7Padding следующим образом:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Уязвимость CBC и CTR и почему вы должны использовать GCM
Хотя некоторые другие режимы, такие как CBC и CTR, являются безопасными, они сталкиваются с проблемой, когда злоумышленник может перевернуть зашифрованные данные, изменив их значение при расшифровке. Допустим, вы зашифровали воображаемое банковское сообщение «Sell 100», ваше зашифрованное сообщение выглядит так: «eu23ng», злоумышленник меняет один бит на «eu53ng», и внезапно, когда расшифровывает ваше сообщение, оно читается как «Sell 900».
Чтобы избежать этого, большинство Интернета использует GCM, и каждый раз, когда вы видите HTTPS, они, вероятно, используют GCM. GCM подписывает зашифрованное сообщение с помощью хэша и проверяет, что сообщение не было изменено с использованием этой подписи.
Я бы избегал внедрения GCM из-за его сложности. Вам лучше использовать новую библиотеку Googles Tink, потому что здесь, если вы случайно повторили IV, вы скомпрометировали ключ в случае с GCM, который является основным недостатком безопасности. Новые исследователи работают над созданием IV устойчивых режимов повторного шифрования, где, даже если вы повторяете IV, ключ не находится в опасности, но это еще не стало массовым явлением.
Теперь, если вы хотите реализовать GCM, вот ссылка на хорошую реализацию GCM . Тем не менее, я не могу обеспечить безопасность или, если она правильно реализована, но она не работает. Также обратите внимание, что с GCM нет заполнения.
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
Ключи против паролей
Еще одно очень важное замечание: когда речь заходит о криптографии, ключ и пароль - это не одно и то же. Ключ в криптографии должен иметь определенную энтропию и случайность, чтобы считаться безопасным. Вот почему вы должны убедиться, что используете соответствующие криптографические библиотеки для генерации ключа для вас.
Таким образом, у вас действительно есть две реализации, которые вы можете сделать здесь, во-первых, использовать код, найденный в этом потоке StackOverflow, для генерации случайного ключа . Это решение использует безопасный генератор случайных чисел для создания ключа с нуля, который вы можете использовать.
Другой менее безопасный вариант - использовать пользовательский ввод, такой как пароль. Проблема, о которой мы говорили, заключается в том, что паролю не хватает энтропии, поэтому нам придется использовать PBKDF2 , алгоритм, который берет пароль и усиливает его. Вот реализация StackOverflow, которая мне понравилась . Однако в библиотеке Google Tink есть все это, и вы должны воспользоваться этим.
Разработчики Android
Один важный момент, на который следует обратить внимание, это то, что вы знаете, что ваш android-код работает в обратном порядке, и в большинстве случаев большинство java-кодов тоже. Это означает, что если вы храните пароль в виде обычного текста в вашем коде. Хакер может легко получить его. Обычно для такого типа шифрования вы хотите использовать асимметричную криптографию и так далее. Это выходит за рамки этого поста, поэтому я не буду вдаваться в подробности.
Интересное чтение с 2013 года : указывает, что 88% реализаций Crypto в Android было сделано неправильно.
Последние мысли
Еще раз я бы рекомендовал избегать реализации библиотеки java для crypto напрямую и использовать Google Tink , это избавит вас от головной боли, поскольку они действительно проделали хорошую работу по реализации всех алгоритмов должным образом. И даже тогда убедитесь, что вы проверили проблемы, поднятые на GitHub Tink, уязвимости всплывают здесь и там.
Если у вас есть какие-либо вопросы или отзывы, не стесняйтесь комментировать! Безопасность всегда меняется, и вам нужно делать все возможное, чтобы не отставать от нее :)