Javax.crypto.BadPaddingException
Я работаю над алгоритмом AES, и у меня есть это исключение, которое я не мог решить.
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
исключение происходит в части расшифровки.
Я инициализирую ключ в другом месте, где алгоритм дешифрования
KeyGenerator kgen = KeyGenerator.getInstance("AES");//key generation for AES
kgen.init(128); // 192 and 256 bits may not be available
то я передаю его с помощью шифрованного текста, который я прочитал из файла, на следующий метод
public String decrypt(String message, SecretKey skey) {
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher;
byte[] original = null;
try {
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
System.out.println("Original string: "
+ message);
original = cipher.doFinal(message.trim().getBytes()); //here where I got the exception
String originalString = new String(original);
}
//catches
ИЗМЕНИТЬ
здесь метод шифрования.
public String encrypt(String message, SecretKey skey) {
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher;
byte[] encrypted = null;
try {
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(message.getBytes());
System.out.println("raw is " + encrypted);
} catches
return asHex(encrypted);
}
и здесь метод asHex
public static String asHex(byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
Здесь, где я читаю строчную текстовую форму, файл
static public String readFile(String filePath) {
StringBuilder file = new StringBuilder();
String line = null;
try {
FileReader reader = new FileReader(filePath);
BufferedReader br = new BufferedReader(reader);
if (br != null) {
line = br.readLine();
while (line != null) {
file.append(line);
// System.out.println("line is " + line);
line = br.readLine();
}
}
br.close();
reader.close();
} catch (IOException ex) {
Logger.getLogger(FileManagement.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("line is " + file.toString());
return String.valueOf(file);
}
может кто-нибудь помочь?
Ответы
Ответ 1
Итак, проблема заключается в том, что вы конвертируете зашифрованные байты в шестнадцатеричную строку (используя метод asHex
), но не преобразуете шестнадцатеричную строку обратно в массив байтов правильно для дешифрования. Вы не можете использовать getBytes
.
Вы можете использовать следующий метод для преобразования шестнадцатеричной строки в массив байтов:
public static byte[] fromHexString(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
а затем измените метод расшифровки:
original = cipher.doFinal(fromHexString(message));
Ответ 2
У меня было исключение Bad Padding Exception и не удалось найти в Интернете решение моей проблемы. Поскольку я нашел его после некоторых трудовых часов, я даю его здесь.
Моя проблема заключалась в том, что я читал файл на своем жестком диске и шифровал его через буфер, всегда вызывая метод doFinal() вместо метода update(). Поэтому, когда он расшифровывался, у меня были ошибки заполнения
input = new FileInputStream(file);
output = new FileOutputStream(newFile);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, mySecretKey);
byte[] buf = new byte[1024];
count = input.read(buf);
while (count >= 0) {
output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method
count = input.read(buf);
}
output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
output.flush();
И при расшифровке с помощью того же метода, но с Cipher init с DECRYPT_MODE
input = new FileInputStream(file);
output = new FileOutputStream(newFile);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, mySecretKey);
byte[] buf = new byte[1024];
count = input.read(buf);
while (count >= 0) {
output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method
//AND HERE WAS THE BadPaddingExceotion -- the first pass in the while structure
count = input.read(buf);
}
output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
output.flush();
С написанным кодом у меня больше нет исключения BadPaddingException.
Я могу уточнить, что это исключение появляется только тогда, когда исходная длина чистого файла (полученная через file.length()) больше, чем буфер. Кроме того, нам не нужно проходить несколько раз в структуре while, и мы можем зашифровать за один проход вызовом doFinal(). Это оправдывает случайный характер исключения, следующего за размером файла, который вы пытаетесь зашифровать.
Надеюсь, вы хорошо прочитали!
Ответ 3
Я думаю, выражение message.trim().getBytes()
не возвращает те же байты, которые генерируются при шифровании сообщения. Специально метод trim()
мог удалять байты, которые были добавлены в качестве дополнения в зашифрованном сообщении.
Убедитесь, что как возвращенный массив метода doFinal()
во время шифрования, так и возвращенный массив message.trim().getBytes()
:
- получил одинаковое количество байтов (длина массива)
- получил те же байты в массиве
Ответ 4
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair rsaKeyPair = kpg.genKeyPair();
byte[] txt = "This is a secret message.".getBytes();
System.out.println("Original clear message: " + new String(txt));
// encrypt
Cipher cipher;
try
{
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPublic());
txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
e.printStackTrace();
return;
}
System.out.println("Encrypted message: " + new String(txt));
// decrypt
try
{
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());
txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
e.printStackTrace();
return;
}
System.out.println("Decrypted message: " + new String(txt));
Ответ 5
Вот решение, которое я смог собрать вместе, используя хранилище ключей jks с шифрованием RSA
import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.cert.Certificate;
public class Main {
public static void main(String[] args) {
byte[] txt = "This is a secret message for your own eyes only".getBytes();
byte[] encText;
try{
// Load the keystore
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
char[] password = "keystorePassword".toCharArray();
java.io.FileInputStream fis = new java.io.FileInputStream("/path/to/keystore/myKeyStore.jks");
ks.load(fis, password);
fis.close();
Key rsakey = ks.getKey("mykeyalias", password);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// Encrypt
Certificate cert = ks.getCertificate("mykeyalias");
try
{
cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
encText = cipher.doFinal(txt);
System.out.println(encText.toString());
}
catch (Throwable e)
{
e.printStackTrace();
return;
}
// Decrypt
cipher.init(Cipher.DECRYPT_MODE, rsakey);
String decrypted = new String(cipher.doFinal(encText));
System.out.println(decrypted);
} catch (Exception e) {
System.out.println("error" + e);
}
}