在 Linux、Java 中加密的 ANSI 编码文件存在问题

Problem with ANSI Encoding file with Encryption in Linux, Java

我用 mysqldump 导出数据库 java 在 Ubuntu 中的数据库,然后用 Java 加密和解密它。我使用以下 类 Encrypt and Decrypt with Java 来做到这一点。但是解密后文件开头的一些字符是错误的。这是问题所在: 第一张图片是以编程方式进行 mysqldump、加密和解密的文件。第二个只是来自同一命令行的 mysqldump。你能给我指明方向吗?谢谢

编辑 我创建了一个盐并将其存储在这样的文件中:

加密:

        FileInputStream saltFis = new FileInputStream("salt.enc");
        byte[] salt = new byte[8];
        saltFis.read(salt);
        saltFis.close();

        // reading the iv
        FileInputStream ivFis = new FileInputStream("iv.enc");
        byte[] iv = new byte[16];
        ivFis.read(iv);
        ivFis.close();

        SecretKeyFactory factory = SecretKeyFactory.getInstance(secretAlgorithm1);
        KeySpec keySpec = new PBEKeySpec(rsaSecret.toCharArray(), salt, 65536, 256);
        SecretKey secretKey = factory.generateSecret(keySpec);
        SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), secretAlgorithm2);

        //
        Cipher cipher = Cipher.getInstance(algorithmEncryption);
        cipher.init(Cipher.ENCRYPT_MODE, secret);

        // file encryption
        byte[] input = new byte[64];
        int bytesRead;

        while ((bytesRead = inFile.read(input)) != -1) {
            byte[] output = cipher.update(input, 0, bytesRead);
            if (output != null)
                outFile.write(output);
        }

        byte[] output = cipher.doFinal();
        if (output != null)
            outFile.write(output);

        inFile.close();
        outFile.flush();
        outFile.close();

解密:

        FileInputStream saltFis = new FileInputStream("salt.enc");
        byte[] salt = new byte[8];
        saltFis.read(salt);
        saltFis.close();

        // reading the iv
        FileInputStream ivFis = new FileInputStream("iv.enc");
        byte[] iv = new byte[16];
        ivFis.read(iv);
        ivFis.close();

        SecretKeyFactory factory = SecretKeyFactory.getInstance(secretAlgorithm1);
        KeySpec keySpec = new PBEKeySpec(rsaSecret.toCharArray(), salt, 65536, 256);
        SecretKey secretKey = factory.generateSecret(keySpec);
        SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), secretAlgorithm2);

        // file decryption
        Cipher cipher = Cipher.getInstance(algorithmEncryption);
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
        FileInputStream fis = new FileInputStream(decodedB64);
        FileOutputStream fos = new FileOutputStream(outputFile);
        byte[] in = new byte[64];
        int read;
        while ((read = fis.read(in)) != -1) {
            byte[] output = cipher.update(in, 0, read);
            if (output != null)
                fos.write(output);
        }

        byte[] output = cipher.doFinal();
        if (output != null)
            fos.write(output);
        fis.close();
        fos.flush();
        fos.close();
        System.out.println("File Decrypted.");

哦,那个很简单。这种使用 CBC 的文件加密方法很愚蠢(但很有趣,否则看起来基本上是正确的),将 IV 存储在一个单独的文件中,覆盖任何旧文件。因此,如果您覆盖或使用了错误的 IV 文件,那么您将在解密后的开头获得 16 个随机字节。因此,除非您能找到希望有意义的 IV 文件,否则您的前 16 个字节(/字符)现在将永远丢失。

当然,任何理智的加密程序都会将盐(密码和 PBKDF2 用于密钥派生)和 IV 存储在与密文相同的文件中。

不过,如果您设法丢失了 salt 文件或密码,那么所有数据都会丢失,所以……


通过添加代码,问题变得更加清晰。在加密模式下,您忘记在初始化期间完全创建和使用 IvParameterSpec

cipher.init(Cipher.ENCRYPT_MODE, secret);

但是,由于读取 IV 数据的方式,您不会收到任何关于未使用变量的警告:

ivFis.read(iv);

如果您创建了一个很好的方法,例如 IvParameterSpec iv = readIvFromFile() 那么您就会发现这个错误。


请注意 Java(默认情况下在 Cipher 包含的提供程序中)使用全零 IV,所以你很幸运,你的数据没有部分消失。