在 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,所以你很幸运,你的数据没有部分消失。
我用 mysqldump 导出数据库 java 在 Ubuntu 中的数据库,然后用 Java 加密和解密它。我使用以下 类 Encrypt and Decrypt with Java 来做到这一点。但是解密后文件开头的一些字符是错误的。这是问题所在:
编辑 我创建了一个盐并将其存储在这样的文件中:
加密:
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,所以你很幸运,你的数据没有部分消失。