"Error while finalizing cipher" 解密文件时

"Error while finalizing cipher" when decrypting a file

每当我想解密我之前加密的文件时,我得到 "error while finalizing cipher"。

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

如果有人能帮助我,那就太棒了,我搜索了几个小时的解决方案:(

不同之处在于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. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC 方案。


看看 RNCryptor (Java, PHP),它包含安全加密和互操作性的所有内容。