【问题标题】:When Decrypting Image, gives javax.crypto.BadPaddingException: pad block corrupted Android解密图像时,给出 javax.crypto.BadPaddingException: pad block损坏的Android
【发布时间】:2013-10-05 08:30:02
【问题描述】:

您好,我是 android 和图像加密的新手。 我的场景是这样的,

  • 首先我要加密图像文件。
  • 那我上传到服务器
  • 我正在从我的应用程序下载加密图像并将其保存在 SD 卡中。
  • 然后我在将其设置为 imageView 之前对其进行解密

(我用过的所有需要​​方法见底部..)

但我得到 javax.crypto.BadPaddingException: 解密时垫块损坏。我读了一些关于这个例外的文章,但都是关于文本加密的。你能帮我避免这种情况吗?提前谢谢你

图像加密使用 ...

private byte[] encrypt(byte[] raw, byte[] clear) throws Exception
{
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(clear);
    return encrypted;
}

这里我也保存了其他几张图片,都成功保存到了sd卡中...

for (int i = 0; i < imageUrls.size(); i++)
                {
                    File file = new File(imageUrls.get(i));

                    String metapath = CommonUtils.getDataFromPreferences("metaPath", "");
                    Log.d("metapath", metapath);
                    String extStorageDirectory = metapath + file.getName();

                    File wallpaperDirectory = new File(extStorageDirectory);
                    if (!wallpaperDirectory.exists() || wallpaperDirectory.length() == 0)
                    {
                        new DownloadImagesTask()
                            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imageUrls.get(i));
                    }
                }
                Toast toast = Toast.makeText(ScratchDetailsActivity.this, "Lottery was purchased and saved to sdcard/E-Lottery",
                    Toast.LENGTH_LONG);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();

图像解密...

这里的解密文件第一个参数是密钥,第二个是我们从 SD 卡获取的加密文件。

        decrpt = simpleCrypto.decrypt(KEY, getImageFileFromSdCard());
        bmpimg2 = BitmapFactory.decodeByteArray(decrpt, 0, decrpt.length);
        Drawable d = new BitmapDrawable(getResources(), bmpimg2);
        hiddenImage.setImageDrawable(d);

下载图像任务..

public class DownloadImagesTask extends AsyncTask<String, Void, InputStream>{
private String fileName;

@Override
protected InputStream doInBackground(String... urls)
{
    //Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    return download_Image(urls[0]);
}

@Override
protected void onPostExecute(InputStream result)
{
    storeImage(result);

}

private InputStream download_Image(String url)
{
    InputStream is = null;
    File file = new File(url);
    fileName = file.getName();
    try
    {
        URL aURL = new URL(url);
        URLConnection conn = aURL.openConnection();
        conn.connect();
        is = conn.getInputStream();
    }
    catch (OutOfMemoryError e)
    {
        Log.e("Hub", "Error getting the image from server : " + e.getMessage().toString());
    }
    catch (IOException e)
    {
        Log.e("Hub", "Error getting the image from server : " + e.getMessage().toString());
    }

    return is;
}

public void storeImage(InputStream is)
{

    String extStorageDirectory = CommonUtils.getDataFromPreferences("metaPath", "");

    Log.d("extStorageDirectory", extStorageDirectory);
    OutputStream outStream = null;

    File wallpaperDirectory = new File(extStorageDirectory);
    if (!wallpaperDirectory.exists())
    {
        wallpaperDirectory.mkdirs();
    }
    File outputFile = new File(wallpaperDirectory, fileName);
    if (!outputFile.exists() || outputFile.length() == 0)
    {
        try
        {
            outStream = new FileOutputStream(outputFile);
        }
        catch (FileNotFoundException e1)
        {
            e1.printStackTrace();
        }

        try
        {
            int bytesRead = -1;
            byte[] buffer = new byte[4096];
            while ((bytesRead = is.read(buffer)) != -1)
            {
                outStream.write(buffer, 0, bytesRead);
            }

            outStream.close();
            is.close();
            Log.d("ScratchActivtiy", "Image Saved");

        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}}

getImageFileFromSDCard 方法

/**
     * This method fetch encrypted file which is save in sd card and convert it in byte array after that this file will
     * be decrept.
     * 
     * @return byte array of encrypted data for decription.
     * @throws FileNotFoundException
     */

public byte[] getImageFileFromSdCard() throws FileNotFoundException
{

    byte[] inarry = null;

    try
    {
        String metapath = CommonUtils.getDataFromPreferences("metaPath", "");

        File imageFolder = new File(metapath);
        File urlFile = new File(selectedLottery.getImage());

        for (File f : imageFolder.listFiles())
        {
            if (urlFile.getName().equals(f.getName()))
                metapath = metapath + f.getName();
        }
        File imageFile = new File(metapath);
        //Convert file into array of bytes.
        FileInputStream fileInputStream = null;
        byte[] bFile = new byte[(int) imageFile.length()];
        fileInputStream = new FileInputStream(imageFile);
        fileInputStream.read(bFile);
        fileInputStream.close();
        inarry = bFile;

    }
    catch (IOException e)
    {
        Log.d("Exception", e.getMessage());
    }

    return inarry;
}

【问题讨论】:

    标签: java android encryption cryptography


    【解决方案1】:

    有很多事情可能会导致 Bad Padding 异常。要检查的明显事项是您正在使用的加密和解密:

    1. 相同的密钥,即逐字节相同。

    2. 相同的加密模式(通常是 CBC、CTR 或 GCM)。

    3. 相同的 IV/Nonce,再次逐字节相同。

    4. 相同的填充(PKCS5 或 PKCS7 很常见)。

    不要依赖系统默认设置,尤其是在一个系统上加密并在另一个系统上解密时,就像您似乎正在做的那样。如果系统默认值不同,那么您的解密将失败。始终明确设置键、模式、IV 和填充。在任何合理的加密库中都会有记录的方法。

    如果这不能解决问题,那么您将需要做更多的挖掘工作。将解密方法临时设置为 NoPadding 或您的库使用的任何等效方法。这将使解密方法忽略填充错误,并为您提供一些输出。查看输出并将其与原始输入进行比较;您可能需要查看此处的十六进制转储以确定发生了什么。

    其中的可能性有:

    1. 输出完全是垃圾:您的密钥错误,或者 IV/Nonce 对于流密码或 GCM 模式或 CTR 模式是错误的。

    2. 第一个块是垃圾,其余块与明文匹配:你 在 CBC 模式下输入错误的 IV。

    3. 输出与最后一些额外的东西匹配:额外的东西 是填充。将您的解密方法设置为期望该类型的 填充。

    如果这些都没有发生,请在此处再次询问并描述症状。

    当您找到解决方案后,您必须将您的解密方法重新设置为期望正确的填充。将其设置为NoPadding 是不安全的,因为任何旧垃圾都可以添加到解密的明文中。

    【讨论】:

    • 感谢@rossum 的回复。我正在使用相同的密钥。我创建了一个测试应用程序,它只使用上面下载图像部分的加密和解密。我在那里使用相同的 KEY 进行加密和解密。以前它工作得很好。但是现在这也给出了同样的例外。无论如何,我肯定会使用相同的 KEY。但关于 IV 和 CBC 模式我不确定。我想我没有使用过它们中的任何一个。我应该在哪里使用它们。你是要我用 NoPadding 替换 AES 吗?抱歉,我不太了解密码学。因为我只是从互联网上复制了这段代码。谢谢。
    • @ssdehero 在不了解的情况下从 Internet 复制代码不是编写密码学应用程序的正确方法。密码学不同于其他类型的代码——它可能似乎工作,但这并不意味着它提供任何类型的安全性。另见这篇文章:blogs.msdn.com/b/ericlippert/archive/2011/09/27/…
    • @ssdehero 您需要仔细研究系统文档。我怀疑您需要从 simpleCrypto 转移到功能更强大的加密库,以便您轻松进行所需的设置。简单的加密库做了很多假设,并且通常只会解密用完全相同的库加密的东西。您可能需要一个功能更齐全的库来覆盖不匹配的默认值。
    • @ntoskrnl 非常感谢您的建议。是的,我应该更多地了解这一点。我会再次阅读这篇文章谢谢你:)
    • @rossum 是的,我需要从这里转到高级版本。我将开始阅读文档。非常感谢你。如果您可以提供我可以参考的正确链接,那将非常有帮助。再次感谢你:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-20
    • 2015-08-04
    • 2019-12-09
    相关资源
    最近更新 更多