Шифрование - дешифрование с помощью AES/BlowFish/DESede и Enum
Прежде всего, я хочу сказать спасибо...
Я написал программу, которая выполняет шифрование и дешифрование с помощью Enum. В Enum есть AES,BlowFish,DESede. Моя программа будет поддерживать эти 3 алгоритма шифрования.
Затем я хотел сгенерировать SecretKey с SecretKeyFactory. Но я думаю, что сделал ошибку, чтобы сгенерировать ключ. (Очевидно, я теряю себя в коде. Я понятия не имею, что я могу сделать...)
Мой код ниже. Цель этой программы:
- Пользователи будут писать параметры метода шифрования и дешифрования. (Текст, алгоритм шифрования)
- Тип алгоритма выберете в типе Enum. (Enum имеет 3 алгоритма формата)
- В соответствии с введенным типом шифрования, программа будет шифровать введенный текст.
Я знаю, что мой код действительно ужасен. В нем много ненужных деклараций и логических ошибок.
Иногда код работает нормально, иногда происходит сбой.
РЕДАКТИРОВАТЬ = Вопрос, мой код не всегда работает. Иногда выдает ошибку. Ошибка = javax.crypto.BadPaddingException: данный последний блок не заполнен должным образом
Спасибо, что ответили.
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class SymetricAlgorithms {
private static enum algorithms { //Enum declaration 3 encryption types here
AES, BlowFish, DESede;
}
private static String data = "HOWCANISOLVETHIS"; //this will be encrypt and decrypt
public static void main(String[] args) throws Throwable {
SecretKey kgen = GenerateKey(); // Create a key.
String encrypText = encrypt(kgen, data, algorithms.AES); //encrypt method calling here.
String decrypText = dencypt(kgen, encrypText, algorithms.AES);//decrypt method calling here.
System.out.println("plaintext = " + data + " key = " + kgen
+ "\nEncryptedText = " + encrypText
+ "\nDecryptedText = " + decrypText);
}
public static String dencypt(SecretKey inKey, String text, algorithms eValue)throws Throwable {//decryption
try {
byte[] text2 = text.getBytes(); //convert from parameters TEXT to Bytes
Cipher cipher = Cipher.getInstance("AES"); //Cipher initialize and choose encryption method (AES)
cipher.init(Cipher.DECRYPT_MODE, inKey); //cipher process
byte plainTextByte[] = new byte[20]; //Creating byte array
plainTextByte =cipher.doFinal(text2);//using byte array to assign ciphers result
System.out.println(plainTextByte);
return new String(plainTextByte);
} catch (Exception e) {
System.err.println("Data Cant Decrypted !");
e.printStackTrace();
}
return null;
}
public static String encrypt(SecretKey inKey, String text, algorithms eValue)
throws Throwable {
try {
Cipher cipher = null; //cipher declaration
switch (eValue) {//Enum. 3 types here and control structure for Users choosing encryption type is acceptable
case AES:cipher = Cipher.getInstance("AES");
break;
case BlowFish:Cipher cipher2 = Cipher.getInstance("BlowFish");
cipher = cipher2;
break;
case DESede:Cipher cipher3 = Cipher.getInstance("DESede");
cipher=cipher3;
break;
default:
System.out.println("Unexpectable value input.");
break;
}
System.out.println(inKey);
//Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, inKey);
byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));//cipher result is assign to byte array
System.out.println(ciphertext);
return new String(ciphertext);
} catch (Exception e) {
System.err.println("Unexpectable algorithm type !");
e.printStackTrace();
}
return null;
}
public static SecretKey GenerateKey() throws Throwable {//Generate a key for using crypt
//could sb explain these? =D I loose myself. I combined codes from finding internet...Failed...
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
byte bytes[] = new byte[20];
prng.nextBytes(bytes);
String passwordTemp = prng.toString();
String saltTemp = passwordTemp;
char[] password = passwordTemp.toCharArray();
byte[] salt = saltTemp.getBytes();
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
return secret;
} catch (Exception e) {
System.err.println("Key cant be generated !");
e.printStackTrace();
}
return null;
}
}
1 ответ
Тема проблемы - непонимание отношений между строками и байтами. В конце метода шифрования, как вы думаете, что делают эти две строки:
byte[] ciphertext = cipher.doFinal(...
return new String(ciphertext);
Последняя строка берет зашифрованные байты, которые могут быть почти чем угодно, и пытается интерпретировать эти байты как кодирование некоторых символов строки. Используя какую кодировку? Строковый конструктор без аргумента кодировки символов использует системную кодировку по умолчанию, которая зависит от JVM/OS/Locale. Допустим, это UTF-8. Вы гарантировано, что на самом деле будет какой-то символ для зашифрованных байтов? Ответ: НЕТ. Получите ли вы те же байты обратно, когда возьмете полученную строку и вызовете.getBytes("UTF-8"). Ответ: Нет, существуют последовательности из нескольких байтов, кодирующие одни и те же символы, поэтому новая строка (байты, "UTF-8"). GetBytes ("UTF-8") не гарантирует возврат байтов, с которых вы начали.
Таким образом, не пытайтесь интерпретировать произвольные байты как строку. Сделайте так, чтобы ваш метод шифрования возвратил byte[], а ваш метод расшифровки примет массив байтов для декодирования - тогда он будет работать.
Нет необходимости заставлять вашу программу работать, но если вы должны представить зашифрованные байты в виде строки, рассмотрите кодировку base64 или шестнадцатеричное кодирование - эти кодировки однозначно отображают каждый возможный байт (или последовательность байтов) в строку.
ОБНОВЛЕНИЕ: вот более краткий метод generateKey(). Это позволяет вам передавать пароль в качестве аргумента.
public static SecretKey generateKey(String password) {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte saltBytes[] = new byte[20];
secureRandom.nextBytes(saltBytes);
KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = factory.generateSecret(spec);
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (Exception e) {
throw new IllegalStateException("Key cant be generated !");
}
}