【问题标题】:Decrypting string generates IllegalBlockSizeException解密字符串生成 IllegalBlockSizeException
【发布时间】:2014-07-15 11:35:55
【问题描述】:

我在处理解密方法时遇到问题。加密产生了正确的输出,但是当我解密完全相同的加密字符串(应该回到明文字符串)时,它不起作用。

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

public class Samp {

    private static String IV = "aaaaaaaaaaaaaaaa";
    private static final String UNICODE_FORMAT = "UTF8";

    private String padd(String plaintext) {
        while (plaintext.length() % 16 != 0) {
            plaintext += "\0";
        }
        return plaintext;
    }

    public String encryptString(String plaintext, String encryptionKey) {
        try {
            byte[] cipher = encrypt(padd(plaintext), encryptionKey);
            return new String(cipher, UNICODE_FORMAT);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public String decryptString(String encString, String encryptionKey) {
        try {
            System.out.println("**** decryptString ****");
            System.out.println("enc = " + encString);
            System.out.println("key = " + encryptionKey);

            String decrypted = decrypt(encString.getBytes(UNICODE_FORMAT), encryptionKey);
            return decrypted;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    private static byte[] encrypt(String plainText, String encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes(UNICODE_FORMAT), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV.getBytes(UNICODE_FORMAT)));
        return cipher.doFinal(plainText.getBytes(UNICODE_FORMAT));
    }

    private static String decrypt(byte[] cipherText, String encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes(UNICODE_FORMAT), "AES");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV.getBytes(UNICODE_FORMAT)));
        return new String(cipher.doFinal(cipherText), UNICODE_FORMAT);
    }
    // implement methods here
    // using AES simple encryption

    public static void main(String[] args){
        String plaintext = "Hello World!";
        String key = "asdfqaqwsaerdqsw";

        Samp s = new Samp();
        String enc = s.encryptString(plaintext, key);
        System.out.println("encrypted string = " + enc);
        String dec = s.decryptString(enc, key);
        System.out.println("decrypted string = " + dec);
    }
}

我已经看到了这个post,它和我的问题一样。我遵循了建议(更改 getBytes() -> getBytes(UNICODE_FORMAT)),但它仍然是一样的。我仍然得到一个异常(javax.crypto.IllegalBlockSizeException:输入长度不是 16 字节的倍数)

【问题讨论】:

  • 如果您使用NoPadding 算法,为什么要在padd 中填充16 个字节
  • 不填充就不行了,所以我决定填充明文就可以了
  • 请注意,用零字符填充是不明确的:在解密时无法判断尾随零是原始字符串的一部分还是填充的一部分。
  • 是的,我也注意到了。你有什么建议@JeffreyHantin
  • PKCS#7 padding 是明确的:填充由 n 个尾随字节组成,所有值 n

标签: java encryption cryptography


【解决方案1】:
  public String encryptString(String plaintext, String encryptionKey)

问题就在这里。字符串不是二进制数据的容器。这个方法应该返回一个字节[]。类似地,decrypt() 方法应该将 byte[] 作为密文参数,而不是 String。

【讨论】:

  • @ScaryWombat 或者对字节进行编码,通过设计方法签名,彻底杜绝问题出现的机会,并完全防止以后通过不知情的修补而再次发生首先是正确的。
【解决方案2】:

您应该使用字符和字节之间一对一映射的编码,例如“ISO-8859-1”。所以把你的代码改成

private static final String UNICODE_FORMAT = "ISO-8859-1";

解决问题。

【讨论】:

  • 不错!!它解决了问题,但如何解决?你能解释一下吗?
  • 使用纯文本来表示加密数据是完全错误的。加密数据可以并且将包含从 0 到 255 的所有字节值,这些值并非都是可打印字符。您必须使用 HEX 或 Base64 编码,而不是简单地将字节数组转换为字符串。
  • @OlegEstekhin 感谢您指出这一点。 OP 无论如何都会这样做,我无意改变他处理加密数据的方式。出于学习或实践的目的,我认为还可以。
  • @krato 你需要一对一的映射编码,所以encString.getBytes(UNICODE_FORMAT) 给你正确的密码
【解决方案3】:

这是我的有效代码

public static String encrypt(String data) throws Exception {

        SecretKeySpec key = generateKey();
        final Cipher c = Cipher.getInstance("AES/EAX/NoPadding", "BC");

        c.init(Cipher.ENCRYPT_MODE, key, ivSpec);

        byte[] encVal = c.doFinal(data.getBytes("UTF8"));       

        String encryptedValue = Hex.toHexString(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {

        Key key = generateKey();
        final Cipher c = Cipher.getInstance("AES/EAX/NoPadding", "BC");

        c.init(Cipher.DECRYPT_MODE, key, ivSpec);
        byte[] ba = Hex.decode(encryptedData);

        byte[] encVal = c.doFinal(ba);  

        return new String (encVal);

    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    相关资源
    最近更新 更多