【问题标题】:android AES decrypt files: BadPaddingException: EVP_CipherFinal_exandroid AES解密文件:BadPaddingException:EVP_CipherFinal_ex
【发布时间】:2017-01-19 08:54:27
【问题描述】:

我最近正在研究文件加密/解密。

BadPaddingException: EVP_CipherFinal_ex: 当我尝试使用相同的密钥解密文件时总是发生。

代码 sn-ps 将在下面发布。

我做错了吗?

感谢您的帮助。

加密

public static void encryptFile() {
    File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + TARGET_FILE);

    FileInputStream fileInputStream;
    FileOutputStream fileOutputStream;

    byte[] buffer = new byte[1024 * 8];

    IvParameterSpec ivParameterSpec = new IvParameterSpec("1234567890123456".getBytes());

    byte[] key = "only for testing".getBytes();
    MessageDigest sha;
    try {
        sha = MessageDigest.getInstance("SHA-1");
        key = sha.digest(key);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    key = Arrays.copyOf(key, 16); // use only first 128 bit

    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

    try {
        fileInputStream = new FileInputStream(file);
        fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/" + ENCRYPT_FILE);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

        //CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher);

        int read;

        while ((read = fileInputStream.read(buffer)) > 0) {
            Log.i(TAG, "encrypt read= " + read);

            byte[] encryptedData = cipher.doFinal(buffer);
            if (encryptedData != null) {
                Log.i(TAG, "encrypted size= " + encryptedData.length);
                fileOutputStream.write(encryptedData, 0, read);
            }

            //cipherOutputStream.write(buffer, 0, buffer.length);
        }
        //cipherOutputStream.flush();
        //cipherOutputStream.close();
        fileInputStream.close();
        fileOutputStream.close();

    } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException
            | IllegalBlockSizeException | BadPaddingException
            | InvalidAlgorithmParameterException | InvalidKeyException e) {
        e.printStackTrace();
    }
}

解密

public static void decryptFile() {
    File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + ENCRYPT_FILE);

    FileInputStream fileInputStream;
    FileOutputStream fileOutputStream;

    byte[] buffer = new byte[1024 * 8];

    IvParameterSpec ivParameterSpec = new IvParameterSpec("1234567890123456".getBytes());

    byte[] key = "only for testing".getBytes();
    MessageDigest sha;
    try {
        sha = MessageDigest.getInstance("SHA-1");
        key = sha.digest(key);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    key = Arrays.copyOf(key, 16); // use only first 128 bit

    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

    try {
        fileInputStream = new FileInputStream(file);
        fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/" + DECRYPT_FILE);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

        //CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher);

        int read;

        while ((read = fileInputStream.read(buffer)) > 0) {
            Log.i(TAG, "decrypt read= " + read);

            byte[] decryptedData = cipher.doFinal(buffer);
            if (decryptedData != null) {
                Log.i(TAG, "decrypted size= " + decryptedData.length);
                fileOutputStream.write(decryptedData, 0, read);
            }

            //fileOutputStream.write(buffer, 0, buffer.length);
        }
        fileOutputStream.flush();
        fileOutputStream.close();
        //cipherInputStream.close();
        fileInputStream.close();

    } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException
            | IllegalBlockSizeException | BadPaddingException
            | InvalidAlgorithmParameterException | InvalidKeyException e) {
        e.printStackTrace();
    }
}

btw:当我使用 CipherInputStream / CipherOutStream 时它会正常工作。我想知道是否可以只使用 FileInputStream / FileOutputStream ?谢谢。

编辑: 加密函数会将字节数组放大约 16 个字节,我尝试增加解密的缓冲区大小,但仍然无法正常工作。

byte[] buffer = new byte[1024 * 8 + 16];

日志:

I/#_:解密读取 = 8208

javax.crypto.BadPaddingException: EVP_CipherFinal_ex

在 com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)

在 com.android.org.conscrypt.OpenSSLCipher.doFinalInternal(OpenSSLCipher.java:430)

在 com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:466)

在 javax.crypto.Cipher.doFinal(Cipher.java:1340)

在 CryptoHelper.decryptFile(CryptoHelper.java:128)

已编辑根据#Robert 对遇到与我相同问题的任何人的回答,在此处更新代码。

加密:

int read;

        while ((read = fileInputStream.read(buffer)) > 0) {
            Log.i(TAG, "encrypt read= " + read);
            byte[] encryptedData = cipher.update(buffer, 0, read);
            //byte[] encryptedData = cipher.doFinal(buffer);
            if (encryptedData != null) {
                Log.i(TAG, "encrypted size= " + encryptedData.length);
                fileOutputStream.write(encryptedData, 0, encryptedData.length);
            }

            //cipherOutputStream.write(buffer, 0, buffer.length);
        }
        byte[] finals = cipher.doFinal();
        Log.i(TAG, "encrypted finals = " + finals.length);
        fileOutputStream.write(finals, 0, finals.length);

解密:

int read;

        while ((read = fileInputStream.read(buffer)) > 0) {
            Log.i(TAG, "decrypt read= " + read);

            //byte[] decryptedData = cipher.doFinal(buffer);
            byte[] decryptedData = cipher.update(buffer, 0, read);
            if (decryptedData != null) {
                Log.i(TAG, "decrypted size= " + decryptedData.length);
                fileOutputStream.write(decryptedData, 0, decryptedData.length);
            }

            //fileOutputStream.write(buffer, 0, buffer.length);
        }
        byte[] finals = cipher.doFinal();
        Log.i(TAG, "decrypted finals = " + finals.length);
        fileOutputStream.write(finals, 0, finals.length);

再次感谢罗伯特的帮助。

【问题讨论】:

    标签: android encryption cryptography


    【解决方案1】:

    你的问题是你总是为每个错误的数据块调用cipher.doFinal(),因为每个块都会被填充。

    如果您要逐块加密/解密数据,请使用cipher.update(...),并且在处理完最后一个块后,只需调用一次cipher.doFinal()

    更简单的方法是使用 CipherInputStream/CipherOutputStream - 它完全符合我为您描述的内容(关闭流时调用 doFinal)。

    【讨论】:

    • 我按照您的回答编辑了代码。现在可以了。非常感谢您的帮助。你拯救了我的一天。
    猜你喜欢
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多