Вопрос-ответ

How to encrypt String in Java

Как зашифровать строку в Java

Что мне нужно, так это зашифровать строку, которая будет отображаться в 2D штрих-коде (PDF-417), поэтому, когда кому-то придет в голову отсканировать ее, ничего читаемого не будет.

Другие требования:


  • не должно быть сложным

  • оно не должно состоять из RSA, инфраструктуры PKI, пар ключей и т.д.

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

Вероятно, эти компании могли бы использовать другие технологии, поэтому было бы хорошо придерживаться какого-то стандарта, который не привязан к какой-то специальной платформе или технологии.

Что вы предлагаете? Есть ли какой-нибудь класс Java, который делает encrypt() & decrypt() без особых сложностей для достижения высоких стандартов безопасности?

Переведено автоматически
Ответ 1

Это первая страница, которая появляется в Google, и уязвимости безопасности во всех реализациях заставляют меня съежиться, поэтому я публикую это, чтобы добавить информацию о шифровании для других, поскольку прошло 7 лет с момента первоначального сообщения. Я имею степень магистра в области компьютерной инженерии и потратил много времени на изучение криптографии, поэтому я вкладываю свои два цента, чтобы сделать Интернет более безопасным местом.


Также обратите внимание, что многие реализации могут быть безопасными для данной ситуации, но зачем использовать их и, возможно, случайно допустить ошибку? Используйте самые надежные инструменты, которые у вас есть, если только у вас нет конкретной причины не делать этого. В целом я настоятельно рекомендую использовать библиотеку и по возможности держаться подальше от мельчайших деталей.


ОБНОВЛЕНИЕ 4/5/18: Я переписал некоторые части, чтобы упростить их понимание, и заменил рекомендуемую библиотеку с Jasypt на новую библиотеку Google Tink, я бы рекомендовал полностью удалить Jasypt из существующей установки.


Предисловие

Ниже я обрисую основы безопасной симметричной криптографии и укажу на распространенные ошибки, которые я вижу в Интернете, когда люди самостоятельно внедряют криптографию с помощью стандартной библиотеки Java. Если вы хотите просто пропустить все подробности, перейдите в новую библиотеку Google Tink, импортируйте ее в свой проект и используйте режим AES-GCM для всех ваших шифрований, и вы будете в безопасности.

Теперь, если вы хотите узнать мельчайшие подробности о том, как зашифровать в Java, читайте дальше :)

Блочные шифры

Перво-наперво вам нужно выбрать блочный шифр с симметричным ключом. Блочный шифр - это компьютерная функция / программа, используемая для создания псевдослучайности. Псевдослучайность - это поддельная случайность, при которой ни один компьютер, кроме квантового, не сможет отличить ее от реальной случайности. Блочный шифр подобен строительному блоку криптографии, и при использовании с различными режимами или схемами мы можем создавать шифрования.

Теперь, что касается доступных сегодня алгоритмов блочного шифрования, убедитесь, что НИКОГДА, я повторяю, НИКОГДА не используйте DES, я бы даже сказал, НИКОГДА не используйте 3DES. Единственный блочный шифр, который даже в релизе АНБ Сноудена было подтверждено, что он действительно максимально приближен к псевдослучайному, - это AES 256. Также существует AES 128; разница в том, что AES 256 работает в 256-битных блоках, в то время как AES 128 работает в 128 блоках. В целом, AES 128 считается безопасным, хотя были обнаружены некоторые слабые места, но 256 настолько надежен, насколько это возможно.

Забавный факт: DES был взломан АНБ еще при его первоначальном создании и фактически хранился в секрете в течение нескольких лет. Хотя некоторые люди по-прежнему утверждают, что 3DES безопасен, существует довольно много исследовательских работ, в которых были обнаружены и проанализированы слабые места в 3DES.

Режимы шифрования

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

Вот пример режима шифрования и самого простого режима, известного как ECB, просто чтобы вы могли визуально понять, что происходит:

Режим ECB

The encryption modes you will see most commonly online are the following:

ECB CTR, CBC, GCM

There exist other modes outside of the ones listed and researchers are always working toward new modes to improve existing problems.

Now let's move on to implementations and what is secure. NEVER use ECB this is bad at hiding repeating data as shown by the famous Linux penguin.Linux Penguin Example

When implementing in Java, note that if you use the following code, ECB mode is set by default:

Cipher cipher = Cipher.getInstance("AES");

... DANGER THIS IS A VULNERABILITY! and unfortunately, this is seen all over StackOverflow and online in tutorials and examples.

Nonces and IVs

In response to the issue found with ECB mode nounces also known as IVs were created. The idea is that we generate a new random variable and attach it to every encryption so that when you encrypt two messages that are the same they come out different. The beauty behind this is that an IV or nonce is public knowledge. That means an attacker can have access to this but as long as they don't have your key, they cant do anything with that knowledge.

Common issues I will see is that people will set the IV as a static value as in the same fixed value in their code. and here is the pitfall to IVs the moment you repeat one you actually compromise the entire security of your encryption.

Generating A Random IV

SecureRandom randomSecureRandom = new SecureRandom();
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 из-за его сложности. Вам лучше использовать новую библиотеку Google 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% реализаций шифрования в Android были выполнены ненадлежащим образом.

Заключительные соображения

Еще раз я бы посоветовал избегать реализации библиотеки java для шифрования напрямую и использовать Google Tink, это избавит вас от головной боли, поскольку они действительно проделали хорошую работу по правильной реализации всех алгоритмов. И даже тогда убедитесь, что вы проверили проблемы, поднятые на Tink github, уязвимости, всплывающие здесь и там.

Если у вас есть какие-либо вопросы или отзывы, не стесняйтесь комментировать! Безопасность постоянно меняется, и вам нужно делать все возможное, чтобы не отставать от этого :)

Ответ 2

Я бы рекомендовал использовать какой-нибудь стандартный симметричный шифр, который широко доступен, такой как DES, 3DES или AES. Хотя это не самый безопасный алгоритм, существует множество реализаций, и вам просто нужно будет передать ключ любому, кто должен расшифровать информацию в штрих-коде. javax.crypto.Шифр - это то, с чем вы хотите работать здесь.

Предположим, что шифруемые байты находятся в

byte[] input;

Далее вам понадобятся ключ и вектор инициализации в байтах

byte[] keyBytes;
byte[] ivBytes;

Теперь вы можете инициализировать шифр для выбранного вами алгоритма:

// wrap key data in Key/IV specs to pass to cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

Шифрование будет выглядеть следующим образом:

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted= new byte[cipher.getOutputSize(input.length)];
int enc_len = cipher.update(input, 0, input.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);

И расшифровка следующим образом:

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(encrypted, 0, enc_len, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);
Ответ 3

спасибо, я создал этот класс, используя ваш код, может быть, кто-то сочтет его удобным

объектный шифровальщик

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class ObjectCrypter {

private Cipher deCipher;
private Cipher enCipher;
private SecretKeySpec key;
private IvParameterSpec ivSpec;


public ObjectCrypter(byte[] keyBytes, byte[] ivBytes) {
// wrap key data in Key/IV specs to pass to cipher


ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
try {
DESKeySpec dkey = new DESKeySpec(keyBytes);
key = new SecretKeySpec(dkey.getKey(), "DES");
deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(Object obj) throws InvalidKeyException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, ShortBufferException, BadPaddingException {
byte[] input = convertToByteArray(obj);
enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

return enCipher.doFinal(input);




// cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
// byte[] encypted = new byte[cipher.getOutputSize(input.length)];
// int enc_len = cipher.update(input, 0, input.length, encypted, 0);
// enc_len += cipher.doFinal(encypted, enc_len);
// return encypted;


}
public Object decrypt( byte[] encrypted) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException, ClassNotFoundException {
deCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

return convertFromByteArray(deCipher.doFinal(encrypted));

}



private Object convertFromByteArray(byte[] byteObject) throws IOException,
ClassNotFoundException {
ByteArrayInputStream bais;

ObjectInputStream in;
bais = new ByteArrayInputStream(byteObject);
in = new ObjectInputStream(bais);
Object o = in.readObject();
in.close();
return o;

}



private byte[] convertToByteArray(Object complexObject) throws IOException {
ByteArrayOutputStream baos;

ObjectOutputStream out;

baos = new ByteArrayOutputStream();

out = new ObjectOutputStream(baos);

out.writeObject(complexObject);

out.close();

return baos.toByteArray();

}


}
Ответ 4

You can use Jasypt

With Jasypt, encrypting and checking a password can be as simple as...

StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);

Encryption:

String myEncryptedText = textEncryptor.encrypt(myText);

Decryption:

String plainText = textEncryptor.decrypt(myEncryptedText);

Gradle:

compile group: 'org.jasypt', name: 'jasypt', version: '1.9.2'

Характеристики:


Jasypt предоставляет вам простые методы однонаправленного (digest) и двунаправленного шифрования.


Открытый API для использования с любым провайдером JCE, а не только с виртуальной машиной Java по умолчанию. Jasypt можно легко использовать с известными провайдерами, такими как Bouncy Castle. Узнать больше.


Повышенная безопасность паролей ваших пользователей. Узнать больше.


Поддержка двоичного шифрования. Jasypt позволяет обрабатывать и шифровать двоичные файлы (массивы байтов). При необходимости шифруйте ваши объекты или файлы (например, для отправки по сети).


Поддержка шифрования чисел. Помимо текстов и двоичных файлов, он позволяет обрабатывать и шифровать числовые значения (BigInteger и BigDecimal, другие числовые типы поддерживаются при шифровании для сохранения в режиме гибернации). Узнать больше.


Полностью потокобезопасен.


Поддержка пула шифровальщиков / сборщиков данных для достижения высокой производительности в многопроцессорных / многоядерных системах.


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


Предоставляет как простые инструменты шифрования без настройки для пользователей, впервые знакомых с шифрованием, так и настраиваемые стандартные инструменты шифрования для опытных пользователей.


Дополнительная интеграция Hibernate 3 и 4 для сохранения полей ваших сопоставленных объектов в зашифрованном виде. Шифрование полей определено в файлах отображения гибернации и остается прозрачным для остальной части приложения (полезно для конфиденциальных личных данных, баз данных со многими пользователями с возможностью чтения ...). Шифруйте тексты, двоичные файлы, числа, логические значения, даты... Узнать больше.


Легко интегрируется в приложение Spring со специальными функциями интеграции для Spring 2, Spring 3.0 и Spring 3.1. Все сборщики данных и шифровальщики в jasypt разработаны для простого использования (создания экземпляров, внедрения зависимостей ...) из Spring. И, поскольку они потокобезопасны, их можно использовать без проблем с синхронизацией в среде, ориентированной на синглтон, такой как Spring. Узнайте больше: Spring 2, Spring 3.0, Spring 3.1.


Spring Security (ранее Acegi Security) дополнительная интеграция для выполнения задач шифрования паролей и сопоставления для платформы безопасности, повышающая безопасность паролей ваших пользователей за счет использования более безопасных механизмов шифрования паролей и предоставляющая вам более высокую степень настройки и контроля. Узнать больше.


Предоставляет расширенные функциональные возможности для шифрования всех или части файлов конфигурации приложения, включая конфиденциальную информацию, такую как пароли базы данных. Легко интегрируйте зашифрованную конфигурацию в обычные приложения на основе Spring и / или с поддержкой гибернации. Узнать больше.


Предоставляет простые в использовании инструменты CLI (интерфейс командной строки), позволяющие разработчикам инициализировать свои зашифрованные данные и включать операции шифрования / дешифрования / дайджеста в задачи обслуживания или сценарии. Узнать больше.


Интегрируется в Apache Wicket для более надежного шифрования URL-адресов в ваших защищенных приложениях.


Подробные руководства и документация javadoc, позволяющие разработчикам лучше понимать, что они на самом деле делают со своими данными.


Надежная поддержка кодировок, разработанная для адекватного шифрования и обработки текстов независимо от исходной кодировки. Полная поддержка таких языков, как японский, корейский, арабский ... без проблем с кодировкой или платформой.


Очень высокий уровень возможностей настройки: разработчик может реализовать такие трюки, как указание "шифровальщику" запросить, например, у удаленного HTTPS-сервера пароль, который будет использоваться для шифрования. Это позволяет вам удовлетворить ваши потребности в безопасности.


java