Reputation: 3246
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
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