我正在尝试使用“pbewithhmacsha256andaesĀu256”标准制定加密和解密文件的正确过程。
从我看到的oracle示例代码的理解来看。
我已经收集到需要salt,以及迭代计数和散列标准。
所以我有我的主要方法,传入加密方法:
用户定义的密码 new String(key).toCharArray()
作为字节数组(将此方法用于其他加密运行)
安全随机静脉注射 initVector
作为字节数组
纯文本文件 inputFile
作为字符串
要创建的密文文件的名称 outputFile
作为字符串
我按照代码示例编写了我认为正确的加密方法。我把salt和iv存储起来,通过把它们都加到密文中来解密。
private static void encrypt(byte[] key, byte[] initVector, String inputFile, String outputFile) //exceptions for throws... {
//Initalisation for encryption
Cipher cipher;
byte[] salt = new byte[16];
SecureRandom rand = new SecureRandom();
// Salt randomly generated with base64
rand.nextBytes(salt);
System.out.println("my salt should be" + Base64.getEncoder().encodeToString(salt));
salt = Base64.getEncoder().encode(salt);
// Iteration count
int count = 1000;
IvParameterSpec iv = new IvParameterSpec(initVector);
// Create PBE parameter set
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(Base64.getDecoder().decode(salt), count, iv);
// Convert pass into SecretKey object
PBEKeySpec pbeKeySpec = new PBEKeySpec(new String(key).toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
SecretKey pbeKey;
try {
pbeKey = keyFac.generateSecret(pbeKeySpec);
} catch (InvalidKeySpecException e) {
System.out.println("Sorry, the password specified cannot be used as a secret key");
System.out.println("Please check that your password uses valid characters");
return;
}
// Create PBE Cipher
cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");
// Initialize PBE Cipher with key and parameters
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
}
//File error checking and file handling (i.e. generating file paths)...
System.out.println("Secret key is " + Base64.getEncoder().encodeToString(key));
System.out.println("IV is " + Base64.getEncoder().encodeToString(initVector));
//Special file reading and writing with 'Cipher Stream'
try (InputStream fin = FileEncryptor.class.getResourceAsStream(loadFile.getName());
OutputStream fout = Files.newOutputStream(saveFile);
CipherOutputStream cipherOut = new CipherOutputStream(fout, cipher) {
}) {
final byte[] bytes = new byte[1024];
for(int length=fin.read(bytes); length!=-1; length = fin.read(bytes)){
fout.write(initVector);
fout.write(salt);
cipherOut.write(bytes, 0, length);
}
} catch (IOException e) {
System.out.println("Something went wrong with reading and writing these files!");
System.out.println("Please check you have the latest version of this program");
System.out.println("Contact your IT admin to make sure you have sufficient privileges");
}
System.out.println("SUCCESS! Encryption finished, saved at specified location");
}
然后我还有我的主要方法,传递到解密方法:
用户定义的密码 String inputKEY
作为字符串(也将此方法用于其他解密运行)
一根绳子 inputIV
,已作为null传入,因为不用于pbe。
密文文件 inputFile
作为字符串
要创建的revealplaintext文件的名称 outputFile
作为字符串
私有静态void decrypt(string inputkey,string inputiv,string inputfile,string outputfile){cipher cipher=null;
//File error checking and file handling (i.e. generating file paths)...
InputStream encryptedData = Files.newInputStream(loadFilePath);
PBEKeySpec pbeKeySpec = new PBEKeySpec(inputKEY.toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
SecretKey pbeKey = null;
try {
pbeKey = keyFac.generateSecret(pbeKeySpec);
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] initVect = new byte[16];
encryptedData.read(initVect);
IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(initVect);
byte[] salt = new byte[16];
encryptedData.read(salt);
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(Base64.getDecoder().decode(salt), 1000, iv);
cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");
System.out.println("my salt should be" + Base64.getEncoder().encodeToString(Base64.getDecoder().decode(salt)));
cipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
try (CipherInputStream decryptStream = new CipherInputStream(encryptedData, cipher);
OutputStream decryptedOut = Files.newOutputStream(saveFile)){
final byte[] bytes = new byte[1024];
for(int length=decryptStream.read(bytes); length!=-1; length = decryptStream.read(bytes)){
decryptedOut.write(bytes, 0, length);
}
} catch (IOException e) { //This is caught when decryption is run
System.out.println("Something went wrong with reading and writing these files!");
System.out.println("Please check you have the latest version of this program");
System.out.println("Contact your IT admin to make sure you have sufficient privileges");
}
System.out.println("SUCESS! Decryption finished, saved at specified location");
}
我相信我对pbe的理解有些不对劲,因此我实现它的方式可能是错误的。有人能指出哪里出了问题吗?
1条答案
按热度按时间ws51t4hk1#
主要问题是:
iv和盐不能写在
for
循环。静脉注射保存在
encrypt
不是base64编码的,而是base64解码的decrypt
.16字节的salt存储在
encrypt
(不必要的)base64编码,即存储24字节。在decrypt
但是,只加载了16个字节。也:
在编码/解码时,有时不指定编码,因此使用默认编码。
encrypt
以及decrypt
对key和iv使用不同的参数类型。代码中有许多复制/粘贴错误。
注意:与您的代码不同,链接的代码除了决定键外还决定了来自密码和salt的iv。在你的代码中,iv是通过的。因此,您必须确保密钥/iv对只能使用一次。通常为每个加密生成一个随机iv。
在下面的代码中(基于您的代码,但为简单起见,没有异常处理),这些问题已得到修复/优化。此外,本守则适用
FileInputStream
以及FileOutputStream
而不是你的课程(但这不是必需的):编辑-关于盐和iv的阅读
decrypt
:正如gpi在评论中指出的,
FileInputStream.read(byte[] b)
一般阅读b.length
字节,但这不能保证。更可靠的方法是确定读取数据的长度,并在循环中调用该方法,直到数据完成。另一种选择是使用InputStream.readNBytes(int len)
,保证len
字节(除非遇到流结尾或抛出异常),正如zabuzard所建议的。在代码中,现在使用了后者,即。read
被替换为readNBytes
.