BadPaddingException 和一些文件停留在 99%
BadPaddingException and some files stuck at 99%
我试图从这里收集关于 Encryption/Decryption 的所有可能信息。修补它,一些成功和失败。
但现在我已经应用了代码及其成功与否。某些文件(exe 或 msi 的)正在运行,但它们仍然给出有关 BadPaddingException 的错误。此外,一些其他媒体文件(如 mp4、mkv 等)卡在 99% 并且不会超过 99%,尽管它们已完全接收(只是一些小的字节差异,但 磁盘大小 总是匹配)。
我只是想要一些帮助来摆脱这两个问题。通过套接字编程将文件从一台PC传输到另一台PC。
服务器:(已编辑)
DataInputStream dis = new DataInputStream(msock.getInputStream());
DataOutputStream dos = new DataOutputStream(msock.getOutputStream());
String file2dl = dis.readLine(); //2
File file = new File(sharedDirectory.toString() + "\" + file2dl);
dos.writeLong(file.length()); //3+
//Get file name without extension.
String fileName = Files.getNameWithoutExtension(file2dl);
//AES-128 bit key initialization.
byte[] keyvalue = "AES128BitPasswd".getBytes();
SecretKey key = new SecretKeySpec(keyvalue, "AES");
//Initialize the Cipher.
Cipher encCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encCipher.init(Cipher.ENCRYPT_MODE, key);
//Get the IV from cipher.
IvParameterSpec spec = null;
try {
spec = encCipher.getParameters().getParameterSpec(IvParameterSpec.class);
} catch (InvalidParameterSpecException ex) {
Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] iv = spec.getIV();
dos.write(iv, 0, iv.length);
File tempDir = new File(tempDirectory.toString());
//Encryption Mechanism.
try (FileInputStream fis = new FileInputStream(file)) {
try (CipherOutputStream cos = new CipherOutputStream(dos, encCipher);
FileInputStream stream = new FileInputStream(tempDir + "\" + fileName + ".encr")) {
int read, r;
byte[] buffer = new byte[1024 * 1024];
while ((read = fis.read(buffer)) != -1) {
cos.write(buffer, 0, read);
}
}
}
}
客户:
long len;
int count = 0;
int dflag = 0;
String size;
dos.writeBytes("Download\r\n"); //1+
dos.writeBytes(filename + "\r\n"); //2+
System.out.println("File to fetch: -> " + filename);
len = dis.readLong(); //3
System.out.println("Size of file: -> " + len);
//Get file name without Extension.
String fileName = Files.getNameWithoutExtension(filename);
//Get Initialization Vector from Encryption Cypher.
byte[] iv = new byte[16];
int j = dis.read(iv, 0, iv.length);
final File encrypted = new File(sharedDirectory.toString() + "\" + fileName + ".encr");
final File decrypted = new File(sharedDirectory.toString() + "\" + filename);
try (FileOutputStream fos = new FileOutputStream(encrypted)) {
byte[] b = new byte[1024 * 1024];
while (fetching) {
int r = dis.read(b, 0, b.length); //4
count = count + r;
double p = (double) count / len;
double per = new BigDecimal(p).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
fos.write(b, 0, r);
System.out.println("Size Appending: -> " + count);
System.out.println("Percentage: ->" + per);
Platform.runLater(() -> {
pBar.setProgress(per);
});
if (count >= len) {
dflag = 1;
break;
}
}
}
如果加密数据完全接收
if(dflag == 1) {
//AES-128 bit key initialization.
System.out.println("File completely received");
byte[] keyvalue = "AES128PeerBuLLet".getBytes();
Key key = new SecretKeySpec(keyvalue, "AES");
//Initialization Vector initialized
IvParameterSpec ivParameterSpec = null;
//Cipher Initialization.
Cipher decCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try {
decCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(decCipher.getProvider().getInfo());
//Decryption Mechanism.
try (FileOutputStream stream = new FileOutputStream(decrypted)) {
try (FileInputStream fis = new FileInputStream(encrypted)) {
try (CipherInputStream cis = new CipherInputStream(fis, decCipher)) {
int read, i = 0;
byte[] buffer = new byte[(1024 * 1024) + 16];
while ((read = cis.read(buffer)) != -1) {
stream.write(buffer, 0, read);
i = i + read;
double d = (double) i / len;
double progress = new BigDecimal(d).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
Platform.runLater(() -> {
pBar.setProgress(progress);
progressText.setText("Decrypting..");
});
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
非常感谢任何意见。谢谢。
编辑 1: 将 link 添加到通过流接收的加密和解密文件的大小。 Dropbox Link
编辑2: 所以最后在三位成员的帮助下问题终于解决了,他们尽最大努力帮助我。我正在审查我的问题的其他解决方案,我遇到了 解决方案,它帮助我深入思考后台发生的实际情况。感谢 Artjom B. 的推荐解决方案和 @zaph & @jtahlborn 清除我关于填充和 Input/Output 流的错误假设。
您不能使用 FileInputStream 读取您当前正在写入的文件。它不是为读取正在进行的文件而构建的。
您似乎正在尝试将加密流写入 dos
(您没有在服务器代码中包含它的定义)。如果是这样,您应该将其用作 CipherOutputStream 的基础流。
同样,在客户端中,您尝试同样的事情。如果要先将文件写入磁盘,则将整个文件写入磁盘,然后再解密。如果你想流式解密,然后将 CipherInputStream 包裹在套接字 InputStream 周围(大概 dis
?)。
此外,您没有显示从客户端获得 len
的位置,但我假设它是 原始 数据的长度?如果是这样,那么您的进度计算不正确,因为加密数据的长度通常与原始数据的长度不同。
使用填充、PKCS#5 或 PKCS#7 时,加密输出会更大,最多并包括一个块大小。参见 PKCS#7。解密后删除填充。
加密的数据会更长,所以必须考虑到这一点。如何取决于如何处理输出。如果它要去一个预先分配的区域,例如内存缓冲区,则必须为缓冲区分配一个更大的块大小(AES 为 16 字节)。如果流式传输通常只是确保发送所有加密字节,则 n=它只是输入的长度。所有这些都是每个实现和 system/language 相关的。
填充字节由加密方法动态创建,因此无需更改输入。这假设加密方法是添加填充,解密方法是删除填充。
示例 1:如果您有 1024 字节的数据,则加密输出将为 1040 字节。解密时输入数据将为 1040 字节,输出解密数据将为 1024 字节。
示例 2:如果您有 1020 字节的数据,则加密输出将为 1024 字节。解密时,输入数据将为 1024 字节,输出解密数据将为 1020 字节。
我试图从这里收集关于 Encryption/Decryption 的所有可能信息。修补它,一些成功和失败。
但现在我已经应用了代码及其成功与否。某些文件(exe 或 msi 的)正在运行,但它们仍然给出有关 BadPaddingException 的错误。此外,一些其他媒体文件(如 mp4、mkv 等)卡在 99% 并且不会超过 99%,尽管它们已完全接收(只是一些小的字节差异,但 磁盘大小 总是匹配)。
我只是想要一些帮助来摆脱这两个问题。通过套接字编程将文件从一台PC传输到另一台PC。
服务器:(已编辑)
DataInputStream dis = new DataInputStream(msock.getInputStream());
DataOutputStream dos = new DataOutputStream(msock.getOutputStream());
String file2dl = dis.readLine(); //2
File file = new File(sharedDirectory.toString() + "\" + file2dl);
dos.writeLong(file.length()); //3+
//Get file name without extension.
String fileName = Files.getNameWithoutExtension(file2dl);
//AES-128 bit key initialization.
byte[] keyvalue = "AES128BitPasswd".getBytes();
SecretKey key = new SecretKeySpec(keyvalue, "AES");
//Initialize the Cipher.
Cipher encCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encCipher.init(Cipher.ENCRYPT_MODE, key);
//Get the IV from cipher.
IvParameterSpec spec = null;
try {
spec = encCipher.getParameters().getParameterSpec(IvParameterSpec.class);
} catch (InvalidParameterSpecException ex) {
Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] iv = spec.getIV();
dos.write(iv, 0, iv.length);
File tempDir = new File(tempDirectory.toString());
//Encryption Mechanism.
try (FileInputStream fis = new FileInputStream(file)) {
try (CipherOutputStream cos = new CipherOutputStream(dos, encCipher);
FileInputStream stream = new FileInputStream(tempDir + "\" + fileName + ".encr")) {
int read, r;
byte[] buffer = new byte[1024 * 1024];
while ((read = fis.read(buffer)) != -1) {
cos.write(buffer, 0, read);
}
}
}
}
客户:
long len;
int count = 0;
int dflag = 0;
String size;
dos.writeBytes("Download\r\n"); //1+
dos.writeBytes(filename + "\r\n"); //2+
System.out.println("File to fetch: -> " + filename);
len = dis.readLong(); //3
System.out.println("Size of file: -> " + len);
//Get file name without Extension.
String fileName = Files.getNameWithoutExtension(filename);
//Get Initialization Vector from Encryption Cypher.
byte[] iv = new byte[16];
int j = dis.read(iv, 0, iv.length);
final File encrypted = new File(sharedDirectory.toString() + "\" + fileName + ".encr");
final File decrypted = new File(sharedDirectory.toString() + "\" + filename);
try (FileOutputStream fos = new FileOutputStream(encrypted)) {
byte[] b = new byte[1024 * 1024];
while (fetching) {
int r = dis.read(b, 0, b.length); //4
count = count + r;
double p = (double) count / len;
double per = new BigDecimal(p).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
fos.write(b, 0, r);
System.out.println("Size Appending: -> " + count);
System.out.println("Percentage: ->" + per);
Platform.runLater(() -> {
pBar.setProgress(per);
});
if (count >= len) {
dflag = 1;
break;
}
}
}
如果加密数据完全接收
if(dflag == 1) {
//AES-128 bit key initialization.
System.out.println("File completely received");
byte[] keyvalue = "AES128PeerBuLLet".getBytes();
Key key = new SecretKeySpec(keyvalue, "AES");
//Initialization Vector initialized
IvParameterSpec ivParameterSpec = null;
//Cipher Initialization.
Cipher decCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try {
decCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(PeersController.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(decCipher.getProvider().getInfo());
//Decryption Mechanism.
try (FileOutputStream stream = new FileOutputStream(decrypted)) {
try (FileInputStream fis = new FileInputStream(encrypted)) {
try (CipherInputStream cis = new CipherInputStream(fis, decCipher)) {
int read, i = 0;
byte[] buffer = new byte[(1024 * 1024) + 16];
while ((read = cis.read(buffer)) != -1) {
stream.write(buffer, 0, read);
i = i + read;
double d = (double) i / len;
double progress = new BigDecimal(d).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
Platform.runLater(() -> {
pBar.setProgress(progress);
progressText.setText("Decrypting..");
});
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
非常感谢任何意见。谢谢。
编辑 1: 将 link 添加到通过流接收的加密和解密文件的大小。 Dropbox Link
编辑2: 所以最后在三位成员的帮助下问题终于解决了,他们尽最大努力帮助我。我正在审查我的问题的其他解决方案,我遇到了
您不能使用 FileInputStream 读取您当前正在写入的文件。它不是为读取正在进行的文件而构建的。
您似乎正在尝试将加密流写入 dos
(您没有在服务器代码中包含它的定义)。如果是这样,您应该将其用作 CipherOutputStream 的基础流。
同样,在客户端中,您尝试同样的事情。如果要先将文件写入磁盘,则将整个文件写入磁盘,然后再解密。如果你想流式解密,然后将 CipherInputStream 包裹在套接字 InputStream 周围(大概 dis
?)。
此外,您没有显示从客户端获得 len
的位置,但我假设它是 原始 数据的长度?如果是这样,那么您的进度计算不正确,因为加密数据的长度通常与原始数据的长度不同。
使用填充、PKCS#5 或 PKCS#7 时,加密输出会更大,最多并包括一个块大小。参见 PKCS#7。解密后删除填充。
加密的数据会更长,所以必须考虑到这一点。如何取决于如何处理输出。如果它要去一个预先分配的区域,例如内存缓冲区,则必须为缓冲区分配一个更大的块大小(AES 为 16 字节)。如果流式传输通常只是确保发送所有加密字节,则 n=它只是输入的长度。所有这些都是每个实现和 system/language 相关的。
填充字节由加密方法动态创建,因此无需更改输入。这假设加密方法是添加填充,解密方法是删除填充。
示例 1:如果您有 1024 字节的数据,则加密输出将为 1040 字节。解密时输入数据将为 1040 字节,输出解密数据将为 1024 字节。
示例 2:如果您有 1020 字节的数据,则加密输出将为 1024 字节。解密时,输入数据将为 1024 字节,输出解密数据将为 1020 字节。