user1016765
user1016765

Reputation: 3043

Java Blowfish decrypt not giving original string back

I'm implementing a simple password store using Blowfish. All was fine until I tried out a few different password/key combinations and came across numerous instances where the decrypted values were still garbage.

Below is a standalone class that demonstrates the issue. I get the following output:

'Aaaaaaa7' encrypted: 'r?—èLèdÓ,·Ã¸ÍÒ'*
'Aaaaaaa7' decrypted: 'ñü=€¼(T'*

Any idea what I need to do to guarantee it always decrypts correctly.

(Using jce.jar in JDK 1.6.0_26)

Thanks,

David

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

public class BlowfishTwoWayHashImpl {

    static {
        test();
    }

    public static void test() {
        String key = "wibble";

        String passwordToEnrypt = "Aaaaaaa7";

        String enc = BlowfishTwoWayHashImpl.encryptBlowfish(passwordToEnrypt, key);
        System.out.println("'" + passwordToEnrypt + "' encrypted: '" + enc + "'");

        String dec = BlowfishTwoWayHashImpl.decryptBlowfish(enc, key);
        System.out.println("'" + passwordToEnrypt + "' decrypted: '" + dec + "'");
    }


    private static final String CIPHER_NAME = "Blowfish";

    public static String encryptBlowfish(String toEncrypt, String key) {
        return processString(toEncrypt, key, Cipher.ENCRYPT_MODE);
    }

    public static String decryptBlowfish(String toDecrypt, String key) {
        return processString(toDecrypt, key, Cipher.DECRYPT_MODE);
    }

    private static String processString(String toEncrypt, String key, int encryptDecryptMode) {

        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), CIPHER_NAME);

        Cipher cipher;
        try {
            cipher = Cipher.getInstance(CIPHER_NAME);
            cipher.init(encryptDecryptMode, secretKeySpec);
            return new String(cipher.doFinal(toEncrypt.getBytes()));
        }
        catch (Exception e) {
            throw new RuntimeException(e.toString());
        }
    }

}

Upvotes: 0

Views: 1680

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1499760

Don't do this:

return new String(cipher.doFinal(toEncrypt.getBytes()));

You're using the platform default encoding all over the place in your code. Don't do this. It will lose data.

When you're converting genuine text to bytes (e.g. on encryption) use a specific charset - UTF-8 is a good choice. Use the same charset to decode from "encoded text" to String.

When you're converting arbitrary binary data to text, use base64 encoding, e.g. via this public domain Base64 encoding library.

Basically, when you create a new string with the String(byte[]) or String(byte[], String) constructors, you're saying, "This is genuine text data - please just decode it as a string." When the data is actually the result of encryption, it's not text data... it's an arbitrary bunch of bytes.

Upvotes: 4

Related Questions