每当我想要解密之前加密过的文件时,我会在“最终确定密码时出错”。
出于测试目的,我只是从here复制了Pero的代码。
我所做的一切都是去除盐并用我的md5功能取而代之。 在此之前,我尝试了盐,它给了我同样的错误:(
在另一个问题中,这个问题似乎以某种方式得到了解决,但他没有进一步详细说明,这只是盐,我甚至没有使用过。
public static void encrypt(String path, String password) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(path.concat(".scrypt"));
byte[] key = md5(password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key,16);
SecretKeySpec sks = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sks);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[8];
while((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
cos.flush();
cos.close();
fis.close();
}
public static void decrypt(String path, String password) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(path.replace(".scrypt", ""));
byte[] key = md5(password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key,16);
SecretKeySpec sks = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
md5()相当于php的md5()
如果有人可以帮助我会很棒,我几个小时都在搜索解决方案:(
答案 0 :(得分:1)
区别在于encrypt
:
byte[] key = md5(password).getBytes("UTF-8");
和decrypt
:
byte[] key = (salt + password).getBytes("UTF-8");
毋庸置疑,这会导致不同的密钥无法进行正确的解密。
密码的这种密钥派生不是远程安全的。密码具有低熵,但密钥具有高熵。如果要将密码转换为密钥,则需要使用计算密集型操作,以便攻击者只能尝试所有简单密码。这可以使用PBKDF2,bcrypt,scrypt或Argon2来完成。使用多次迭代或高成本因子,并始终使用随机生成的盐。盐不必是秘密的,但它必须与密文一起发送到接收器。您可以在密文前面写它并在解密期间将其读回。
始终使用完全限定的密码字符串,因为不同的JVM可能具有不同的默认值。这将使互操作性成为一场噩梦。您当前的字符串可能默认为Cipher.getInstance("AES/ECB/PKCS5Padding");
绝不使用ECB mode 。它具有确定性,因此在语义上不安全。您应该至少使用CBC或CTR等随机模式。最好对您的密文进行身份验证,以便像padding oracle attack这样的攻击是不可能的。这可以使用经过身份验证的模式(如GCM或EAX)或encrypt-then-MAC方案来完成。