junit java.security.NoSuchAlgorithmException: Cannot find any provider supporting

12,353

Solution 1

You need to add the Bouncy Castle provider to the Java runtime. You can see how to install the provider by looking at the Bouncy Castle wiki page. Neither the Blowfish algorithm nor zero padding is supported out of the box by Java installations.

The following runs fine on my box:

Security.addProvider(new BouncyCastleProvider());

byte[] mKeyData = new byte[16];
byte[] mIv = new byte[8];

SecretKeySpec KS = new SecretKeySpec(mKeyData, "Blowfish");

Cipher cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding");
cipher.init(Cipher.ENCRYPT_MODE, KS, new IvParameterSpec(mIv));

Make sure that the provider is also available to the test framework when it is run. You'll need to put the bcprov-jdk15on-[version].jar in the class path of the runtime before you can install the provider.

Solution 2

The problem is with this line:

Cipher cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding");

The algorithm you're requesting is not supported on your system. Any particular reason you want that specific one?

The docs specify the following default implementations:

  • AES/CBC/NoPadding (128)
  • AES/CBC/PKCS5Padding (128)
  • AES/ECB/NoPadding (128)
  • AES/ECB/PKCS5Padding (128)
  • DES/CBC/NoPadding (56)
  • DES/CBC/PKCS5Padding (56)
  • DES/ECB/NoPadding (56)
  • DES/ECB/PKCS5Padding (56)
  • DESede/CBC/NoPadding (168)
  • DESede/CBC/PKCS5Padding (168)
  • DESede/ECB/NoPadding (168)
  • DESede/ECB/PKCS5Padding (168)
  • RSA/ECB/PKCS1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
Share:
12,353
Toon Leijtens
Author by

Toon Leijtens

Updated on June 04, 2022

Comments

  • Toon Leijtens
    Toon Leijtens almost 2 years

    I'm using JUnit 4 [C:\eclipse\plugins\org.junit_4.11.0.v201303080030\junit.jar] in combination with Eclipse (MARS, Version: Mars Milestone 3 (4.5.0M3) Build id: 20141113-0320.

    I have some tests that test a simple class and which work well. But now arrived at the point where I wanted to test my encryption class, which implements the following encrypt function:

    public String encrypt(String data) {
    
        try {
    
            SecretKeySpec KS = new SecretKeySpec(mKeyData, "Blowfish");
    
            Cipher cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding"); // PKCS5Padding
            cipher.init(Cipher.ENCRYPT_MODE, KS, new IvParameterSpec(mIv));
            return bytesToHex(cipher.doFinal(data.getBytes()));       
    
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }
    

    The Crypto class is not sub classed...

    public class Crypto {
    

    So to test this Class and more the encrypt function I have designed the following unit test:

    package my.junit4.example;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class CryptoTest {
    
        @Test
        public void testEncryption() {
    
            Crypto myCrypto = new Crypto();
    
            String encodedString = myCrypto.encrypt("Secret");
    
            assertTrue("The decrypted encrypted word should deliver the original string", encodedString.equals(myCrypto.decrypt(encodedString)));
        }
    }
    

    This test is failing with a stack trace:

    java.security.NoSuchAlgorithmException: Cannot find any provider supporting Blowfish/CBC/ZeroBytePaddingnull
    at javax.crypto.Cipher.getInstance(Cipher.java:535)     at
    my.junit.example.encrypt(Crypto.java:35)    at
    my.junit.example.CryptoTest.testEncrypt(CryptoTest.java:14)     at
    

    This didn't make much sense to me. But being relatively new to JUnit I suspect the issue is with me not understanding how to formulate these tests. The code works well encryption - decryption in my debugger is giving me the desired outcome. But how can I get this to work with JUnit. What obvious mistake I have made?

  • Maarten Bodewes
    Maarten Bodewes over 9 years
    Beware: the zero byte padding of Bouncy Castle is always applied, i.e. 1..8 bytes for Blowfish, this is different than e.g. the zero byte padding performed by mcrypt (in PHP), i.e. 0..7 bytes. You will need to pad yourself if you want to mimic that kind of padding.
  • Toon Leijtens
    Toon Leijtens over 9 years
    Thanks for responding Rick. This is an interesting observation. As you can see I had the comment '// PKCS5Padding'. I have changed this to ZeroBytePadding since that would align my code to the kind of padding I have at the PHP end. From the Blowfish implementation I observed that I could use it. But formally you are right it did not feature in the docs. But now for the one-million-dollar-question (not going to give that as a reward by the way)... how on earth does this work in my Java-Java and Java-PHP and only fail when using JUnit? Any ideas there? anyone?
  • Toon Leijtens
    Toon Leijtens over 9 years
    Hi owlstead, this looks like a useful hint I will look into this BC-prov. It is strange though that only JUnit is giving me a problem. Why do you think only JUnit is not fine with the Blowfish/ZeroBytePadding? and why my Java-Java and Java-PHP are fine? But thank you I will test BCprov anyway, let you know how that improved things.
  • Maarten Bodewes
    Maarten Bodewes over 9 years
    It's not JUnit, it is because either the provider is not installed or missing from the classpath in that particular runtime coniguration. You can always test by requesting the list of providers from the Security class. Check that you are using the correct JRE, I sometimes find out an entirely different JRE is being used.
  • Rick
    Rick over 9 years
    See the answer by @owlsetad. He provides some instructions regarding installing the provider. However, this isn't JUnit related. If you simply create a main method and try using encrypt you will run in to the same problems.