解密文件时“最终确定密码时出错”

时间:2016-01-31 23:30:04

标签: android file encryption aes

每当我想要解密之前加密过的文件时,我会在“最终确定密码时出错”。

出于测试目的,我只是从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()

如果有人可以帮助我会很棒,我几个小时都在搜索解决方案:(

1 个答案:

答案 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 。它具有确定性,因此在语义上不安全。您应该至少使用CBCCTR等随机模式。最好对您的密文进行身份验证,以便像padding oracle attack这样的攻击是不可能的。这可以使用经过身份验证的模式(如GCM或EAX)或encrypt-then-MAC方案来完成。

查看RNCryptorJavaPHP),其中包含安全加密和互操作性的所有内容。