0

我正在使用以下代码加密资产文件夹中的图像并尝试在 apk 中解密。(我这样做只是为了避免通过解压缩apk文件轻松复制图像)。我知道我将把密钥作为 apk 的一部分。

我使用并测试了下面的代码,用于使用独立的 java 程序加密图像。(我通过 decrpyting 对其进行了测试,它在独立的 java 程序中运行良好。

加密

         byte[] incrept = simpleCrypto.encrypt(KEY, simpleCrypto.getImageFile("E:/aeroplane.png"));


         //Store encrypted file in SD card of your mobile with name vincent.mp3.
       FileOutputStream fos = new FileOutputStream(new File("E:/out-aeroplane.png"));
          fos.write(incrept);
          fos.close();

解密

        byte[] decrpt = simpleCrypto.decrypt(KEY, simpleCrypto.getImageFile("E:/out-aeroplane.png"));

          //Store encrypted file in SD card of your mobile with name vincent.mp3.
          FileOutputStream fosdecrypt = new FileOutputStream(new File("E:/outdecrypt-aeroplane.png"));


          fosdecrypt.write(decrpt);
          fosdecrypt.close();

加密解密逻辑

   public byte[]   getImageFile(String fileName) throws FileNotFoundException
{
  byte[] Image_data = null;
  byte[] inarry = null;

    try {
        File file = new File(fileName);
        @SuppressWarnings("resource")
    FileInputStream  is = new FileInputStream (file); // use recorded file instead of getting file from assets folder.
        int length = is.available();
        Image_data = new byte[length];

        int bytesRead;
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        while ((bytesRead = is.read(Image_data)) != -1)
        {
            output.write(Image_data, 0, bytesRead);
        }
      inarry = output.toByteArray();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

return inarry;
}


public  byte[] encrypt(String seed, byte[] cleartext) throws Exception {

    byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext);
      //  return toHex(result);
        return result;
}

public  byte[] decrypt(String seed, byte[] encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = encrypted;
        byte[] result = decrypt(rawKey, enc);

        return result;
}

//done
private  byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(seed);
    kgen.init(128, sr); 
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
} 


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;
}

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

在将图像作为 InputStream 获取后的我的 apk 文件中,我在将它们转换为字节数组后对其进行解密。我再次将解密的字节数组转换为 BitmapFactory.decode 的输入流。我尝试了 decodeByteArray 和 decodeStream。两者都不起作用。

图像使用独立的 java 程序加密,并在 apk 中解密。(如果我在独立的 java 程序中解密,它工作正常。)

我收到错误消息 Failed to decode Stream javax.crypto.BadPaddingException: pad block损坏

    public static Bitmap readBitmap(InputStream input) {
    if (input == null)
        return null;

    try {
        String KEY = "kumar";

        byte[] inarry =IOUtils.toByteArray(input);
        byte[] decrpt = SquarksCryptUtil.decrypt(KEY, inarry);

    InputStream cleanStream = null;

    cleanStream = new ByteArrayInputStream(decrpt);

     //   return BitmapFactory.decodeStream(cleanStream);
    return BitmapFactory.decodeByteArray(decrpt, 0, decrpt.length);


       // return BitmapFactory.decodeStream(input);
    } catch (Exception e) {
        Log.e(FILE_NAME, "Failed to decode Stream " + e);
        return null;
    } finally {
        close(input);
    }

}

4

1 回答 1

3

您面临的问题是因为您假设随机数在每个平台上生成相同的密钥。这个问题是由于互联网上有一个非常糟糕的示例SecureRandom用作密钥派生函数,但事实并非如此SecureRandom如果直接设置种子,甚至没有很好的定义。您可以使用 PBKDF2 而不是两边不正确的密钥派生函数,stackoverflow 上应该有足够的指针来说明如何使用 Java 执行 PBKDF2 密钥派生。

最好的办法是在 SE 平台上解密图像,然后使用 PBKDF2 正确地重新加密它们。目前,密钥的派生方式仅在 Sun 实现的源代码中指定"SHA1PRNG"。这根本不是一个好的基础。

此外,正如其他人已经指出的那样,您需要确保在加密/解密期间没有平台依赖性。

于 2013-05-30T20:33:25.720 回答