我在Android应用程序中实现了加密/解密。
我添加了一个加密类,它已经成为一个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;
}
}
使用单例示例实现了字符串的加密和解密,它们基本上都能正常工作。
有时,虽然密码已经初始化,但仍然会抛出异常:java.lang.IllegalStateException: Cipher not initialized
场景主要是在某个时间间隔(30分钟)之后执行字符串的解密。
这可能是由于Singleton示例的不正确使用造成的吗?
而不是Singleton类,我尝试加密字符串,使用new运算符创建Encryption类的示例,但问题是我需要相同的对象进行解密,否则会抛出**java.lang.IllegalStateException: Cipher not initialized
**。
欢迎任何建议/提示。
5条答案
按热度按时间wydwbb8l1#
这个问题在多线程环境中必然会出现,就像我遇到的一样。问题是mCipher.init()和mCipher.doFinal()方法之间的冲突。
以下是Cipher类中的相关方法:
查看
initialized
变量在多线程环境中的行为,其中有两个线程执行init()和doFinal()。返回的Exception与未实际初始化的对象无关,而是与initialized
变量设置为false
有关。我通过同步encryptString()和decryptString()方法解决了这个问题。希望你能通过浏览密码得到一些见解。
dw1jzc5e2#
确保在encrypt和decrypt方法中调用了
Cipher.getInstance()
。getInstance()
方法为当前线程获取一个密码示例,以避免竞争条件,例如您刚刚发布的异常。xmq68pz93#
在
decryptstring
方法中,调用在你打电话之前写几行字
由于在调用getOutputSize时密码尚未初始化,因此会出现异常。重新排列这些行应该可以解决这个问题。(对我来说是这样)。
s5a0g9ez4#
我也遇到了同样的问题(
Cipher not initialized
)。我使用的是高加密,对我来说,解决方案是用无限强度版本替换jre/lib/security
中的普通策略jar。sigwle7e5#
如果你用这个方法
那么你必须立即摆脱这个方法:D.相反,您可以在ConvertToEntity和ConvertToColumn方法中重新初始化密码。例如:
我只是想帮你,我也希望你能帮上忙.还有一件事,我使用@sneakyThrows而不是try和catch:D