【问题标题】:javax.crypto.IllegalBlockSizeException : Input length must be multiple of 16 when decrypting with padded cipher [duplicate]javax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是 16 的倍数 [重复]
【发布时间】:2013-06-18 12:47:19
【问题描述】:

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

}

【问题讨论】:

  • 无论你解密的是错误的大小。它需要是块大小 (16) 的倍数,否则无法解密。你是如何得到你的解密数据的?
  • 实际上我在将密码保存到 sql db 之前对其进行了加密。然后在检索时我试图解密它。
  • 你确定你保存的数据和你读出的数据长度一样吗?
  • 写入数据库时​​获取数组的长度,读出时再获取。

标签: java encryption


【解决方案1】:

您使用的算法“AES”是“AES/ECB/NoPadding”的简写。这意味着您正在使用具有 128 位密钥大小的 AES algorithmblock size,以及 ECB mode of operationno padding

换句话说:您只能加密 128 位或 16 字节的块中的数据。这就是为什么您会收到 IllegalBlockSizeException 异常。

如果您想加密大小不是 16 字节的倍数的数据,您将不得不使用某种填充或密码流。例如,您可以通过将“AES/CBC/NoPadding”指定为算法来使用CBC mode(一种将分组密码有效地转换为stream cipher的操作模式),或者通过指定“AES/ECB/PKCS5”来使用PKCS5填充

无论如何,我强烈建议你现在停下手头的工作,去学习一些关于密码学的入门材料。例如,检查Crypto I on Coursera。您应该非常了解选择一种或另一种模式的含义,它们的优势是什么,最重要的是,它们的劣势是什么。如果没有这些知识,就很容易构建很容易被破坏的系统。


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

【讨论】:

  • 我不知道我不应该加密密码并将其存储在数据库中。感谢您的信息。
  • @baburao113 那么你真的应该接受答案
  • +1 推荐散列而不是加密
  • 所以,非常棒地提到哈希更好,虽然更好会更好,但是如何提供关于它是什么以及如何完成它的线索。那会更棒。
  • 对戏剧性和屈尊俯就投反对票。必须以纯文本形式传输的密码不能存储为哈希
【解决方案2】:

几个cmets:

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

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

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

【讨论】:

  • 还有其他支持Base64转换的库 > 从Java 6开始,试试DatatypeConverter
【解决方案3】:

那是因为

您只能加密 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;
}

希望这会有所帮助。

【讨论】:

  • 抱歉,sn-p 提供的代码不能解密。它仅使用 Base64 对输入进行解码。解码将使用 new String(c.doFinal(decodedValue))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
  • 1970-01-01
  • 2012-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多