Поделитесь password
(a char[]
) и salt
(a - byte[]
8 байтов, выбранных символом a, SecureRandom
- хорошей солью, которую не нужно хранить в секрете) с получателем вне диапазона. Затем, чтобы получить хороший ключ из этой информации:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Магические числа (которые могут быть определены как константы где-то) 65536 и 256 - это количество итераций вывода ключа и размер ключа соответственно.
Функция получения ключа повторяется, чтобы потребовать значительных вычислительных усилий, и это не позволяет злоумышленникам быстро пробовать много разных паролей. Количество итераций может быть изменено в зависимости от доступных вычислительных ресурсов.
Размер ключа может быть уменьшен до 128 бит, который все еще считается «сильным» шифрованием, но он не дает большой запас прочности, если обнаружены атаки, которые ослабляют AES.
При использовании с надлежащим режимом цепочки блоков один и тот же производный ключ может использоваться для шифрования многих сообщений. В Cipher Block Chaining (CBC) случайный вектор инициализации (IV) генерируется для каждого сообщения, давая различный зашифрованный текст, даже если обычный текст идентичен. CBC может быть не самым безопасным режимом, доступным для вас (см. AEAD ниже); Есть много других режимов с различными свойствами безопасности, но все они используют одинаковый случайный ввод. В любом случае выходные данные каждой операции шифрования представляют собой зашифрованный текст и вектор инициализации:
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
Храните ciphertext
и iv
. При дешифровании, SecretKey
регенерируется точно так же, используя пароль с теми же параметрами соли и итерации. Инициализируйте шифр с этим ключом и вектором инициализации, сохраненным с сообщением:
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);
Java 7 включала поддержку API для режимов шифрования AEAD , и поставщик SunJCE, включенный в дистрибутивы OpenJDK и Oracle, реализует их начиная с Java 8. Один из этих режимов настоятельно рекомендуется вместо CBC; это защитит целостность данных, а также их конфиденциальность.
java.security.InvalidKeyException
С сообщением «Незаконные размер ключа или по умолчанию параметров» означает , что сила криптография является ограниченным; файлы политики неограниченной юрисдикции находятся не в правильном месте. В JDK они должны быть помещены под${jdk}/jre/lib/security
Судя по описанию проблемы, похоже, что файлы политики установлены неправильно. Системы могут легко иметь несколько сред выполнения Java; перепроверьте, чтобы убедиться, что используется правильное местоположение.