Co jest nie tak z następującym przykładem?
Problem polega na tym, że pierwsza część odszyfrowanego ciągu jest nonsensowna. Jednak reszta jest w porządku, dostaję ...
Result: `£eB6O�geS��i are you? Have a nice day.
@Test
public void testEncrypt() {
try {
String s = "Hello there. How are you? Have a nice day.";
// Generate key
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
SecretKey aesKey = kgen.generateKey();
// Encrypt cipher
Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);
// Encrypt
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptCipher);
cipherOutputStream.write(s.getBytes());
cipherOutputStream.flush();
cipherOutputStream.close();
byte[] encryptedBytes = outputStream.toByteArray();
// Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
// Decrypt
outputStream = new ByteArrayOutputStream();
ByteArrayInputStream inStream = new ByteArrayInputStream(encryptedBytes);
CipherInputStream cipherInputStream = new CipherInputStream(inStream, decryptCipher);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = cipherInputStream.read(buf)) >= 0) {
outputStream.write(buf, 0, bytesRead);
}
System.out.println("Result: " + new String(outputStream.toByteArray()));
}
catch (Exception ex) {
ex.printStackTrace();
}
}
java
encryption
aes
TedTrippin
źródło
źródło
Odpowiedzi:
Wiele osób, w tym ja, napotyka wiele problemów podczas wykonywania tej pracy z powodu braku niektórych informacji, takich jak zapomnienie o konwersji do Base64, wektorach inicjalizacyjnych, zestawie znaków itp. Pomyślałem więc o stworzeniu w pełni funkcjonalnego kodu.
Mam nadzieję, że przyda się to wszystkim: aby skompilować, potrzebujesz dodatkowego jar Apache Commons Codec, który jest dostępny tutaj: http://commons.apache.org/proper/commons-codec/download_codec.cgi
źródło
System.out.println("encrypted string:" + DatatypeConverter.printBase64Binary(encrypted));
byte[] original = cipher.doFinal(DatatypeConverter.parseBase64Binary(encrypted));
SecureRandom
Oto rozwiązanie bez
Apache Commons Codec
„sBase64
:Przykład użycia:
Wydruki:
źródło
encrypt(String)
a nieencrypt(byte[] )
? Szyfrowanie (również deszyfrowanie) jest procesem opartym na bajtach (tak czy inaczej AES). Szyfrowanie przyjmuje bajty jako dane wejściowe i wyprowadza bajty, podobnie jak deszyfrowanie (przykład:Cipher
obiekt robi). Otóż, jednym szczególnym przypadkiem użycia może być zaszyfrowanie bajtów pochodzących ze Stringa lub wysłanie ich jako String (załącznik MIME base64 dla poczty ...), ale jest to kwestia kodowania bajtów, dla których istnieją setki rozwiązania całkowicie niezwiązane z AES / szyfrowaniem.Strings
ponieważ w zasadzie pracuję w 95% przypadków, a ty i tak konwertujesz.Wydaje mi się, że nie radzisz sobie właściwie z wektorem inicjalizacyjnym (IV). Minęło dużo czasu, odkąd ostatnio czytałem o AES, IV i łańcuchach bloków, ale twoja linia
nie wydaje się być w porządku. W przypadku AES, możesz myśleć o wektorze inicjującym jako o „stanie początkowym” instancji szyfru, a ten stan to trochę informacji, których nie możesz uzyskać z klucza, ale z rzeczywistego obliczenia szyfru szyfrującego. (Można by argumentować, że gdyby IV można było wyodrębnić z klucza, nie byłoby to przydatne, ponieważ klucz jest już przekazany instancji szyfru podczas fazy inicjalizacji).
Dlatego powinieneś otrzymać IV jako bajt [] z instancji szyfru na końcu twojego szyfrowania
i powinieneś zainicjować swój
Cipher
inDECRYPT_MODE
tym bajtem []:Następnie odszyfrowanie powinno być OK. Mam nadzieję że to pomoże.
źródło
IV, którego używasz do odszyfrowania, jest nieprawidłowy. Zastąp ten kod
Z tym kodem
I to powinno rozwiązać twój problem.
Poniżej znajduje się przykład prostej klasy AES w Javie. Nie polecam używania tej klasy w środowiskach produkcyjnych, ponieważ może ona nie uwzględniać wszystkich specyficznych potrzeb aplikacji.
Zauważ, że AES nie ma nic wspólnego z kodowaniem, dlatego zdecydowałem się obsługiwać go osobno i bez potrzeby jakichkolwiek bibliotek innych firm.
źródło
"/NoPadding"
. CTR to tryb, który zamienia AES w szyfr strumieniowy, a szyfr strumieniowy działa na bajtach zamiast blokach.W tej odpowiedzi zdecydowałem się podejść do głównego tematu „Prosty przykład szyfrowania / odszyfrowania w języku Java AES”, a nie do konkretnego pytania dotyczącego debugowania, ponieważ myślę, że przyniesie to korzyści większości czytelników.
To jest proste podsumowanie mojego wpisu na blogu na temat szyfrowania AES w Javie, więc polecam przeczytać go przed wdrożeniem czegokolwiek. Podam jednak prosty przykład do użycia i kilka wskazówek, na co należy uważać.
W tym przykładzie wybiorę użycie uwierzytelnionego szyfrowania w trybie Galois / Counter lub GCM . Powodem jest to, że w większości przypadków zależy Ci na uczciwości i autentyczności w połączeniu z poufnością (czytaj więcej na blogu ).
Samouczek szyfrowania / deszyfrowania AES-GCM
Oto kroki wymagane do szyfrowania / odszyfrowywania za pomocą AES-GCM z architekturą Java Cryptography Architecture (JCA) . Nie mieszaj z innymi przykładami , ponieważ subtelne różnice mogą spowodować, że Twój kod będzie całkowicie niepewny.
1. Utwórz klucz
Ponieważ zależy to od twojego przypadku użycia, przyjmuję najprostszy przypadek: losowy tajny klucz.
Ważny:
SecureRandom
2. Utwórz wektor inicjujący
Wektor inicjujący (IV) jest używany tak, że ten sam klucz tajny będzie tworzyć różne teksty szyfr .
Ważny:
SecureRandom
3. Szyfruj za pomocą IV i klucza
Ważny:
CipherInputStream
podczas szyfrowania dużych fragmentów danychcipher.updateAAD(associatedData);
Więcej tutaj.3. Serializuj do pojedynczej wiadomości
Wystarczy dołączyć IV i zaszyfrowany tekst. Jak wspomniano powyżej, IV nie musi być tajne.
Opcjonalnie zakoduj za pomocą Base64, jeśli potrzebujesz reprezentacji ciągu. Użyj wbudowanej implementacji Androida lub Java 8 (nie używaj kodeka Apache Commons - to okropna implementacja). Kodowanie służy do „konwersji” tablic bajtowych na reprezentację łańcuchową, aby zapewnić bezpieczeństwo ASCII, np .:
4. Przygotuj deszyfrowanie: deserializacja
Jeśli zakodowałeś wiadomość, najpierw zdekoduj ją do tablicy bajtów:
Ważny:
5. Odszyfruj
Zainicjuj szyfr i ustaw te same parametry, co przy szyfrowaniu:
Ważny:
cipher.updateAAD(associatedData);
jeśli dodałeś je podczas szyfrowania.W tym streszczeniu można znaleźć działający fragment kodu.
Zauważ, że najnowsze implementacje Androida (SDK 21+) i Java (7+) powinny mieć AES-GCM. Starsze wersje mogą go nie mieć. Nadal wybieram ten tryb, ponieważ jest łatwiejszy do wdrożenia i jest bardziej wydajny w porównaniu do podobnego trybu Encrypt-then-Mac (z np. AES-CBC + HMAC ). Zobacz ten artykuł o tym, jak wdrożyć AES-CBC z HMAC .
źródło
this is true for CBC mode but not for GCM
masz na myśli całą część, czy tylko to, że faktycznie nie musi być nieprzewidywalne?Wersja do uruchamiania edytora online: -
źródło
Często dobrym pomysłem jest skorzystanie z rozwiązania dostarczanego przez bibliotekę standardową:
Spowoduje to wyświetlenie tekstu „Tekst do zakodowania”.
Rozwiązanie jest oparte na podręczniku Java Cryptography Architecture Reference Guide i https://stackoverflow.com/a/20591539/146745 answer.
źródło
To poprawa w stosunku do zaakceptowanej odpowiedzi.
Zmiany:
(1) Używając losowego IV i dołącz go do zaszyfrowanego tekstu
(2) Używanie SHA-256 do generowania klucza na podstawie hasła
(3) Brak zależności od Apache Commons
źródło
Kolejne rozwiązanie wykorzystujące java.util.Base64 z Spring Boot
Klasa szyfrująca
Klasa EncryptorController
application.properties
Przykład
http: // localhost: 8082 / cipher / encrypt / jmendoza
2h41HH8Shzc4BRU3hVDOXA ==
http: // localhost: 8082 / cipher / decrypt / 2h41HH8Shzc4BRU3hVDOXA ==
jmendoza
źródło
Zoptymalizowana wersja zaakceptowanej odpowiedzi.
brak bibliotek innych firm
włącza IV do zaszyfrowanej wiadomości (może być publiczna)
hasło może mieć dowolną długość
Kod:
Stosowanie:
Przykładowe dane wyjściowe:
źródło
e.printStackTrace()
tak zwanego kodu zoptymalizowanego.