Шифрование и дешифрование с помощью кодирования AES и Base64
У меня есть следующая программа для шифрования данных.
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Test {
private static final String ALGORITHM = "AES";
private static final byte[] keyValue = "ADBSJHJS12547896".getBytes();
public static void main(String args[]) throws Exception {
String encriptValue = encrypt("dude5");
decrypt(encriptValue);
}
/**
* @param args
* @throws Exception
*/
public static String encrypt(String valueToEnc) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
System.out.println("encValue length" + encValue.length);
byte[] encryptedByteValue = new Base64().encode(encValue);
String encryptedValue = encryptedByteValue.toString();
System.out.println("encryptedValue " + encryptedValue);
return encryptedValue;
}
public static String decrypt(String encryptedValue) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] enctVal = c.doFinal(encryptedValue.getBytes());
System.out.println("enctVal length " + enctVal.length);
byte[] decordedValue = new Base64().decode(enctVal);
return decordedValue.toString();
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGORITHM);
return key;
}
}
Здесь я получаю следующий вывод с исключением?
valueToEnc.getBytes().length 5
encValue length16
encryptedValue [[email protected]
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
Может кто-нибудь объяснить мне причину? Почему его единственное высказывание при расшифровке этой длины должно быть 16. Не конвертирует ли он в 16 как шифрование с помощью метода doFinal.
И как исключение говорит " как расшифровать без прошитого шифрования?"
Ответы
Ответ 1
Ваш заказ для шифрования: getBytes, encrypt, encode, toString
Ваш заказ для расшифровки: getBytes, расшифровать, декодировать, toString
Две проблемы:
- Как уже упоминалось, вы должны отменить порядок операций для дешифрования. Вы этого не делаете.
- encrypt дает вам 16 байт, кодирует 24 байта, но toString дает 106 байтов. Что-то делать с неверными символами, занимающими дополнительное пространство.
Примечание. Также вам не нужно дважды звонить generateKey()
.
Исправить проблему №1, используя обратный порядок дешифрования. Правильный порядок: getBytes, декодировать, расшифровывать, toString
Исправьте проблему №2, заменив xxx.toString()
на new String(xxx)
. Сделайте это как в функции шифрования, так и дешифрования.
Ваш расшифровка должна выглядеть так:
c.init(Cipher.DECRYPT_MODE, key)
val decodedValue = new Base64().decode(encryptedValue.getBytes())
val decryptedVal = c.doFinal(decodedValue)
return new String(decryptedVal)
Это должно вернуть вам "dude5"
Ответ 2
Линия
String encryptedValue = encryptedByteValue.toString();
- проблема. Тип encryptedByteValue является байтом [], а вызов toString на нем не является тем, что вы хотите сделать там. Вместо этого попробуйте
String encryptedValue = Base64.getEncoder().encodeToString(encValue);
Затем используйте Base64.decodeBase64(encryptedValue)
в расшифровке. Вы должны сделать это, прежде чем пытаться расшифровать. Вы должны отменить операции в обратном порядке метода шифрования.
Ответ 3
Где вы получаете версию кодека apache с encodeToString или encodeBase64String?
Я загрузил 1.5 с сайта apache, и пока он говорит в документации, что эти методы существуют, они не отображаются, когда вы выполняете завершение кода, и при создании их создаете неизвестный метод.
Я смог:
byte raw[] = md.digest(); //step 4
byte hashBytes[] = Base64.encodeBase64(raw); //step 5
StringBuffer buffer = new StringBuffer();
for( int i=0; i<hashBytes.length; i++ )
buffer.append(hashBytes[i]);
return buffer.toString(); //step 6
И тогда строка, которую я получил, была очень длинной, но она была расшифрована правильно.
Я не думаю, что это "правильный" способ сделать что-то, но не может найти методы, о которых говорит документация.
Ответ 4
В принципе, существует асимметрия между вашей функцией шифрования и функцией расшифровки. Когда вы шифруете, вы выполняете шифрование AES, а затем кодировку base64, когда вы расшифровываете, вы не отменяете сначала шаг кодирования base64.
Я думаю, что что-то не так с вашей кодировкой base64, а также [
не должно появляться в кодировке base64.
Посмотрев документацию на org.apache.commons.codec.binary.Base64
, вы сможете сделать это при кодировании:
String encryptedValue = Base64.encodeBase64String(encValue);
и это при декодировании:
byte[] encValue = Base64.decodeBase64(encryptedValue);
Ответ 5
Я заменяю строку в примере:
String encryptedValue = encryptedByteValue.toString();
со следующим:
String encryptedValue = new String(encryptedByteValue);
Все работает отлично!
Ответ 6
Все было в порядке, вам просто нужно
1) Используйте новую строку вместо toString(), поскольку toString() не возвращает то, что вам нужно здесь (в обоих случаях, шифрование и дешифрование)
2) вам нужно сначала декодировать, поскольку значение кодируется в base64.
Я наткнулся на эту тему, но мне потребовалось некоторое время, чтобы узнать фактическую точку. Я отправляю свой код для отдыха людей, которые сталкиваются с этой проблемой.
public abstract class EncryptionDecryption {
static byte[] key = "[email protected]#[email protected]#$%^&**&^%".getBytes();
final static String algorithm="AES";
public static String encrypt(String data){
byte[] dataToSend = data.getBytes();
Cipher c = null;
try {
c = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec k = new SecretKeySpec(key, algorithm);
try {
c.init(Cipher.ENCRYPT_MODE, k);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encryptedData = "".getBytes();
try {
encryptedData = c.doFinal(dataToSend);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encryptedByteValue = new Base64().encode(encryptedData);
return new String(encryptedByteValue);//.toString();
}
public static String decrypt(String data){
byte[] encryptedData = new Base64().decode(data);
Cipher c = null;
try {
c = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec k =
new SecretKeySpec(key, algorithm);
try {
c.init(Cipher.DECRYPT_MODE, k);
} catch (InvalidKeyException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
byte[] decrypted = null;
try {
decrypted = c.doFinal(encryptedData);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new String(decrypted);
}
public static void main(String[] args){
String password=EncryptionDecryption.encrypt("password123");
System.out.println(password);
System.out.println(EncryptionDecryption.decrypt(password));
}
}