Frage

Hullo,

I am encrypting and decrypting in Java with Blowfish.

The encryption works fine, but the decryption fails.

Here is my Java code for decrypting :

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 … ]

I get an exception :

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

Can you tell me how to make this simply work ? Thank you.

The input I give comes from my encryption Java code, + encoding in Base64, and I decode it from Base64 just before giving it to this decrypting operation.

War es hilfreich?

Lösung 4

Now I have the solution !

First, there were some problems with Unicode, so I have put ISO-8859-1 everywhere. Including in the Base64 encoding and decoding.

Then, I have juggled with the variants.

Here is my Java code which works for Blowfish decryption :

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 … ]

Note that I have replaced "Blowfish" with "Blowfish/ECB/PKCS5Padding" for getting the Cipher instance, but, if you do the same for the key, it fails.

The key myKey has to be a Latin-1 string of 8 characters. This makes a key of 128 bits. The Blowfish algorithm allows bigger keys, but they fail in Java because of the USA export restriction in the JRE — the USA allow encryption but not stronger than what the NSA can break.

The CHARSET_ISO_8859_1 is a constant defined like this :

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

And Charset is java.nio.charset.Charset.

Last but not least, I have changed my encryption Java code accordingly.

Andere Tipps

Converting bytes to hex and back is tricky. This should solve your problem. (You need to fix your string representation of encryptedString)

Output:

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]

Code:

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();
    }
  }
}

Your myKey variable lenght must be multiple of 8

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 … ]

You can use Base64 class to solve this problem.

You should definitely be more explicit with the Cipher by declaring the mode and padding. How is this code getting encrypted? What is actually in the String encryptedString? Is it hex encoded or base64 encoded? If it isn't encoded that could definitely be a source of trouble.

Try this

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());
}

here you can find whole class with enc/dec --- http://dexxtr.com/post/57145943236/blowfish-encrypt-and-decrypt-in-java-android

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(); }

    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. List item
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top