How to fix the NoSuchAlgorithmException in Java when using Blowfish?

Tamer picture Tamer · Apr 23, 2011 · Viewed 13.6k times · Source

So I'm writing a program to encrypt and decrypt text files but I seem to be always getting this error when I use an encrypthion other than "Blowfish" (e.g. "Blowfish/CBC/PKCS5Padding"). The excepthiong I get is:

Exception in thread "main" java.security.NoSuchAlgorithmException: Blowfish/CBC/PKCS5Padding KeyGenerator not available
    at javax.crypto.KeyGenerator.<init>(DashoA13*..)
    at javax.crypto.KeyGenerator.getInstance(DashoA13*..)
    at Encryptor.<init>(Encryptor.java:87)
    at Encryptor.main(Encryptor.java:30)

A portion of my code:

import java.security.MessageDigest;
import java.security.SecureRandom;

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

public class Encryptor2 {
    private IvParameterSpec ivSpec;
    private SecretKeySpec keySpec;
    private Cipher cipher;

    public static void main(String[] args) throws Exception {
        Encryptor2 e = new Encryptor2(
                "averylongtext!@$@#$#@$#*&(*&}{23432432432dsfsdf");
        String enc = e.encrypt("john doe");
        String dec = e.decrypt(enc);
    }

    public Encryptor2(String pass) throws Exception {
        // setup AES cipher in CBC mode with PKCS #5 padding
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // setup an IV (initialization vector) that should be
        // randomly generated for each input that's encrypted
        byte[] iv = new byte[cipher.getBlockSize()];
        new SecureRandom().nextBytes(iv);
        ivSpec = new IvParameterSpec(iv);

        // hash keyString with SHA-256 and crop the output to 128-bit for key
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(pass.getBytes());
        byte[] key = new byte[16];
        System.arraycopy(digest.digest(), 0, key, 0, key.length);
        keySpec = new SecretKeySpec(key, "AES");
    }

    public String encrypt(String original) throws Exception {
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(original.getBytes("UTF-8"));
        System.out.println("encrypted: `" + new String(encrypted) + "`");
        return new String(encrypted);
    }

    public String decrypt(String encrypted) throws Exception {
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] decrypted = cipher.doFinal(encrypted.getBytes("UTF-8"));
        System.out.println("decrypted: `" + new String(decrypted, "UTF-8")
                + "`");
        return new String(decrypted, "UTF-8");
    }
}

But now it fails with Input length must be multiple of 16 when decrypting with padded cipher

Answer

WhiteFang34 picture WhiteFang34 · Apr 23, 2011

The additional parameters that you're specifying with the algorithm are meant for Cipher. For KeyGenerator and SecretKeySpec you only specify the algorithm. The other parameters are for the cipher mode of operation and padding to be used. For example, if you're using Blowfish in CBC mode with PKCS #5 padding you want:

KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding");

See Encrypting and Decrypting Using Java: Unable to get same output for an example. It uses the same mode and padding as you have. The only difference is that uses AES instead of Blowfish, however it works exactly the same.