1

Hello dear people of stackoverflow,

I'm currently developing/implementing security measures within my application and somewhat experiencing issues with encryption and decryption of certain data.

Yesterday in fact i was able to encrypt a message and then decrypt the encrypted message with the very same instance of the class - yet could not do vice versa. That's what I wanted to post today (about the issue) -

After pushing the latest changes from the linux system I've worked and trying to continue working on the windows pc, the following error was thrown:

    java.security.InvalidKeyException: Illegal key size or default parameters
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026)
    at javax.crypto.Cipher.implInit(Cipher.java:801)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1249)
    at javax.crypto.Cipher.init(Cipher.java:1186)
    at com.x.backend.security.Decrypter.encrypt(Decrypter.java:43)
    at crypto.CryptoTest.main(CryptoTest.java:11)
java.lang.NullPointerException
    at javax.crypto.spec.IvParameterSpec.<init>(IvParameterSpec.java:53)
    at com.x.backend.security.Decrypter.decrypt(Decrypter.java:54)
    at crypto.CryptoTest.main(CryptoTest.java:12)

So I tried finding a solution but did not find any, so here's what I tried so far:

  • Updating to JDK 9/10/11 is not an option for me, I tried it, I failed miserably and there'd be too much to adapt if I'd to the move up (it's not worth the effort as of this moment)

  • I've read something about Java Cryptography Extension (JCE), yet that does not apply to me since I am running the JDK version 1.8.66 (and since 1.8.55 it no longer requires any kind of file installed within the java directory)

  • Invalidated cache (IntelliJ) + Restarted my PC

  • Resetted the project state to the initial commit (git hard reset)

My class:

public class Decrypter {

    private static Decrypter instance;

    private Cipher cipher;

    private byte[] IV;

    private SecretKeySpec secretKeySpec;

    private Decrypter() {
        initialize();
    }

    private void initialize() {
        try {
            final byte[] salt = "@1jq3#-o1_uHvaL:".getBytes();
            final String key = "hehexd";
            final int iterationCount = 12;
            final int keyStrength = 256;
            this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            this.secretKeySpec = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(key.toCharArray(), salt, iterationCount, keyStrength)).getEncoded(), "AES");
        } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public final String encrypt(String data) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            IV = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
            return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public final String decrypt(String base64EncryptedData) {
        try {
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV));
            byte[] decryptedData = Base64.getDecoder().decode(base64EncryptedData);
            byte[] utf8 = cipher.doFinal(decryptedData);
            return new String(utf8, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static Decrypter getInstance() {
        return instance == null ? instance = new Decrypter() : instance;
    }
}

My test class:

    public class CryptoTest {

    public static void main(String[] args) {
        String encrypted = Decrypter.getInstance().encrypt("lol");
        String decrypted = Decrypter.getInstance().decrypt(encrypted);
        System.out.println("Verification: PLAINTEXT -> ENCRYPT: " + encrypted);
        System.out.println("Verification: ENCRYPT -> DECRYPT: " + decrypted);
    }
}

Please don't mind any conventional mistake/bad practice, I'm a newcomer when it comes to cryptography (reading my way into it as of this moment)

Any help or input would be appreciated!

Edit:

Thank you for your immediate replies!

Unfortunately I'm having another error thrown. Full output:

    Verification: PLAINTEXT -> ENCRYPT: 
java.security.InvalidKeyException: Illegal key size
Verification: PLAINTEXT -> DECRYPT: 
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
    at javax.crypto.Cipher.implInit(Cipher.java:805)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at com.x.backend.security.Decrypter.encrypt(Decrypter.java:48)
    at crypto.CryptoTest.main(CryptoTest.java:11)
java.security.InvalidKeyException: No installed provider supports this key: javax.crypto.spec.SecretKeySpec
    at javax.crypto.Cipher.chooseProvider(Cipher.java:893)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at com.x.backend.security.Decrypter.decrypt(Decrypter.java:58)
    at crypto.CryptoTest.main(CryptoTest.java:12)

changed code:

 public final String encrypt(String data) {
        try {
            IV = new IvParameterSpec("testtesttesttest".getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, IV);
            return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
Sh0ck
  • 97
  • 2
  • 12

2 Answers2

2

I don't know where you got the information that JDK 1.8.66 ships with unlimited strength JCE. That is not the case outside US.

You still need to download and install unlimited strength JCE JARs from Oracle.

If you're sure you have unlimited strength JCE, try adding to jre/lib/security/java.security:

crypto.policy=unlimited

Only starting from Java SE 8u161 is unlimited strength enabled by default. So this setting isn't needed there.


On a side note - your error handling can be improved. Might be better to replace e.printStackTrace() with throw new RuntimeException(e) to treat all those init errors as fatal errors (they are a deal breaker at that stage).

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • I've tweaked the file, yet nothing changed at all as in error output - also thank you for the hint! - Also, I'll install SE 8u161 now, just to proof-test it – Sh0ck Oct 29 '18 at 19:25
  • Then you need to download the unlimited strength JCE from [Oracle](https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) – rustyx Oct 29 '18 at 19:38
  • https://stackoverflow.com/questions/37741142/how-to-install-unlimited-strength-jce-for-java-8-in-os-x/45055461 - It turns out the mechanism you mentioned was invented from 151 up to 166, and will do! Will the JCE part affect any user as in, would they need to do any similar step? – Sh0ck Oct 29 '18 at 19:39
0

Turns out, an update to the latest JDK fixed all the issues which occured. I can now easily Decrypt and Encrypt stuff independently!

Thanks for everyone who participated in finding a solution!

Sh0ck
  • 97
  • 2
  • 12