Расшифровка на Java с помощью Blowfish

Привет,

Я шифрую и дешифруя в Java с помощью Blowfish.

Шифрование работает нормально, но дешифрование не выполняется.

Вот мой код 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 перед тем, как передать его в эту операцию дешифрования.

Ответ 1

Теперь у меня есть решение!

Во-первых, были проблемы с Unicode, поэтому я поместил ISO-8859-1 всюду. Включение в кодировку и декодирование Base64.

Затем я жонглировал вариантами.

Вот мой код Java, который работает для расшифровки Blowfish:

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 должен быть строкой Latin-1 из 8 символов. Это делает ключ из 128 бит. Алгоритм Blowfish позволяет создавать большие ключи, но они не работают на Java из-за ограничения экспорта США в JRE - США допускают шифрование, но не более того, чем NSA может сломаться.

CHARSET_ISO_8859_1 - константа, определенная следующим образом:

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

И Charset - java.nio.charset.Charset.

И последнее, но не менее важное: я поменял свой код Java на шифрование.

Ответ 2

Преобразование байтов в шестнадцатеричные и обратно сложно. Это должно решить вашу проблему. (Вам нужно исправить строковое представление 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();
    }
  }
}

Ответ 3

Ваша длина переменной myKey должна быть кратной 8

Ответ 4

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 для решения этой проблемы.

Ответ 5

Вы должны определенно быть более явным с Cipher, объявив режим и дополнение. Как этот код шифруется? Что на самом деле находится в String encryptedString? Является ли кодировка с шестнадцатеричным кодированием или base64? Если он не закодирован, это определенно может стать источником проблем.

Ответ 6

Попробуйте это

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