2

你好,

我正在使用 Blowfish 在 Java 中进行加密和解密。

加密工作正常,但解密失败。

这是我用于解密的 Java 代码:

String encryptedString = … ;
String decryptedString = null;
SecretKeySpec key = new SecretKeySpec(myKey.getBytes(), "Blowfish");
Cipher cipher;
try {
    cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decrypted = cipher.doFinal(encryptedString.getBytes());
    decryptedString = new String(decrypted, Charset.forName("UTF-8"));
} [ catch Exceptions … ]

我得到一个例外:

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

你能告诉我如何让它简单地工作吗?谢谢你。

我提供的输入来自我的加密 Java 代码,+ Base64 中的编码,我在将其提供给此解密操作之前从 Base64 对其进行解码。

4

8 回答 8

10

将字节转换为十六进制并返回是很棘手的。这应该可以解决您的问题。(您需要修复 encryptedString 的字符串表示形式)

输出:

StackOverflow 537461636B4F766572666C6F77 [83, 116, 97, 99, 107, 79, 118, 101, 114, 102, 108, 111, 119]
J~3¹ÙÂÖ"¢ª„¨u 194A7E33B9060CD9C2D622A2AA84A875 [25, 74, 126, 51, -71, 6, 12, -39, -62, -42, 34, -94, -86, -124, -88, 117]
StackOverflow 537461636B4F766572666C6F77 [83, 116, 97, 99, 107, 79, 118, 101, 114, 102, 108, 111, 119]

代码:

import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Main {

  public static void main(String[] args) throws Exception {

    KeyGenerator keygenerator = KeyGenerator.getInstance("Blowfish");
    SecretKey secretkey = keygenerator.generateKey();

    String plaintextString = "StackOverflow";
    System.out.println(plaintextString + " " + bytesToHex(plaintextString.getBytes()) + " " + Arrays.toString(plaintextString.getBytes()));

    SecretKeySpec key = new SecretKeySpec(secretkey.getEncoded(), "Blowfish");
    Cipher cipher = Cipher.getInstance("Blowfish");

    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] encrypted = cipher.doFinal(plaintextString.getBytes());
    String encryptedString = bytesToHex(encrypted);
    System.out.println(new String(encrypted) + " " + encryptedString + " " + Arrays.toString(encrypted));

    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decrypted = cipher.doFinal(hexToBytes(encryptedString));
    String decryptedString = bytesToHex(decrypted);
    System.out.println(new String(decrypted) + " " + decryptedString + " " + Arrays.toString(decrypted));

  }

  public static byte[] hexToBytes(String str) {
    if (str == null) {
      return null;
    } else if (str.length() < 2) {
      return null;
    } else {
      int len = str.length() / 2;
      byte[] buffer = new byte[len];
      for (int i = 0; i < len; i++) {
        buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
      }
      return buffer;
    }

  }

  public static String bytesToHex(byte[] data) {
    if (data == null) {
      return null;
    } else {
      int len = data.length;
      String str = "";
      for (int i = 0; i < len; i++) {
        if ((data[i] & 0xFF) < 16)
          str = str + "0" + java.lang.Integer.toHexString(data[i] & 0xFF);
        else
          str = str + java.lang.Integer.toHexString(data[i] & 0xFF);
      }
      return str.toUpperCase();
    }
  }
}
于 2013-04-11T13:16:46.830 回答
3

您的 myKey 变量长度必须是 8 的倍数

于 2013-04-11T12:30:06.663 回答
1
String encryptedString = … ;  
String decryptedString = null;
SecretKeySpec key = new SecretKeySpec(myKey.getBytes(), "Blowfish");
private static byte[] linebreak = {}; // Remove Base64 encoder default linebreak
private static Base64 coder;
Cipher cipher;
try {
    coder = new Base64(32, linebreak, true);
    cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decrypted = cipher.doFinal(encryptedString.getBytes());
    decryptedString = new String(coder.encode(decrypted));
} [ catch Exceptions … ]

你可以使用 Base64 类来解决这个问题。

于 2013-04-11T13:56:23.193 回答
1

现在我有了解决方案!

首先,Unicode 存在一些问题,所以我将 ISO-8859-1 放在了各处。包括在Base64编码和解码中。

然后,我处理了变体。

这是我用于 Blowfish 解密的 Java 代码:

String encryptedString = … ;
String decryptedString = null;
SecretKeySpec key = new SecretKeySpec(myKey.getBytes(CHARSET_ISO_8859_1), "Blowfish");
Cipher cipher;
try {
    cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] decrypted = cipher.doFinal(encryptedString.getBytes(CHARSET_ISO_8859_1));
    decryptedString = new String(decrypted, CHARSET_ISO_8859_1);
} [ catch Exceptions … ]

请注意,我已替换"Blowfish""Blowfish/ECB/PKCS5Padding"获取Cipher 实例,但是,如果您对密钥执行相同操作,则会失败。

密钥 myKey必须是 8 个字符的 Latin-1 字符串。这使得密钥为 128 位。Blowfish 算法允许更大的密钥,但由于 JRE 中的美国出口限制,它们在 Java 中失败——美国允许加密,但不比NSA可以破解的更强。

是一个像这样定义的CHARSET_ISO_8859_1常量:

final Charset CHARSET_ISO_8859_1 = Charset.forName("ISO-8859-1");

并且Charsetjava.nio.charset.Charset

最后但同样重要的是,我相应地更改了我的加密 Java 代码。

于 2013-04-11T15:27:19.737 回答
0

尝试这个

private byte[] encrypt(String key, String plainText) throws GeneralSecurityException {

    SecretKey secret_key = new SecretKeySpec(key.getBytes(), ALGORITM);

    Cipher cipher = Cipher.getInstance(ALGORITM);
    cipher.init(Cipher.ENCRYPT_MODE, secret_key);

    return cipher.doFinal(plainText.getBytes());
}

在这里你可以找到整个班级 enc/dec --- http://dexxtr.com/post/57145943236/blowfish-encrypt-and-decrypt-in-java-android

于 2013-08-02T12:20:50.087 回答
0

Cipher通过声明模式和填充,您绝对应该更加明确。这段代码是如何加密的?里面到底有什么String encryptedString?它是十六进制编码还是base64编码?如果它没有被编码,那肯定是麻烦的根源。

于 2013-04-11T13:25:22.207 回答
0

try { /** * 初始化用于解密的密码 / cipher.init(Cipher.DECRYPT_MODE, secretKey); / * * 初始化输入输出流 */ inStream = new FileInputStream(encryptedFile); outStream = new FileOutputStream(decryptedFile); 字节[]缓冲区=新字节[1024];国际化; while ((len = inStream.read(buffer)) > 0) { outStream.write(cipher.update(buffer, 0, len)); outStream.flush(); } outStream.write(cipher.doFinal()); inStream.close(); outStream.close(); }

于 2021-07-29T09:17:22.157 回答
0
    try {
        /**
         * Initialize the cipher for decryption
         */
     cipher.init(Cipher.DECRYPT_MODE, secretKey);
        /**
         * Initialize input and output streams
         */
        inStream = new FileInputStream(encryptedFile);
        outStream = new FileOutputStream(decryptedFile);
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) > 0) {
            outStream.write(cipher.update(buffer, 0, len));
            outStream.flush();
        }
        outStream.write(cipher.doFinal());
        inStream.close();
        outStream.close();
    }

...

  1. 项目清单
于 2021-07-29T09:30:56.523 回答