KJ21
KJ21

Reputation: 83

Exception in thread java.lang.IllegalStateException: Cipher not initialized

At runtime, getting java.lang.IllegalStateException with Cipher not initialized message while decypting ciphertext my code is as below:

public String decrypt(String cipherText) throws SecurityException {
        String clearText = null;
        try {
            cipher = Cipher.getInstance("AES/OFB/NoPadding");
            byte[] cipherTextBytes = Base64.decodeBase64(cipherText.getBytes());
            byte[] iv = ArrayUtils.subarray(cipherTextBytes, 0, INIT_VECTOR_LENGTH);
            cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
            byte[] decryptedBytes = cipher
                    .doFinal(ArrayUtils.subarray(cipherTextBytes, INIT_VECTOR_LENGTH, cipherTextBytes.length));
            clearText = new String(decryptedBytes, CHARACTER_ENCODING).trim();
        } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException
                | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
            throw new SecurityException(e);
        }
        return clearText;
    }

Exception in thread "pool-5-thread-3" java.lang.IllegalStateException: Cipher not initialized at javax.crypto.Cipher.checkCipherState(Cipher.java:1749) at javax.crypto.Cipher.doFinal(Cipher.java:2156)

and this is intermittent issue, after some time it decrypts ciphetext and works as expected.

Upvotes: 1

Views: 2308

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93958

Cipher instances are a stateful and inherently not thread safe. You should not share them between threads at all. And there is no need either, as they are relatively lightweight objects; making them thread safe would probably slow down the application more than simply recreating the object instance. It is much better to put the key into a field and share that if you need key reuse. Then simply call getInstance("AES/OFB/NoPadding") and assign the Cipher instance to a local variable.

Side note: the code seems to contain two issues: cipher is a field (first issue), but as it is initialized each time within decrypt (second issue). That means that the the init call may actually replace the object instance for CipherSpi or Security.Service (i.e. the implementation of the cipher) from within another thread, leading to the error you are getting now.

As always with multi-threading, it may well be that you don't get an error in specific circumstances: the program is however erroneous and may crash later on.

Upvotes: 9

Related Questions