1

我使用像3des-encryption-decryption-in-java这样的代码,但是当我使用解密它时,它得到了这样的错误

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
07-17 11:27:27.580: WARN/System.err(22432): at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:705)
07-17 11:27:27.580: WARN/System.err(22432): at javax.crypto.Cipher.doFinal(Cipher.java:1111)

但是如果我final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");改为final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding");,该方法可以运行但得到错误的结果(模式与服务器不同)。所以我想知道它的原因。

解密方法:

public static String decrypt(byte[] message) throws Exception {
    final MessageDigest md = MessageDigest.getInstance("SHA-1");
    final byte[] digestOfPassword = md.digest(token.getBytes("utf-8"));
    final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
    for (int j = 0, k = 16; j < 8;) {
        keyBytes[k++] = keyBytes[j++];
    }

    final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
    final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
    final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    // final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding");
    decipher.init(Cipher.DECRYPT_MODE, key, iv);
    final byte[] plainText = decipher.doFinal(message);
    return new String(plainText, "UTF-8");
}

加密方法:

public static byte[] encrypt(String message) throws Exception {
        final MessageDigest md = MessageDigest.getInstance("SHA-1");
        final byte[] digestOfPassword = md.digest(token
                .getBytes("utf-8"));
        final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        for (int j = 0, k = 16; j < 8; ) {
            keyBytes[k++] = keyBytes[j++];
        }

        final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
        final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv, new SecureRandom(new byte[5]));
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);

        final byte[] plainTextBytes = message.getBytes("utf-8");
        final byte[] cipherText = cipher.doFinal(plainTextBytes);
        return cipherText;
    }
4

1 回答 1

1

有很多可能性
最常见的是,如果您将密钥编码为字符串,尤其是没有指定字符编码。如果要执行此操作,请使用 Base-64,它旨在对任何binary数据进行编码,而不是字符编码
还要确保源平台和目标平台编码应该相同。正如您在UTF-8此处和其他地方使用的那样,UTF-8必须使用

现在看看你告诉代码正在运行final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding");但不是final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
在解密时运行的事实,你必须知道你在加密时选择的填充大小模式。正如你所说,当你利用CBC模式比它抛出异常但是当你改变它时CFB它就可以运行了。在这种情况下,你需要确定你在加密时使用的是哪种模式。

附带说明: CBC、OFB 和 CFB 是相同的,但是 OFB/CFB 更好,因为您只需要加密而不需要解密,这样可以节省代码空间。
CBC(密码块链接)用于数据经过AES函数的地方,反馈用于修改预先加密的数据,使重复的​​明文数据不会产生相同的加密数据。数据只能在与底层加密函数的块大小匹配的块中处理(在 AES 的情况下是 128 位块),并且必须在加密和解密引擎之间提供此块级别的同步,否则数据将无法破译
CFB(密码反馈模式)也是一种通用模式,并提供了使底层分组密码像流密码一样工作的可能性;IE。以便处理的数据可以是较短值的流(例如字节甚至单个位),而不是仅处理更大的块。在 CFB 模式下,数据本身不通过 AES 引擎,而是进行异或使用 AES 引擎从以前的消息历史记录中生成的值。这意味着通过 CFB 函数的延迟可以最小化,因为应用于数据的唯一处理是 XOR 函数。数据宽度可以设置为不超过底层密码块大小的任何大小,但请注意,吞吐量会随着数据宽度与块大小的比率变小而降低。(边注结束:D)
如果您使用密码反馈 (CFB) 或输出反馈 (OFB) 或计数器 (CTR) 模式进行加密,则密文将与明文大小相同,因此不需要填充。但是,在使用这些模式时要小心,因为初始化向量 (IV) 必须是唯一的。
同样,使用 RC4 或 PC1 等流密码进行加密也不需要填充。

现在,如果我们比您更严格地进行调查,则应该注意块大小和填充大小(上面已经提到)。现在您需要确保的第一件事是您的加密算法定义的填充大小。正如我在 CFB 中提到的那样不需要填充大小写,所以首先尝试不提供填充。
如果问题仍然存在,则检查它是pkcs5pkcs7.通过将 decrytpion 填充大小设置为来尝试您的代码pkcs7。如果是,pkcs7那么我想它也应该与 CBC 一起使用。我建议您阅读Using Padding in Encryption

作为附加信息

  • PKCS#5 填充在 RFC 2898(PKCS#5:基于密码的加密规范版本 2.0)中定义。

  • PKCS5 填充是一种填充方案,用于扩展任意数据以匹配块密码的块大小,从而允许接收端可靠地删除填充。

  • PKCS#7 (CMS, RFC 3369) 定义了一个填充方案,但它是 PKCS#5 填充的扩展,用于块密码超过 8 个字节。

于 2013-07-17T04:03:53.197 回答