αƞjiβ
αƞjiβ

Reputation: 3246

Cipher initialization error when running test

I wrote a utility program to do encryption and decryption using AES algorithm. Regular program works fine but when I run test with same method I am getting Cipher initialization error on doFinal method.

I did some research and some suggest to put init and doFinal in a synchronized block. I did that and still getting same exception.

I also updated US_export_policy.jar and local_policy.jar in jre7/lib/security folder as suggested by some forum. Still getting same issue.

What could be wrong in the code?

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;

public class CipherUtil {
    private static Logger log = Logger.getLogger(CipherUtil.class);
    private static final String SECRET_KEY = "000102030405060708090A0B0C0D0E0F";
    private Cipher cipher;
    private SecretKeySpec secretKeySpec;

    private static CipherUtil cipherUtil;

    private CipherUtil() {
        try {
            cipher = Cipher.getInstance("AES");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
            log.error(ex);
        }
        byte[] key = null;
        try {
            key = Hex.decodeHex(SECRET_KEY.toCharArray());
        } catch (DecoderException ex) {
            log.error(ex);
        }
        secretKeySpec = new SecretKeySpec(key, "AES");
    }

    public static synchronized CipherUtil getCipherUtilObject() {
        if (cipherUtil == null) {
            cipherUtil = new CipherUtil();
        }
        return cipherUtil;
    }

    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public String encrypt(String plainText) {
        if (plainText == null)
            return null;
        String encryptedText = null;
        byte[] encrypted = null;

        synchronized (cipher) {
            try {
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            } catch (InvalidKeyException e) {
                log.error(e.getMessage());
            }
        }

        synchronized (cipher) {
            try {
                encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
                encryptedText = new String(Base64.encodeBase64(encrypted));
            } catch (IllegalBlockSizeException | BadPaddingException
                    | UnsupportedEncodingException e) {
                log.error(e.getMessage());
            }
        }

        return encryptedText;
    }

    public synchronized String decrypt(String encryptedText) {
        if (encryptedText == null)
            return null;
        byte[] toDecrypt = null;
        byte[] original = null;
        String decryptedText = null;

        synchronized (cipher) {
            try {
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            } catch (InvalidKeyException e) {
                log.error(e.getMessage());
            }
        }
        toDecrypt = Base64.decodeBase64(encryptedText);
        synchronized (cipher) {
            try {
                original = cipher.doFinal(toDecrypt);
            } catch (IllegalBlockSizeException | BadPaddingException e) {
                log.error(e.getMessage());
            }
        }
        try {
            decryptedText = new String(original, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }

        return decryptedText;
    }
}

and the test class:

import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

public class CipherTest {
    CipherUtil cipherUtil;

    @Before
    public void setUp() {
        cipherUtil = CipherUtil.getCipherUtilObject();
    }

    @Test
    public void testEncryptDecrypt() {
        String plainText = "Secret Message";
        String encryptedText = cipherUtil.encrypt(plainText);
        assertThat(encryptedText, not(equalTo(plainText)));
        String decryptedText = cipherUtil.decrypt(encryptedText);
        assertThat(decryptedText, is(equalTo(plainText)));
        assertThat(encryptedText, not(equalTo(decryptedText)));
    }
}

and finally this is the exception:

java.lang.IllegalStateException: Cipher not initialized
    at javax.crypto.Cipher.checkCipherState(Cipher.java:1672)
    at javax.crypto.Cipher.doFinal(Cipher.java:2079)
    at com.testapp.util.CipherUtil.encrypt(CipherUtil.java:67)
    at com.testapp.util.CipherTest.testEncryptDecrypt(CipherTest.java:23)

Upvotes: 2

Views: 6451

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93948

The code ran fine on my machine. Note that your encrypt method is not synchronized, so running this in a threaded environment will make it fail. In general you should have one Cipher instance per thread. Cipher contains state between method calls, so just synchronizing access to the method calls themselves will fail from time to time.

Upvotes: 1

Related Questions