2

我试图从这里收集有关加密/解密的所有可能信息。修补它,一些成功和失败。
但是现在我已经应用了代码以及它的成功和失败。一些文件(exe 或 msi)正在运行,但它们仍然给出有关 BadPaddingException 的错误。此外,其他一些媒体文件,如(mp4、mkv 等),尽管已完全接收,但仍停留在 99% 并且没有超出此范围(只是一些微小的字节差异,但磁盘上的大小始终匹配)。

我只是想要一些帮助来摆脱这两个问题。文件 r 通过套接字编程从一台 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:添加了通过流接收的加密和解密文件大小的链接。Dropbox Link

Edit 2:所以最后在三位参与帮助我的成员的帮助下,问题得到了解决。我正在审查我的问题的其他解决方案,我遇到了这个解决方案,它帮助我深入思考后台发生的实际情况。感谢Artjom B.的推荐解决方案以及@zaph 和 @jtahlborn清除了我关于填充和输入/输出流的错误假设。

4

2 回答 2

2

当使用填充、PKCS#5 或 PKCS#7 时,加密输出会更大,最多包括一个块大小。参见PKCS#7。解密后删除填充。

加密数据将更长,因此必须加以考虑。如何取决于如何处理输出。如果它要进入预分配区域,例如内存缓冲区,则必须为缓冲区分配大一个块大小(AES 为 16 字节)。如果流式传输通常只是确保发送所有加密字节,则 n=它只是输入的长度。所有这些都取决于每个实现和系统/语言。

填充字节由加密方法动态创建,因此不需要更改输入。这假设加密方法是添加填充,而解密方法是删除填充。

示例 1:如果您有 1024 字节的数据,则加密输出将为 1040 字节。解密时,输入数据为 1040 字节,输出解密数据为 1024 字节。

示例 2:如果您有 1020 字节的数据,则加密输出将为 1024 字节。解密时,输入数据为 1024 字节,输出解密数据为 1020 字节。

于 2016-02-27T13:00:46.140 回答
1

您不能使用 FileInputStream 来读取您当前正在编写的文件。它不是为读取正在进行的文件而构建的。

看起来您正在尝试将加密流写入dos(您没有在服务器代码中包含它的定义)。如果是这样,您应该将其用作 CipherOutputStream 的基础流。

同样,在客户端中,您尝试同样的事情。如果要先将文件写入磁盘,然后将整个文件写入磁盘,然后解密。如果要流式解密,则将 CipherInputStream 包装在套接字 InputStream 周围(大概dis?)。

此外,您没有显示您len从客户端获得的位置,但我假设它是原始数据的长度?如果是这样,那么您的进度计算是不正确的,因为加密数据的长度通常与原始数据的长度不同。

于 2016-02-26T22:28:27.167 回答