Шифрование и дешифрование с помощью 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 [B@aa9835
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.
И как говорит исключение " Как расшифровать без подкладки шифра?"
6 ответов:
Ваш заказ на шифрование: getBytes, encrypt, encode, toString
Ваш заказ на расшифровку: getBytes, decrypt, decode, toStringДве проблемы:
Примечание: кроме того, вам не нужно звонить
- как кто-то уже упоминал, вы должны изменить порядок операций для расшифровки. Вы этого не сделаете.
- шифрование дает 16 байт, кодирование 24 байта, но toString дает 106 байт. Что-то связанное с недействительными символами, занимающими дополнительные пространство.
generateKey()дважды.Исправьте проблему №1, используя обратный порядок для расшифровки. Правильный порядок: getBytes, decode, decrypt, 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"
Линия
String encryptedValue = encryptedByteValue.toString();- вот в чем проблема. Тип encryptedByteValue-byte [], и вызов toString на нем-это не то, что вы хотите сделать там. Вместо этого попробуйте
String encryptedValue = Base64.getEncoder().encodeToString(encValue);Затем используйте
Base64.decodeBase64(encryptedValue)для расшифровки. Однако вы должны сделать это до того, как попытаетесь расшифровать. Вы должны отменить операции в обратном порядке метода шифрования.
Где вы получаете версию Apache codec, которая имеет 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И затем строка, которую я получил, была очень длинной, но она расшифровывалась правильно.
Я не думаю, что это "правильный" способ делайте что-то, но не можете найти методы, о которых говорится в документации.
Это было нормально, тебе просто нужно было
1) Используйте новую строку вместо toString (), так как toString() не возвращает то, что вам нужно (в обоих случаях шифрование и расшифровка)
2) вам нужно сначала декодировать, так как значение кодируется в base64.
Я наткнулся на эту нить, но потребовалось некоторое время, чтобы выяснить фактическую точку..Я публикую свой код для остальных людей, которые сталкиваются с этой проблемой.
public abstract class EncryptionDecryption { static byte[] key = "!@#$!@#$%^&**&^%".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)); } }
По сути, существует асимметрия между функцией шифрования и функцией дешифрования. Когда вы шифруете, вы выполняете шифрование AES, а затем кодирование base64, когда вы расшифровываете, вы сначала не отменяете шаг кодирования base64.
Я думаю, что что-то не так с вашей кодировкой base64, а также
[не должно появляться в строке с кодировкой base64.Глядя на документацию для
org.apache.commons.codec.binary.Base64Вы должны быть в состоянии сделать это на encode:String encryptedValue = Base64.encodeBase64String(encValue);И это на расшифровать:
byte[] encValue = Base64.decodeBase64(encryptedValue);
У меня есть замена строки в Примере:
String encryptedValue = encryptedByteValue.toString();Со следующим:
String encryptedValue = new String(encryptedByteValue);Все работает отлично!
Comments