javax.crypto.BadPaddingException: 给定的最终块未在 CipherInputStream 中正确填充
javax.crypto.BadPaddingException: Given final block not properly padded in CipherInputStream
这个问题可能已经有人问过了,但由于我很难理解密码学,尤其是密钥处理,我不确定如何处理这个异常,也不知道在哪里/如何找到解决方案。
我正在尝试在加密文件中写入和读取对象。
为此,我将 CipherInputStream 包装在 DataInputStream 下。
我收到 BadPadding 异常,这可能意味着我对密钥的处理有误。
请帮帮我。
Main.java:
package main;
import java.util.Arrays;
import io.Io;
public class Main {
static final String FIRST_TEXT_TO_CRYPTO = "First text";
static final boolean BOOLEAN_CRYPTO = true;
static final String SECOND_TEXT_TO_CRYPTO = "First text";
static final String KEY = "key123";
public static void main(String[] args) {
Io.encryptAndWriteAll(Arrays.asList(new Stuff(FIRST_TEXT_TO_CRYPTO, BOOLEAN_CRYPTO, SECOND_TEXT_TO_CRYPTO)),
KEY);
for (Stuff stuff : Io.readAndDecryptAllFromLocation(KEY)) {
System.out.println(stuff);
}
}
}
Stuff.java
package main;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
public class Stuff {
SimpleStringProperty firstString = new SimpleStringProperty(), secondString = new SimpleStringProperty();
SimpleBooleanProperty bool = new SimpleBooleanProperty();
public Stuff(String firstString, boolean bool, String secondString) {
this.firstString.set(firstString);
this.secondString.set(secondString);
this.bool.set(bool);
}
@Override
public String toString() {
return String.format("FirstString: %s; Boolean: %B; SecondString: %s", getFirstString(), isBool(),
getSecondString());
}
public final SimpleStringProperty firstStringProperty() {
return this.firstString;
}
public final String getFirstString() {
return this.firstStringProperty().get();
}
public final void setFirstString(final String firstString) {
this.firstStringProperty().set(firstString);
}
public final SimpleStringProperty secondStringProperty() {
return this.secondString;
}
public final String getSecondString() {
return this.secondStringProperty().get();
}
public final void setSecondString(final String secondString) {
this.secondStringProperty().set(secondString);
}
public final SimpleBooleanProperty boolProperty() {
return this.bool;
}
public final boolean isBool() {
return this.boolProperty().get();
}
public final void setBool(final boolean bool) {
this.boolProperty().set(bool);
}
}
Io.java:
package io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import main.Stuff;
public class Io {
private static final File FILE = new File("file.file");
public static void encryptAndWriteAll(List<Stuff> stuffs, String key) {
try (FileOutputStream fos = new FileOutputStream(FILE);
BufferedOutputStream bos = new BufferedOutputStream(fos);
CipherOutputStream cos = new CipherOutputStream(bos, new Crypto(key).getEncryptionCipher());
DataOutputStream dos = new DataOutputStream(cos)) {
for (Stuff stuff : stuffs) {
dos.writeUTF(stuff.getFirstString());
dos.writeBoolean(stuff.isBool());
dos.writeUTF(stuff.getSecondString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static List<Stuff> readAndDecryptAllFromLocation(String key) {
try (FileInputStream fis = new FileInputStream(FILE);
BufferedInputStream bis = new BufferedInputStream(fis);
CipherInputStream cis = new CipherInputStream(bis, new Crypto(key).getDecryptionCipher());
DataInputStream dis = new DataInputStream(cis)) {
ArrayList<Stuff> stuffs = new ArrayList<>();
try {
for (;;)
// The next line throws
// ("at io.Io.readAndDecryptAllFromLocation(Io.java:52)")
stuffs.add(new Stuff(dis.readUTF(), dis.readBoolean(), dis.readUTF()));
} catch (EOFException e) {
System.out.println("EOF");
e.printStackTrace();
} catch (UTFDataFormatException e) {
e.printStackTrace();
}
return stuffs;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Crypto.java:
package io;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final String ALGORITHM = "AES";
private byte[] paddedKey;
public Crypto(String key) {
paddedKey = addPaddingToKey(key);
}
private byte[] addPaddingToKey(String key) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return Arrays.copyOf(digest.digest(key.getBytes()), 16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private Key getKey() {
return new SecretKeySpec(paddedKey, ALGORITHM);
}
public Cipher getEncryptionCipher() {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, getKey());
return cipher;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public Cipher getDecryptionCipher() {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getKey());
return cipher;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
}
异常:
java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:121)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:239)
at java.io.DataInputStream.readFully(DataInputStream.java:195)
at java.io.DataInputStream.readUTF(DataInputStream.java:609)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at io.Io.readAndDecryptAllFromLocation(Io.java:52)
at main.Main.main(Main.java:17)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:975)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2048)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:118)
... 6 more
Exception in thread "main" java.lang.NullPointerException
at main.Main.main(Main.java:17)
您正在使用 AES/CBC,这需要 IV 参数。如果您在加密时未指定 IV 参数,则会生成并使用随机 IV。
您可以随机生成 IV 并将其添加到加密数据中,因为 IV 不需要保密。
这个问题可能已经有人问过了,但由于我很难理解密码学,尤其是密钥处理,我不确定如何处理这个异常,也不知道在哪里/如何找到解决方案。
我正在尝试在加密文件中写入和读取对象。 为此,我将 CipherInputStream 包装在 DataInputStream 下。
我收到 BadPadding 异常,这可能意味着我对密钥的处理有误。
请帮帮我。
Main.java:
package main;
import java.util.Arrays;
import io.Io;
public class Main {
static final String FIRST_TEXT_TO_CRYPTO = "First text";
static final boolean BOOLEAN_CRYPTO = true;
static final String SECOND_TEXT_TO_CRYPTO = "First text";
static final String KEY = "key123";
public static void main(String[] args) {
Io.encryptAndWriteAll(Arrays.asList(new Stuff(FIRST_TEXT_TO_CRYPTO, BOOLEAN_CRYPTO, SECOND_TEXT_TO_CRYPTO)),
KEY);
for (Stuff stuff : Io.readAndDecryptAllFromLocation(KEY)) {
System.out.println(stuff);
}
}
}
Stuff.java
package main;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
public class Stuff {
SimpleStringProperty firstString = new SimpleStringProperty(), secondString = new SimpleStringProperty();
SimpleBooleanProperty bool = new SimpleBooleanProperty();
public Stuff(String firstString, boolean bool, String secondString) {
this.firstString.set(firstString);
this.secondString.set(secondString);
this.bool.set(bool);
}
@Override
public String toString() {
return String.format("FirstString: %s; Boolean: %B; SecondString: %s", getFirstString(), isBool(),
getSecondString());
}
public final SimpleStringProperty firstStringProperty() {
return this.firstString;
}
public final String getFirstString() {
return this.firstStringProperty().get();
}
public final void setFirstString(final String firstString) {
this.firstStringProperty().set(firstString);
}
public final SimpleStringProperty secondStringProperty() {
return this.secondString;
}
public final String getSecondString() {
return this.secondStringProperty().get();
}
public final void setSecondString(final String secondString) {
this.secondStringProperty().set(secondString);
}
public final SimpleBooleanProperty boolProperty() {
return this.bool;
}
public final boolean isBool() {
return this.boolProperty().get();
}
public final void setBool(final boolean bool) {
this.boolProperty().set(bool);
}
}
Io.java:
package io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import main.Stuff;
public class Io {
private static final File FILE = new File("file.file");
public static void encryptAndWriteAll(List<Stuff> stuffs, String key) {
try (FileOutputStream fos = new FileOutputStream(FILE);
BufferedOutputStream bos = new BufferedOutputStream(fos);
CipherOutputStream cos = new CipherOutputStream(bos, new Crypto(key).getEncryptionCipher());
DataOutputStream dos = new DataOutputStream(cos)) {
for (Stuff stuff : stuffs) {
dos.writeUTF(stuff.getFirstString());
dos.writeBoolean(stuff.isBool());
dos.writeUTF(stuff.getSecondString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static List<Stuff> readAndDecryptAllFromLocation(String key) {
try (FileInputStream fis = new FileInputStream(FILE);
BufferedInputStream bis = new BufferedInputStream(fis);
CipherInputStream cis = new CipherInputStream(bis, new Crypto(key).getDecryptionCipher());
DataInputStream dis = new DataInputStream(cis)) {
ArrayList<Stuff> stuffs = new ArrayList<>();
try {
for (;;)
// The next line throws
// ("at io.Io.readAndDecryptAllFromLocation(Io.java:52)")
stuffs.add(new Stuff(dis.readUTF(), dis.readBoolean(), dis.readUTF()));
} catch (EOFException e) {
System.out.println("EOF");
e.printStackTrace();
} catch (UTFDataFormatException e) {
e.printStackTrace();
}
return stuffs;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Crypto.java:
package io;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final String ALGORITHM = "AES";
private byte[] paddedKey;
public Crypto(String key) {
paddedKey = addPaddingToKey(key);
}
private byte[] addPaddingToKey(String key) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return Arrays.copyOf(digest.digest(key.getBytes()), 16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private Key getKey() {
return new SecretKeySpec(paddedKey, ALGORITHM);
}
public Cipher getEncryptionCipher() {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, getKey());
return cipher;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public Cipher getDecryptionCipher() {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getKey());
return cipher;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
}
异常:
java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:121)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:239)
at java.io.DataInputStream.readFully(DataInputStream.java:195)
at java.io.DataInputStream.readUTF(DataInputStream.java:609)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at io.Io.readAndDecryptAllFromLocation(Io.java:52)
at main.Main.main(Main.java:17)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:975)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2048)
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:118)
... 6 more
Exception in thread "main" java.lang.NullPointerException
at main.Main.main(Main.java:17)
您正在使用 AES/CBC,这需要 IV 参数。如果您在加密时未指定 IV 参数,则会生成并使用随机 IV。
您可以随机生成 IV 并将其添加到加密数据中,因为 IV 不需要保密。