如何用Java对PKCS#12存档文件进行AES256加密/解密



我的应用程序需要加密已使用密码notasecret加密的PKCS#12存档文件。该文件应该是AES256加密的。

我尝试使用此解决方案进行加密。我的想法是加密从文件中读取的字符串,并将其写入新文件,然后在需要时解密

现在我正在测试字符串是否正确加密和解密(创建的新文件是否与原始文件相同)。事实并非如此。

问题

我下面的代码应该通过加密和解密.p12文件来创建一个相同的文件,但生成的文件更大(原始文件:1.7KB,新文件:2.5KB),并且作为PKCS#12档案无法读取。中间的字符串长度测试显示相同的长度。

有线索吗?文件是一种格式还是另一种格式(PKCS#12存档、二进制、纯文本)重要吗如果要加密的文件是纯文本的,下面的代码非常有效

代码

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.security.AlgorithmParameters;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class FileEncryptionTest {
public static void main(String[] args) throws Exception {
char[] password = "password".toCharArray();
byte[] salt = new byte[8];
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
String file = "someprivatekey.p12";
String keyFileText = readFile(file);
byte[] ciphertext = cipher.doFinal(keyFileText.getBytes("UTF-8"));
Cipher otherCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
otherCipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(otherCipher.doFinal(ciphertext), "UTF-8");
if (plaintext.equals(keyFileText))
System.out.println("decrypted plaintext same as plaintext");
System.out.println("plaintext length: " + plaintext.length() + " keyFileText length: " + keyFileText.length());
writeFile(plaintext, "new-" + file);
}
private static void writeFile(String contents, String filePath) {
PrintWriter out = null;
try {
out = new PrintWriter(new FileOutputStream(filePath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
out.write(contents);
out.close();
}
private static String readFile(String filePath) {
FileInputStream fis = null;
int buf;
StringBuilder contents = null;
try {
fis = new FileInputStream(filePath);
contents = new StringBuilder();
while ((buf = fis.read()) != -1) {
contents.append((char) buf);
}
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
return contents.toString();
}
}

您将二进制文件视为字符串。二进制文件将包含许多不能作为字符处理的字符。请重写您的代码,并假设PKCS#12文件是二进制的(例如使用FileInputStream/FileOutputStream组合,或者-对于不是那么大的文件-使用readAllBytes而不是输入流。

多亏了@owlstead关于错误使用数据的提示,我成功地将数据视为byte[]而非String来正确加密和解密文件。这些是相关的变化:

private static void writeFile(byte[] contents, String filePath) {
FileOutputStream out = null;
try {
out = new FileOutputStream(filePath);
out.write(contents);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static byte[] readFile(String filePath) {
FileInputStream fis = null;
File f = new File(filePath);
int buf, i = 0;
byte[] array = null;
try {
fis = new FileInputStream(f);
array = new byte[(int) f.length()];
while ((buf = fis.read()) != -1) {
array[i++] = (byte) buf;
}
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
return array;
}

最新更新