我使用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;
}
答案 0 :(得分:1)
有很多种可能性。最常见的是如果你将密钥编码为字符串,特别是没有指定字符编码。如果要执行此操作,请使用Base-64,它用于编码任何binary
数据,而不是字符编码。还要确保源平台和目标平台编码应该相同。当您在这里使用UTF-8
然后在另一个en上使用UTF-8
必须使用
现在看看你告诉代码运行{{1而不是final Cipher decipher = Cipher.getInstance("DESede/CFB/NoPadding");
在解密时,您必须知道在加密时选择的填充大小和模式。正如您所说的那样,当您使用final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
模式时抛出异常,但当你将其更改为CBC
时,它就能运行。在这种情况下,你需要确保在加密时使用哪种模式。
作为附注: CBC,OFB和CFB是相同的,但OFB / CFB更好,因为您只需要加密而不是解密,这可以节省代码空间。
CBC(密码块链接)用于数据通过AES功能的地方,并应用反馈来修改预加密数据,以便重复的普通数据不会产生相同的加密数据。数据只能在与基础加密函数的块大小匹配的块中处理(在AES的情况下为128位块),并且必须在加密和解密引擎之间提供此块级别的同步,否则数据将难以理解的
CFB(密码反馈模式)也是一种常见模式,它提供了使基础分组密码像流密码一样工作的可能性。即。因此,正在处理的数据可以是较短值的流(例如字节或甚至单个位),而不是仅处理更大的块。在CFB模式下,数据本身不通过AES引擎,而是进行异或具有AES引擎从先前消息历史记录生成的值。这意味着可以最小化通过CFB功能的延迟,因为应用于数据的唯一处理是XOR功能。数据宽度可以设置为任何大小,直到基础密码块大小,但请注意,随着数据宽度与块大小之比的宽度变小,吞吐量会降低。(侧注结束:D)
如果使用密码反馈(CFB)或输出反馈(OFB)或计数器(CTR)模式进行加密,则密文将与明文的大小相同,因此不需要填充。但是,使用这些模式时要小心,因为初始化矢量(IV)必须是唯一的
同样,使用像RC4或PC1这样的流密码进行加密不需要填充。
现在如果我们进行更严格的调查,你应该注意块的大小和填充大小(已经在上面提到过)。现在你需要确定的第一件事就是加密定义的填充大小算法。正如我所提到的,在CFB情况下不需要填充,所以首先尝试它而不给出填充。
如果问题仍然存在,则检查它是CFB
还是pkcs5
。尝试你的代码将decryptpion填充大小设置为pkcs7
。如果是pkcs7
,那么我猜它也适用于CBC。我建议你阅读Using Padding in Encryption
作为附加信息
PKCS#5填充在RFC 2898(PKCS#5:基于密码的加密规范版本2.0)中定义。
PKCS5填充是一种填充方案,用于扩展任意数据以匹配块密码的块大小,允许接收端可靠地删除填充。
PKCS#7(CMS,RFC 3369)定义了一个填充方案,但它是块密码的PKCS#5填充的扩展,块密码超过8个字节。