2012-04-27 397 views
4

我在Android应用程序中实现了加密/解密。java.lang.IllegalStateException:密码未初始化

我已经添加了一个加密类,它已经成为一个Singleton类。

部分的代码如下:

public class Encryption { 

     private SecretKeySpec mKey = null; 
     private Cipher mCipher = null; 
     private byte[] mKeyBytes = null; 
     private AlgorithmParameterSpec mParamSpec = null; 
     private static Encryption sInstance; 

     public Encryption() { 
      byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 
      mParamSpec = new IvParameterSpec(iv); 
      mKeyBytes = getMD5(MD5_KEY.getBytes(); 
      mKey = new SecretKeySpec(mKeyBytes, AES_TAG); 
      try { 
       mCipher = Cipher.getInstance(TRANSFORMATION_STR); 
      } catch (NoSuchAlgorithmException e) { 
      } catch (NoSuchPaddingException e) { 
      } 
     } 

     public static synchronized Encryption getInstance() { 
      if (sInstance == null) { 
       sInstance = new Encryption(); 
      } 
      return sInstance; 
     } 

     public String encryptString(String strPwd) { 
      String strToEncripted = null; 
      strToEncripted = strPwd; 
      String result = null; 
      byte[] input = null; 
      byte[] cipherText = null; 
      int ctLength = 0; 
      try { 
       input = strToEncripted.getBytes(UTF8_STR); 
       mCipher.init(Cipher.ENCRYPT_MODE, mKey, mParamSpec); 
       cipherText = new byte[mCipher.getOutputSize(input.length)]; 
       ctLength = mCipher.update(input, 0, input.length, cipherText, 0); 
       ctLength += mCipher.doFinal(cipherText, ctLength); 
       result = Base64.encodeToString(cipherText, Base64.DEFAULT) 
         .replace(NEWLINE_CHAR, EMPTY_CHAR).trim(); 
      } catch (InvalidKeyException e) { 
      } catch (UnsupportedEncodingException e) { 
      } catch (InvalidAlgorithmParameterException e) { 
      } catch (ShortBufferException e) { 
      } catch (IllegalBlockSizeException e) { 
      } catch (BadPaddingException e) { 
      } catch (IllegalStateException e) { 
      } 
      return result; 
     } 

     public String decryptstring(byte[] encripted) { 
      String textDecrypt = ""; 
      byte[] encriptedByteDecode64 = Base64.decode(encripted, Base64.DEFAULT); 
      byte[] plainText = new byte[mCipher.getOutputSize(encriptedByteDecode64.length)]; 
      int ptLength = 0; 
      try { 
       mCipher.init(Cipher.DECRYPT_MODE, mKey, mParamSpec); 
       ptLength = mCipher.update(encriptedByteDecode64, 0, encriptedByteDecode64.length, plainText, 0); 
       ptLength += mCipher.doFinal(plainText, ptLength); 
       textDecrypt = (new String(plainText)).trim(); 
      } catch (InvalidKeyException e) { 
      } catch (InvalidAlgorithmParameterException e) { 
      } catch (ShortBufferException e) { 
      } catch (IllegalBlockSizeException e) { 
      } catch (BadPaddingException e) { 
      } 
      return textDecrypt; 
     } 


     private String getMD5(String strKey) { 
      String key = strKey; 
      String result = null; 
      try { 
       MessageDigest algorithm = MessageDigest.getInstance(MD5_TAG); 
       algorithm.reset(); 
       algorithm.update(key.getBytes(UTF8_STR)); 
       byte messageDigest[] = algorithm.digest(); 
       StringBuilder hexString = new StringBuilder(); 
       for (int count = 0; count < messageDigest.length; count++) { 
        String hexaDecimal = Integer.toHexString(0xFF & messageDigest[count]); 
        while (hexaDecimal.length() < 2) 
         hexaDecimal = new StringBuilder(ZERO_STR).append(hexaDecimal).toString(); 
        hexString.append(hexaDecimal); 
       } 
       result = hexString.toString(); 
      } catch (NoSuchAlgorithmException e) { 
      } catch (UnsupportedEncodingException e) { 
      } 
      return result; 
     } 
    } 

使用Singleton实例,加密解密&字符串的实现&他们的工作居多。

有时候,虽然密码已经初始化,仍为其抛出一个异常:java.lang.IllegalStateException: Cipher not initialized

的情况主要是当一些时间间隔(30分钟)后,进行字符串的解密。

它可能是由于Singleton实例的不正确使用造成的吗?

相反Singleton类的,我曾试图加密字符串使用new运算符创建加密类的实例,但问题是我需要解密的同一个对象,否则java.lang.IllegalStateException: Cipher not initialized被抛出。

欢迎任何建议/提示。

+0

你使用它像'Encryption.getInstance()。encryptString(“123”);'?从多个线程或从1? – zapl 2012-04-27 19:13:15

+0

它来自一个线程 – chiranjib 2012-04-28 06:26:06

+0

你是否设法解决这个问题?我也经历了同样的问题 - 持续使用几分钟后IllegalStateExceptions。我甚至在每次使用之前调用init()(由于不断变化的IV)。如果您设法发现问题,请使用解决方案回答您自己的问题。 :) – Tustin2121 2012-08-01 15:43:10

回答

6

这个问题一定会发生在多线程环境中,就像它发生在我身上一样。问题是mCipher.init()和mCipher.doFinal()方法之间的冲突。

以下是在Cipher类相关的方法:

public final void init(int opmode, Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException 
{ 
    init(opmode, key, params, JceSecurity.RANDOM); 
} 


public final void init(int opmode, Key key, AlgorithmParameterSpec params, 
         SecureRandom random) 
     throws InvalidKeyException, InvalidAlgorithmParameterException 
{ 
    initialized = false; 
    checkOpmode(opmode); 

    if (spi != null) { 
     checkCryptoPerm(spi, key, params); 
     spi.engineInit(opmode, key, params, random); 
    } else { 
     chooseProvider(I_PARAMSPEC, opmode, key, params, null, random); 
    } 

    initialized = true; 
    this.opmode = opmode; 
} 


public final int doFinal(byte[] output, int outputOffset) 
     throws IllegalBlockSizeException, ShortBufferException, 
      BadPaddingException { 
    checkCipherState(); 

    // Input sanity check 
    if ((output == null) || (outputOffset < 0)) { 
     throw new IllegalArgumentException("Bad arguments"); 
    } 

    chooseFirstProvider(); 
    return spi.engineDoFinal(null, 0, 0, output, outputOffset); 
} 


private void checkCipherState() { 
    if (!(this instanceof NullCipher)) { 
     if (!initialized) { 
      throw new IllegalStateException("Cipher not initialized"); 
     } 
     if ((opmode != Cipher.ENCRYPT_MODE) && 
      (opmode != Cipher.DECRYPT_MODE)) { 
      throw new IllegalStateException("Cipher not initialized " + 
              "for encryption/decryption"); 
     } 
    } 
} 

参见initialized变量的行为在多线程环境中的两个线程中执行init()和doFinal()。返回的异常与未实际初始化的对象无关,但initialized变量设置为false

我通过同步我的encryptString()和decryptString()方法解决了我的问题。希望您可以通过密码代码获得一些见解。

1

我有同样的问题(Cipher not initialized)。我使用的是高度加密,对我而言,解决方案是用无限强度版本替换jre/lib/security中的常规策略罐。

0

在你decryptstring方法,你叫

byte[] plainText = new byte[mCipher.getOutputSize(encriptedByteDecode64.length)]; 

几行,你叫

mCipher.init(Cipher.DECRYPT_MODE, mKey, mParamSpec); 

之前由于密码尚未初始化当你调用getOutputSize它,你得到的异常。重新排序这些行应该修复它。 (它为我做。)