javax.crypto在不同版本的Android操作系统中工作方式不同?
我正在使用此代码段加密/解密我的应用程序数据库中的数据: 看起来javax.crypto.KeyGenerator.generateKey()操作在Android 2.3.3操作系统中的工作方式与其他(以前的?)版本不同。当然,当我的用户将他们的设备从2.2升级到2.3.3,并且应用程序开始在解密数据库时抛出错误时,这对他们来说是一个大问题 这是一个已知的问题吗?我是否错误地使用了加密库?有没有人对如何解决这个问题有什么建议,以便在2.2中加密的数据能够在2.3.3中解密 我构建了一个测试应用程序,它通过encrypt函数提供值。当我在2.2 AVD上运行它时,我得到一个结果。当我在2.3.3 AVD上运行它时,会得到不同的结果javax.crypto在不同版本的Android操作系统中工作方式不同?,java,android,encryption,javax.crypto,Java,Android,Encryption,Javax.crypto,我正在使用此代码段加密/解密我的应用程序数据库中的数据: 看起来javax.crypto.KeyGenerator.generateKey()操作在Android 2.3.3操作系统中的工作方式与其他(以前的?)版本不同。当然,当我的用户将他们的设备从2.2升级到2.3.3,并且应用程序开始在解密数据库时抛出错误时,这对他们来说是一个大问题 这是一个已知的问题吗?我是否错误地使用了加密库?有没有人对如何解决这个问题有什么建议,以便在2.2中加密的数据能够在2.3.3中解密 我构建了一个测试应用
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class main extends Activity {
TextView tvOutput;
static String out;
String TEST_STRING = "abcdefghijklmnopqrstuvwxyz";
String PASSKEY = "ThePasswordIsPassord";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvOutput = (TextView) findViewById(R.id.tvOutput);
}
@Override
public void onResume() {
super.onResume();
out = "";
runTest();
tvOutput.setText(out);
}
private void runTest() {
out = "Test string: " + TEST_STRING + "\n";
out += "Passkey: " + PASSKEY + "\n";
try {
out += "Encrypted: " + encrypt(PASSKEY, TEST_STRING) + "\n";
} catch (Exception e) {
out += "Error: " + e.getMessage() + "\n";
e.printStackTrace();
}
}
public static String encrypt(String seed, String cleartext)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result) + "\n" + "Raw Key: " + String.valueOf(rawKey)
+ "\n";
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}
导入java.security.SecureRandom;
导入javax.crypto.Cipher;
导入javax.crypto.KeyGenerator;
导入javax.crypto.SecretKey;
导入javax.crypto.spec.SecretKeySpec;
导入android.app.Activity;
导入android.os.Bundle;
导入android.widget.TextView;
公共类主要扩展活动{
文本视图输出;
静态串出;
字符串测试_String=“abcdefghijklmnopqrstuvwxyz”;
字符串PASSKEY=“ThePasswordIsPassord”;
/**在首次创建活动时调用*/
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvOutput=(TextView)findViewById(R.id.tvOutput);
}
@凌驾
恢复时公开作废(){
super.onResume();
out=“”;
runTest();
tvOutput.setText(输出);
}
私有void runTest(){
out=“测试字符串:“+Test\u字符串+”\n”;
out+=“Passkey:”+Passkey+“\n”;
试一试{
out+=“加密:”+加密(密钥,测试字符串)+“\n”;
}捕获(例外e){
out+=“错误:”+e.getMessage()+“\n”;
e、 printStackTrace();
}
}
公共静态字符串加密(字符串种子、字符串明文)
抛出异常{
byte[]rawKey=getRawKey(seed.getBytes());
byte[]result=encrypt(rawKey,cleartext.getBytes());
返回到十六进制(结果)+“\n”+”原始键:“+String.valueOf(原始键)
+“\n”;
}
私有静态字节[]getRawKey(字节[]种子)引发异常{
KeyGenerator kgen=KeyGenerator.getInstance(“AES”);
SecureRandom sr=SecureRandom.getInstance(“SHA1PRNG”);
高级种子(种子);
kgen.init(128,sr);//192和256位可能不可用
SecretKey skey=kgen.generateKey();
字节[]原始=skey.getEncoded();
返回原材料;
}
私有静态字节[]加密(字节[]原始,字节[]清除)引发异常{
SecretKeySpec skeySpec=新SecretKeySpec(原始,“AES”);
Cipher Cipher=Cipher.getInstance(“AES”);
cipher.init(cipher.ENCRYPT_模式,skeySpec);
字节[]加密=cipher.doFinal(清除);
返回加密;
}
公共静态字符串toHex(字符串txt){
返回到hex(txt.getBytes());
}
公共静态字符串fromHex(字符串十六进制){
返回新字符串(toByte(hex));
}
公共静态字节[]toByte(字符串hexString){
int len=hexString.length()/2;
字节[]结果=新字节[len];
对于(int i=0;i>4)和0x0f)).append(十六进制字符(b和0x0f));
}
}
我的main.xml布局如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:id="@+id/tvOutput" />
</LinearLayout>
我不能发布链接或图片,因为我是一个新用户,但如果您想看到结果,可以破译以下两个图片的URL:
我从2.2中得到了什么:
..和第2.3.3节:
答案就在这个问题上:你误用了伪随机数生成器,它的种子是一个键求导函数——这真的是一种非常糟糕的风格。伪随机数生成器“SHA1PRNG”不像AES那样是一个标准,因此您永远不知道您得到的是什么实现。 看到了吗 难怪你会得到不同的结果。基于给定种子获得确定性结果并不是伪随机数函数的特性 如果您想从密码派生加密密钥,请使用类似PKCS#5/PBKDF2的密码。
Bouncy Castle中包含了PBKDF2的一个实现。我要感谢所有对此问题做出贡献的人 下面是我最终提出的一个如何使用密码进行加密/解密的示例,这在Android 2.2和2.3.3之间似乎是一致的 主要活动:
package cc.ndl.testencryption;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class main extends Activity {
TextView tvOutput;
static String out;
String TEST_STRING = "abcdefghijklmnopqrstuvwxyz";
static String PASSKEY = "ThePasswordIsPassord";
static byte[] SALT = { 1, 2, 4, 5 };
static int ITERATIONS = 1979;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvOutput = (TextView) findViewById(R.id.tvOutput);
}
@Override
public void onResume() {
super.onResume();
out = "";
runTest();
tvOutput.setText(out);
}
private void runTest() {
out = "Test string: " + TEST_STRING + "\n";
out += "Passkey: " + PASSKEY + "\n";
try {
Crypto crypto = new Crypto(PASSKEY);
String encryptedData = crypto.encrypt(TEST_STRING);
out += "Encrypted: " + encryptedData + "\n";
out += "Decrypted: " + crypto.decrypt(encryptedData);
} catch (Exception e) {
out += "Error: " + e.getMessage() + "\n";
e.printStackTrace();
}
}
}
主要布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:id="@+id/tvOutput" />
</LinearLayout>
加密对象:
package cc.ndl.testencryption;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class Crypto {
Cipher ecipher;
Cipher dcipher;
// 8-byte Salt
byte[] salt = { 1, 2, 4, 5, 7, 8, 3, 6 };
// Iteration count
int iterationCount = 1979;
Crypto(String passPhrase) {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt,
iterationCount);
SecretKey key = SecretKeyFactory.getInstance(
"PBEWITHSHA256AND128BITAES-CBC-BC").generateSecret(keySpec);
ecipher = Cipher.getInstance(key.getAlgorithm());
dcipher = Cipher.getInstance(key.getAlgorithm());
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt,
iterationCount);
// Create the ciphers
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
}
}
public String encrypt(String str) {
String rVal;
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
rVal = toHex(enc);
} catch (Exception e) {
rVal = "Error encrypting: " + e.getMessage();
}
return rVal;
}
public String decrypt(String str) {
String rVal;
try {
// Decode base64 to get bytes
byte[] dec = toByte(str);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
rVal = new String(utf8, "UTF8");
} catch (Exception e) {
rVal = "Error encrypting: " + e.getMessage();
}
return rVal;
}
private static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
}
private static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}
包cc.ndl.testencryption;
导入java.security.spec.AlgorithmParameterSpec;
导入java.security.spec.KeySpec;
导入javax.crypto.Cipher;
导入javax.crypto.SecretKey;
导入javax.crypto.SecretKeyFactory;
导入javax.crypto.spec.PBEKeySpec;
导入javax.crypto.sp