【问题标题】:How to correctly decrypt a javax.crypto encrypted string如何正确解密 javax.crypto 加密字符串
【发布时间】:2016-03-26 16:45:21
【问题描述】:

我在尝试解密时收到以下错误:

javax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是 16 的倍数

这是我实现的加密类:

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class StringEncrypter {

    public static String encrypt(String key, String string, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
        Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        byte[] encrypted = cipher.doFinal(string.getBytes());
        return encrypted.toString();
    }

    public static String decrypt(String key, String encryptedString, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
        Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, aesKey);
        String decrypted = new String(cipher.doFinal(encryptedString.getBytes()));
        return decrypted;
    }
}

这就是我加密字符串的方式:

StringEncrypter.encrypt("0306868080306868", "ddd", "AES"); // [B@e19957c

当我尝试像这样解密上面的加密字符串时:

String decrypted = StringEncrypter.decrypt("0306868080306868", "[B@e19957c", "AES");

我收到了illegalBlockSizeException

我在上面做错了什么?如何正确解密加密字符串?

【问题讨论】:

  • 请注意,您似乎正在使用 ECB 加密,这是不安全的。您的代码中至少缺少一个(随机)IV。
  • @ArtjomB。它解释了如何生成输出,但用new String(byte[]) 替换它会例如不能解决问题。
  • @MaartenBodewes 你是对的,但是将其编码为十六进制会
  • 是的,首选:只是二进制,用于调试和显示键/IV 的:十六进制,以及更大尺寸数组的二进制编码:base64。压缩率成为真正问题时的专业基础。 Java 还没有十六进制,因此 base 64 成为首选格式。

标签: java encryption cryptography


【解决方案1】:

您需要对您的密钥和密文执行 base 64 编码解码。在 Java 8 中有一个新的 Base64 类。不能只在字符串中存储任何字节,并非所有字节都表示可打印甚至是有效字符,并且密码的输出与随机无法区分。

除此之外,字节数组“类”(在Java中用[B表示)没有实现toString方法,这意味着你只需要打印出Object.toString,即类名@987654327 @ 和对象实例的人类可读标识符而不是实际密文。

【讨论】:

  • 为什么需要进行base 64编码和解码?还有一个 1.7 版本 - 不幸的是我不能使用 Java 8。
  • 充气城堡和 Apache Commons Codec 库运动 Base64 类。您需要执行 base64 编码(实际上是解码),因为不是每个二进制字符串都可以用没有编码的文本字符串表示。当然,如果您实际上不需要文本字符串表示,您也可以将密文/密钥保留为字节数组。
  • “如 Oracle JDK 支持路线图中所述,2015 年 4 月之后,Oracle 将不会在其公共下载站点上发布 Java SE 7 的进一步更新。需要继续访问关键错误修复和安全修复的客户以及 Java SE 7 或更早版本的一般维护可以通过 Oracle Java SE Support 获得长期支持。” ...所以您正在 Java 7 中创建一个与安全相关的应用程序。您确定您知道自己在做什么吗?
  • 更多关于使用字符串的信息here
  • DatatypeConverter 包含 base64 编码和解码方法,至少从 Java 1.6 开始就可以使用
【解决方案2】:

您不能将字节(二进制)用作字符串。不等价

你应该转换它。几种方式。例如 Base64 或 Hexa 你 使用 base64,它给出了这个:

import javax.xml.bind.DatatypeConverter ;

byte[] bt= ... // what you get

// Conversion B64
String encodedb64=DatatypeConverter.printBase64Binary(bt);

// CONVERSION base 64 => byte 
// base 64 => byte
byte [] byteArrayreverse=DatatypeConverter.parseBase64Binary(encodedb64);

【讨论】:

    猜你喜欢
    • 2011-07-02
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 2012-07-01
    • 2018-08-26
    • 1970-01-01
    相关资源
    最近更新 更多