【问题标题】:Android AES with no padding decryption, unknown characters 'NUL' at the end of string没有填充解密的Android AES,字符串末尾的未知字符“NUL”
【发布时间】:2014-07-15 03:16:33
【问题描述】:

我有以下代码来解密通过 PHP mcrypt 函数加密的 Java 文件。

private String iv = "MYKEYHERE";//Dummy iv (CHANGE IT!)
private String SecretKey = "MYKEYHERE";//Dummy secretKey (CHANGE IT!)

private byte[] decrypt(String code)
{
    byte[] decrypted = null;
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
        SecretKeySpec keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
        if(code == null || code.length() == 0)
            throw new Exception("Empty string");

        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

        decrypted = cipher.doFinal(hexToBytes(code));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return decrypted;
}

private static byte[] hexToBytes(String str) {
    if (str==null) {
        return null;
    } else if (str.length() < 2) {
        return null;
    } else {
        int len = str.length() / 2;
        byte[] buffer = new byte[len];
        for (int i=0; i<len; i++) {
            try {
                buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return buffer;
    }
}

我正在从 SDCARD 读取和写入文件为

String encyptedData = readFileFromSDCard(params[0]);

byte[] decryptedByteArray = decrypt(encyptedData);

File rootFile = new File(Constants.folioTempLocation+params[1]);
rootFile.mkdirs();

File outFile = new File(rootFile,  new File(params[0]).getName());
FileOutputStream out = new FileOutputStream(outFile);
//IOUtils.write(decryptedByteArray, out);
out.write(decryptedByteArray);
out.flush();
out.close();

解密并将文件写回SD_CARD没有问题。但是我在每个文件的末尾都有未知字符,这限制了整个解密文件的正常工作。

我附上了连接到字符串末尾的未知字符的屏幕截图。我还附上了encrypted_html_file,供任何想使用此文件测试代码的人使用。

截图

【问题讨论】:

  • @Andrew T. 感谢您的编辑,您知道我做错了什么吗?
  • 其实我也不知道,因为我自己没遇到过。如果在其他文件上测试,是否总是返回 5 个 NULL 字符?
  • @AndrewT。 NUL 字符是任意的,它在字符串末尾从 2 到 10 不等。 Notepad++ 将其显示为NUL 字符,但记事本将其显示为空格。
  • 它是一个null control character,以字节为单位表示为0x00。由于解密没有问题,我怀疑是加密神器。在任何情况下,可能都可以通过在解密文件后、保存文件之前删除尾随的空值来修复它。
  • @AndrewT。感谢您的研究,您能否发布如何删除尾随 NUL 的答案,因为我也尝试从末尾修剪 byte[],但没有运气。

标签: java php android encryption cryptography


【解决方案1】:

CBC 是一种块模式,必须与适当的填充方案一起使用。

PHP 的mcrypt 使用zero padding - 它将\0 字符附加到输入数据以使其长度成为块大小的倍数。很明显,解密时你会得到这些零字节。

mycrypt 页面有一个示例,说明如何在用户 cmets 中实现正确的 PKCS#7 填充方案。在其他mcrypt padding 问题中,How to add/remove PKCS7 padding from an AES encrypted string? 提供了一个类似的例子。

【讨论】:

    【解决方案2】:

    由于我不知道问题的原因,我只能提供一种解决方法来删除尾随的空值 (NUL)。

    public static byte[] removeTrailingNulls(byte[] source) {
        int i = source.length;
        while (source[i - 1] == 0x00) {
            i--;
        }
    
        byte[] result = new byte[i];
        System.arraycopy(source, 0, result, 0, i);
    
        return result;
    }
    

    解密文件后试试

    byte[] decryptedByteArray = removeTrailingNulls(decrypt(encyptedData));
    

    警告: 这可能会影响性能(尤其是在移动设备上),因为它使用了几乎两倍的内存使用量。

    这种解决方法并不完美,因为无论原始数据如何,它都会删除尾随的空值。使用风险自负

    【讨论】:

    • 像魅力一样工作,但如果我在主内存超过 1GB 的设备的后台线程中执行该进程,我是否需要担心。
    • 警告更像是对未来观众的一般警告:并非所有设备都超过 1GB,也不是所有应用都可以使用所有这些 ;)
    • 如果真实数据有尾随零字节怎么办?您的代码无法区分那些零字节和填充字节。
    • @Greg 我知道,这就是为什么我说“解决方法”,而不是“正确的方法”。尽管如此,我将把这个答案留在这里,并为此添加了另一个警告。谢谢你提醒我。
    猜你喜欢
    • 2012-12-14
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多