Udostępnij password
(a char[]
) i salt
(- byte[]
8 bajtów wybranych przez SecureRandom
markę stanowi dobrą sól - co nie musi być utrzymywane w tajemnicy) odbiorcy spoza pasma. Następnie, aby uzyskać dobry klucz z tych informacji:
/* 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");
Liczby magiczne (które można gdzieś zdefiniować jako stałe) 65536 i 256 to odpowiednio liczba iteracji pochodnych kluczy i rozmiar klucza.
Funkcja wyprowadzania klucza jest iterowana, co wymaga znacznego wysiłku obliczeniowego, co uniemożliwia atakującym szybkie wypróbowanie wielu różnych haseł. Liczbę iteracji można zmienić w zależności od dostępnych zasobów obliczeniowych.
Rozmiar klucza można zmniejszyć do 128 bitów, co nadal jest uważane za „silne” szyfrowanie, ale nie zapewnia większego marginesu bezpieczeństwa, jeśli zostaną wykryte ataki osłabiające AES.
W tym samym kluczu pochodnym, używanym z odpowiednim trybem łączenia bloków, można szyfrować wiele wiadomości. W łańcuchu bloków szyfrów (CBC) dla każdej wiadomości generowany jest losowy wektor inicjalizacji (IV), co daje inny tekst szyfru, nawet jeśli zwykły tekst jest identyczny. CBC może nie być najbezpieczniejszym dostępnym trybem (patrz AEAD poniżej); istnieje wiele innych trybów o różnych właściwościach bezpieczeństwa, ale wszystkie wykorzystują podobne losowe dane wejściowe. W każdym przypadku wyjściami każdej operacji szyfrowania są tekst zaszyfrowany i wektor inicjalizacji:
/* 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"));
Przechowuj ciphertext
i iv
. Podczas deszyfrowania plik SecretKey
jest regenerowany dokładnie w ten sam sposób, przy użyciu hasła o tych samych parametrach soli i iteracji. Zainicjuj szyfr za pomocą tego klucza i wektora inicjalizacji zapisanego z komunikatem:
/* 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 zawiera obsługę API dla trybów szyfrowania AEAD , a dostawca „SunJCE” dołączony do dystrybucji OpenJDK i Oracle implementuje je począwszy od Java 8. Jeden z tych trybów jest zdecydowanie zalecany zamiast CBC; zapewni ochronę integralności danych, a także ich prywatności.
A java.security.InvalidKeyException
z komunikatem „Nielegalny rozmiar klucza lub parametry domyślne” oznacza, że siła kryptografii jest ograniczona; pliki zasad jurysdykcji o nieograniczonej sile nie znajdują się we właściwej lokalizacji. W JDK należy je umieścić pod${jdk}/jre/lib/security
Na podstawie opisu problemu wygląda na to, że pliki zasad nie są poprawnie zainstalowane. Systemy mogą łatwo mieć wiele środowisk wykonawczych Java; sprawdź dwukrotnie, aby upewnić się, że używana jest poprawna lokalizacja.