29

我在 java 类中遇到解密错误:

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher.

我能做些什么来解决这个问题?

更新:

我忘了提到它正在工作一次,当我第二次尝试再次执行它时,它会抛出上述错误。

package com.tb.module.service;
import java.security.Key;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.*;

/**
 * This class is used for encrypt and decrypt the  password field.
 *
 */
public class PswdEnc {

    private static final String ALGO = "AES";
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };

    public static String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey(); 
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }


    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
    }

}
4

3 回答 3

87

您使用的算法“AES”是“AES/ECB/NoPadding”的简写。这意味着您正在使用具有 128 位密钥大小和块大小的AES 算法,具有ECB操作模式并且没有填充

换句话说:您只能加密 128 位或 16 字节块中的数据。这就是为什么你得到那个IllegalBlockSizeException例外。

如果要加密大小不是 16 字节的倍数的数据,则要么必须使用某种填充,要么使用密码流。例如,您可以通过将“AES/CBC/NoPadding”指定为算法来使用CBC 模式(一种有效地将块密码转换为流密码的操作模式),或者通过指定“AES/ECB/PKCS5”来使用 PKCS5 填充,这将自动以非常特定的格式在数据末尾添加一些字节,以使密文的大小成为 16 个字节的倍数,并且解密算法将理解它必须忽略某些数据。

无论如何,我强烈建议你现在停止你正在做的事情,去学习一些关于密码学的非常介绍性的材料。例如,查看Coursera 上的 Crypto I。您应该非常了解选择一种或另一种模式的含义,它们的优势是什么,最重要的是,它们的劣势是什么。如果没有这些知识,就很容易构建很容易被破坏的系统。


更新:根据您对该问题的评论,将密码存储在数据库中时永远不要加密!!!!!!!你永远不应该这样做。您必须对密码进行哈希处理,正确加盐,这与加密完全不同。真的,请不要做你想做的事......通过加密密码,它们可以被解密。这意味着您作为数据库管理员并且知道密钥,您将能够读取存储在数据库中的每个密码。要么你知道这一点并且正在做非常非常糟糕的事情,要么你不知道这一点,应该感到震惊并停止它。

于 2013-06-22T05:20:29.677 回答
5

几点评论:

import sun.misc.*;不要这样做。它是非标准的,并且不保证在实现之间是相同的。还有其他可用 Base64 转换的库。

byte[] encVal = c.doFinal(Data.getBytes()); 您在这里依赖默认字符编码。始终指定您使用的字符编码:byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); 不同地方的默认值可能不同。

正如@thegrinner 指出的那样,您需要明确检查字节数组的长度。如果存在差异,则逐字节比较它们,以查看差异在哪里蔓延。

于 2013-06-21T15:18:37.200 回答
0

那是因为

您只能加密 128 位或 16 字节块中的数据。这就是您收到 IllegalBlockSizeException 异常的原因。一种方法是将数据直接加密到字符串中。

看看这个。尝试一下,你将能够解决这个问题

public static String decrypt(String encryptedData) throws Exception {

    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.DECRYPT_MODE, key);
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
    System.out.println("This is Data to be Decrypted" + decordedValue);
    return decordedValue;
}

希望这会有所帮助。

于 2014-01-27T10:17:42.147 回答