【问题标题】:"Error while finalizing cipher" when decrypting a file解密文件时出现“确定密码时出错”
【发布时间】:2016-01-31 23:30:04
【问题描述】:

每当我想解密之前加密的文件时,我都会收到“确定密码时出错”。

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

如果有人可以帮助我,那就太棒了,我花了几个小时寻找解决方案:(

【问题讨论】:

    标签: android file encryption aes


    【解决方案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),它拥有安全加密和互操作性的一切。

    【讨论】:

    • 首先,感谢所有关于如何加密的见解,其次感谢提到 RNCryptor。我已经尝试过了,至少它有效。然而性能却是惨不忍睹。只需加密“Hello World!”解密总共需要 10 秒。你知道为什么这需要这么长时间吗?无论我加密什么,每个命令都需要 5 秒才能加载...
    • 不,我不知道为什么这么慢。
    • Nvm 我切换到了一个新的解决方案,我已经接近让它工作了。我完成后你能看一下代码并指出我犯的任何错误吗?我对这个游戏还很陌生,它会让我受益匪浅!
    • 如果您有工作代码,但您不知道它是否有任何好处(安全性/性能/可读性),Stack Overflow 不适合提出这样的问题。 Code Review 更适合这类问题。如果你可以让它工作,那么你可以在这里提出一个新问题。
    • 只要它确实回答了您的问题,我认为它没有任何问题。不要忘记链接回Code Review 上的特定问答,以提供正确的归属。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多