Niepoprawne początkowe bajty po odszyfrowaniu Java AES/CBC
Co jest nie tak z poniższym przykładem?
Problem w tym, że pierwsza część odszyfrowanego ciągu jest nonsensem. Jednak reszta jest w porządku, Rozumiem...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();
}
}
10 answers
Wiele osób, w tym ja, napotyka wiele problemów z wykonaniem tej pracy z powodu braku niektórych informacji, takich jak, zapominanie o konwersji do Base64, wektory inicjalizacyjne, zestaw znaków itp. Więc pomyślałem o stworzeniu w pełni funkcjonalnego kodu.
Mam nadzieję, że będzie to przydatne dla was wszystkich: Do kompilacji potrzebny jest dodatkowy Jar Apache Commons Codec, który jest dostępny tutaj: http://commons.apache.org/proper/commons-codec/download_codec.cgi
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Encryptor {
public static String encrypt(String key, String initVector, String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string: "
+ Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String key = "Bar12345Bar12345"; // 128 bit key
String initVector = "RandomInitVector"; // 16 bytes IV
System.out.println(decrypt(key, initVector,
encrypt(key, initVector, "Hello World")));
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 16:49:46
Tutaj rozwiązanie bez Apache Commons Codec
's Base64
:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AdvancedEncryptionStandard
{
private byte[] key;
private static final String ALGORITHM = "AES";
public AdvancedEncryptionStandard(byte[] key)
{
this.key = key;
}
/**
* Encrypts the given plain text
*
* @param plainText The plain text to encrypt
*/
public byte[] encrypt(byte[] plainText) throws Exception
{
SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(plainText);
}
/**
* Decrypts the given byte array
*
* @param cipherText The data to decrypt
*/
public byte[] decrypt(byte[] cipherText) throws Exception
{
SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(cipherText);
}
}
Przykład użycia:
byte[] encryptionKey = "MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8);
byte[] plainText = "Hello world!".getBytes(StandardCharsets.UTF_8);
AdvancedEncryptionStandard advancedEncryptionStandard = new AdvancedEncryptionStandard(
encryptionKey);
byte[] cipherText = advancedEncryptionStandard.encrypt(plainText);
byte[] decryptedCipherText = advancedEncryptionStandard.decrypt(cipherText);
System.out.println(new String(plainText));
System.out.println(new String(cipherText));
System.out.println(new String(decryptedCipherText));
Druki:
Hello world!
դ;��LA+�b*
Hello world!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-20 14:33:41
Wygląda na to, że nie radzisz sobie właściwie ze swoim wektorem inicjalizacji (IV). Dawno nie czytałem o AES, kroplówkach i łańcuchowaniu bloków, ale twoja linia
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
Nie wydaje się być w porządku. W przypadku AES wektor inicjalizacji można traktować jako "stan początkowy" instancji szyfru, a stan ten jest fragmentem informacji, których nie można uzyskać z klucza, ale z rzeczywistego obliczenia szyfru szyfrującego. (Można by argumentować, że jeśli IV może być wydobyty z klucza, wtedy nie będzie użyteczny, ponieważ klucz jest już przekazany instancji szyfru w fazie init).
Dlatego powinieneś uzyskać IV jako bajt [] z instancji szyfru na końcu szyfrowania
cipherOutputStream.close();
byte[] iv = encryptCipher.getIV();
I powinieneś zainicjować swoje Cipher
w DECRYPT_MODE
tym bajtem []:
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Wtedy twoje odszyfrowanie powinno być OK. Mam nadzieję, że to pomoże.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-29 13:45:38
IV, którego używasz do deszyfrowania jest niepoprawne. Zastąp ten kod
//Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
Z tym kodem
//Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptCipher.getIV());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
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 nie uwzględniać wszystkich specyficznych potrzeb Twojej aplikacji.
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AES
{
public static byte[] encrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
{
return AES.transform(Cipher.ENCRYPT_MODE, keyBytes, ivBytes, messageBytes);
}
public static byte[] decrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
{
return AES.transform(Cipher.DECRYPT_MODE, keyBytes, ivBytes, messageBytes);
}
private static byte[] transform(final int mode, final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
{
final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
final IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
byte[] transformedBytes = null;
try
{
final Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(mode, keySpec, ivSpec);
transformedBytes = cipher.doFinal(messageBytes);
}
catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e)
{
e.printStackTrace();
}
return transformedBytes;
}
public static void main(final String[] args) throws InvalidKeyException, InvalidAlgorithmParameterException
{
//Retrieved from a protected local file.
//Do not hard-code and do not version control.
final String base64Key = "ABEiM0RVZneImaq7zN3u/w==";
//Retrieved from a protected database.
//Do not hard-code and do not version control.
final String shadowEntry = "AAECAwQFBgcICQoLDA0ODw==:ZtrkahwcMzTu7e/WuJ3AZmF09DE=";
//Extract the iv and the ciphertext from the shadow entry.
final String[] shadowData = shadowEntry.split(":");
final String base64Iv = shadowData[0];
final String base64Ciphertext = shadowData[1];
//Convert to raw bytes.
final byte[] keyBytes = Base64.getDecoder().decode(base64Key);
final byte[] ivBytes = Base64.getDecoder().decode(base64Iv);
final byte[] encryptedBytes = Base64.getDecoder().decode(base64Ciphertext);
//Decrypt data and do something with it.
final byte[] decryptedBytes = AES.decrypt(keyBytes, ivBytes, encryptedBytes);
//Use non-blocking SecureRandom implementation for the new IV.
final SecureRandom secureRandom = new SecureRandom();
//Generate a new IV.
secureRandom.nextBytes(ivBytes);
//At this point instead of printing to the screen,
//one should replace the old shadow entry with the new one.
System.out.println("Old Shadow Entry = " + shadowEntry);
System.out.println("Decrytped Shadow Data = " + new String(decryptedBytes, StandardCharsets.UTF_8));
System.out.println("New Shadow Entry = " + Base64.getEncoder().encodeToString(ivBytes) + ":" + Base64.getEncoder().encodeToString(AES.encrypt(keyBytes, ivBytes, decryptedBytes)));
}
}
Zauważ, że AES nie ma nic wspólnego z kodowaniem, dlatego zdecydowałem się obsługiwać go osobno i bez potrzeby bibliotek stron trzecich.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-07 17:51:01
w tej odpowiedzi wybieram podejście do głównego motywu" Simple Java AES encrypt/decrypt example", a nie do konkretnego pytania debugowania, ponieważ myślę, że przyniesie to korzyści większości czytelników.
Jest to proste podsumowanie mojego posta na blogu o szyfrowaniu AES w Javie więc polecam przeczytać go przed wdrożeniem czegokolwiek. Jednak nadal podam prosty przykład do użycia i podam kilka wskazówek, na co należy uważać.
W tym przykładzie będę wybierz użycie uwierzytelnionego szyfrowania z trybem Galois/Counter lub trybem GCM. Powodem jest to, że w większości przypadków chcesz integralności i autentyczności w połączeniu z poufnością (więcej na blog ).
Samouczek szyfrowania/deszyfrowania AES-GCM
Oto kroki wymagane do szyfrowania / deszyfrowania za pomocą AES-GCM za pomocą Java Cryptography Architecture (JCA). Nie mieszaj z innymi przykładami, ponieważ subtelne różnice mogą sprawić, że Twój kod będzie całkowicie niepewny.
1. Utwórz Klucz
Ponieważ zależy to od Twojego przypadku użycia, zakładam najprostszy przypadek: losowy tajny klucz.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Ważne:
- Zawsze używaj silnego generatora liczb pseudorandomowych Jak
SecureRandom
16-bajtowy / 128 - bitowy klucz (lub więcej - , ale więcej rzadko jest potrzebne)
- jeśli chcesz, aby klucz pochodził z hasła użytkownika, zajrzyj do password hash function (lub KDF) with stretching property like PBKDF2 or bcrypt
- jeśli chcesz, aby klucz pochodził z innych źródeł, użyj odpowiedniej funkcji wyprowadzania kluczy (KDF) Jak HKDF (implementacja Javy tutaj ). Do nie używaj prostych kryptograficznych skrótów (Jak SHA-256).
2. Tworzenie wektora inicjalizacji
An inicjalizacja wektor (IV) jest używany tak, że ten sam tajny klucz utworzy różne teksty szyfrów.
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
Ważne:
- nigdy używaj ponownie tego samego IV z tym samym kluczem (bardzo ważne w GCM/CTR mode)
- IV musi być unikalny (tj. użyj random IV lub licznika)
- IV nie musi być tajemnicą
- Zawsze używaj silnego generatora liczb pseudorandomowych Jak
SecureRandom
- 12 bajt IV jest prawidłowym wyborem dla trybu AES-GCM
3. Szyfruj za pomocą IV i klucza
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
Ważne:
- 16 bajtów / 128 bitów znacznik uwierzytelniania (używany do weryfikacji integralności / autentyczności)
Znacznik uwierzytelniania zostanie automatycznie dołączony do zaszyfrowanego tekstu (w implementacji JCA).]}
- ponieważ GCM zachowuje się jak szyfr strumieniowy, brak wypełnienia jest wymagane
- użycie
CipherInputStream
podczas szyfrowania dużych fragmentów danych - chcesz sprawdzić dodatkowe (jawne) dane, jeśli zostały zmienione? Możesz użyć powiązanych danych z
cipher.updateAAD(associatedData);
więcej tutaj.
3. Serialize to Single Message
Po prostu dołącz IV i tekst szyfrowy. Jak wspomniano powyżej, IV nie musi być tajemnicą.
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Opcjonalnie Zakoduj za pomocą Base64 jeśli potrzebujesz reprezentacji ciągu znaków. Albo użyć Android lub Java 8 wbudowana implementacja (nie używaj kodeka Apache Commons - to okropna implementacja). Kodowanie jest używane do "konwersji" tablic bajtowych na reprezentację łańcuchową, aby zapewnić bezpieczeństwo ASCII, np.:
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
4. Przygotowanie Deszyfrowania: Deserialize
Jeśli zakodowałeś wiadomość, najpierw dekoduj ją do tablicy bajtów:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Ważne:
- należy uważać, aby zweryfikować parametry wejściowe, aby uniknąć Ataki typu denial of service poprzez przydzielanie zbyt dużej ilości pamięci.
5. Decrypt
Zainicjalizuj szyfr i ustaw te same parametry, co przy szyfrowaniu:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
//use first 12 bytes for iv
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
//use everything from 12 bytes on as ciphertext
byte[] plainText = cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12);
Ważne:
- nie zapomnij dodać powiązanych danych z
cipher.updateAAD(associatedData);
, jeśli dodałeś je podczas szyfrowania.
Działający fragment kodu można znaleźć w tym gist.
Zauważ, że najnowszy Android (SDK 21+) i Java (7+) implementacje powinny mieć AES-GCM. W starszych wersjach może go zabraknąć. Nadal wybieram ten tryb, ponieważ jest on łatwiejszy do zaimplementowania, oprócz tego jest bardziej wydajny w porównaniu do podobnego trybu Encrypt-then-Mac (Z np. AES-CBC + HMAC ). zobacz ten artykuł Jak wdrożyć AES-CBC z HMAC.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-19 20:36:54
Wersja dostępna w edytorze Online: -
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
//import org.apache.commons.codec.binary.Base64;
import java.util.Base64;
public class Encryptor {
public static String encrypt(String key, String initVector, String value) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
//System.out.println("encrypted string: "
// + Base64.encodeBase64String(encrypted));
//return Base64.encodeBase64String(encrypted);
String s = new String(Base64.getEncoder().encode(encrypted));
return s;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String key = "Bar12345Bar12345"; // 128 bit key
String initVector = "RandomInitVector"; // 16 bytes IV
System.out.println(encrypt(key, initVector, "Hello World"));
System.out.println(decrypt(key, initVector, encrypt(key, initVector, "Hello World")));
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-19 18:04:47
Często dobrym pomysłem jest oparcie się na standardowym rozwiązaniu dostarczonym przez Bibliotekę:
private static void stackOverflow15554296()
throws
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException
{
// prepare key
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecretKey aesKey = keygen.generateKey();
String aesKeyForFutureUse = Base64.getEncoder().encodeToString(
aesKey.getEncoded()
);
// cipher engine
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// cipher input
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] clearTextBuff = "Text to encode".getBytes();
byte[] cipherTextBuff = aesCipher.doFinal(clearTextBuff);
// recreate key
byte[] aesKeyBuff = Base64.getDecoder().decode(aesKeyForFutureUse);
SecretKey aesDecryptKey = new SecretKeySpec(aesKeyBuff, "AES");
// decipher input
aesCipher.init(Cipher.DECRYPT_MODE, aesDecryptKey);
byte[] decipheredBuff = aesCipher.doFinal(cipherTextBuff);
System.out.println(new String(decipheredBuff));
}
Wyświetla "tekst do zakodowania".
Rozwiązanie oparte jest na Java Cryptography Architecture Reference Guide i https://stackoverflow.com/a/20591539/146745 odpowiedz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:20
Jest to poprawa w stosunku do zaakceptowanej odpowiedzi.
Zmiany:
(1) używając random IV i poprzedzając go zaszyfrowanym tekstem
W tym celu należy użyć SHA-256 do wygenerowania klucza z hasła.]}(3) Brak zależności od Apache Commons
public static void main(String[] args) throws GeneralSecurityException {
String plaintext = "Hello world";
String passphrase = "My passphrase";
String encrypted = encrypt(passphrase, plaintext);
String decrypted = decrypt(passphrase, encrypted);
System.out.println(encrypted);
System.out.println(decrypted);
}
private static SecretKeySpec getKeySpec(String passphrase) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return new SecretKeySpec(digest.digest(passphrase.getBytes(UTF_8)), "AES");
}
private static Cipher getCipher() throws NoSuchPaddingException, NoSuchAlgorithmException {
return Cipher.getInstance("AES/CBC/PKCS5PADDING");
}
public static String encrypt(String passphrase, String value) throws GeneralSecurityException {
byte[] initVector = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(initVector);
Cipher cipher = getCipher();
cipher.init(Cipher.ENCRYPT_MODE, getKeySpec(passphrase), new IvParameterSpec(initVector));
byte[] encrypted = cipher.doFinal(value.getBytes());
return DatatypeConverter.printBase64Binary(initVector) +
DatatypeConverter.printBase64Binary(encrypted);
}
public static String decrypt(String passphrase, String encrypted) throws GeneralSecurityException {
byte[] initVector = DatatypeConverter.parseBase64Binary(encrypted.substring(0, 24));
Cipher cipher = getCipher();
cipher.init(Cipher.DECRYPT_MODE, getKeySpec(passphrase), new IvParameterSpec(initVector));
byte[] original = cipher.doFinal(DatatypeConverter.parseBase64Binary(encrypted.substring(24)));
return new String(original);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-21 00:14:35
Inne rozwiązanie wykorzystujące Javę.util.Base64 ze sprężynowym bagażnikiem
Klasa Szyfrująca
package com.jmendoza.springboot.crypto.cipher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Component
public class Encryptor {
@Value("${security.encryptor.key}")
private byte[] key;
@Value("${security.encryptor.algorithm}")
private String algorithm;
public String encrypt(String plainText) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return new String(Base64.getEncoder().encode(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8))));
}
public String decrypt(String cipherText) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
}
}
Klasa EncryptorController
package com.jmendoza.springboot.crypto.controller;
import com.jmendoza.springboot.crypto.cipher.Encryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cipher")
public class EncryptorController {
@Autowired
Encryptor encryptor;
@GetMapping(value = "encrypt/{value}")
public String encrypt(@PathVariable("value") final String value) throws Exception {
return encryptor.encrypt(value);
}
@GetMapping(value = "decrypt/{value}")
public String decrypt(@PathVariable("value") final String value) throws Exception {
return encryptor.decrypt(value);
}
}
Zastosowanie.właściwości
server.port=8082
security.encryptor.algorithm=AES
security.encryptor.key=M8jFt46dfJMaiJA0
Przykład
Http://localhost:8082/cipher/encrypt/jmendoza
2h41HH8Shzc4BRU3hVDOXA= =
Http://localhost:8082/cipher/decrypt/2h41HH8Shzc4BRU3hVDOXA==
Jmendoza
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-30 18:47:01
Zoptymalizowana wersja zaakceptowanej odpowiedzi.
-
No 3rd party libs
-
Zawiera IV do zaszyfrowanej wiadomości (może być Publiczna)
-
Hasło może być dowolnej długości
Kod:
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryptor {
public static byte[] getRandomInitialVector() {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] initVector = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(initVector);
return initVector;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static byte[] passwordTo16BitKey(String password) {
try {
byte[] srcBytes = password.getBytes("UTF-8");
byte[] dstBytes = new byte[16];
if (srcBytes.length == 16) {
return srcBytes;
}
if (srcBytes.length < 16) {
for (int i = 0; i < dstBytes.length; i++) {
dstBytes[i] = (byte) ((srcBytes[i % srcBytes.length]) * (srcBytes[(i + 1) % srcBytes.length]));
}
} else if (srcBytes.length > 16) {
for (int i = 0; i < srcBytes.length; i++) {
dstBytes[i % dstBytes.length] += srcBytes[i];
}
}
return dstBytes;
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
return null;
}
public static String encrypt(String key, String value) {
return encrypt(passwordTo16BitKey(key), value);
}
public static String encrypt(byte[] key, String value) {
try {
byte[] initVector = Encryptor.getRandomInitialVector();
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.getEncoder().encodeToString(encrypted) + " " + Base64.getEncoder().encodeToString(initVector);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, String encrypted) {
return decrypt(passwordTo16BitKey(key), encrypted);
}
public static String decrypt(byte[] key, String encrypted) {
try {
String[] encryptedParts = encrypted.split(" ");
byte[] initVector = Base64.getDecoder().decode(encryptedParts[1]);
if (initVector.length != 16) {
return null;
}
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedParts[0]));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
Użycie:
String key = "Password of any length.";
String encrypted = Encryptor.encrypt(key, "Hello World");
String decrypted = Encryptor.decrypt(key, encrypted);
System.out.println(encrypted);
System.out.println(decrypted);
Przykładowe wyjście:
QngBg+Qc5+F8HQsksgfyXg== yDfYiIHTqOOjc0HRNdr1Ng==
Hello World
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-27 09:41:47