我能够加密短信并将其从一个模拟器(Android 2.2)发送到另一个模拟器。 在接收端,我能够成功解密。但问题是如果在一个操作系统版本(即Android 2.2)中进行加密并尝试在另一个操作系统版本(Android 2.3)中进行解密,我会收到'糟糕的填充异常'。我检查过我在两端使用了相同的密钥。 代码如下所示
public class ED {
private String Key;
public ED() {
Key = "abc12"; // Assigning default key.
}
public ED(String key) {
// TODO Auto-generated constructor stub
Key = key;
}
public String encrypt(String toEncrypt) throws Exception {
byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
byte[] result = encrypt(rawKey, toEncrypt.getBytes("UTF-8"));
return toHex(result);
}
public byte[] encrypt(byte[] key, byte[] toEncodeString) throws Exception {
SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
byte[] encrypted = cipher.doFinal(toEncodeString);
return encrypted;
}
private byte[] getRawKey(byte[] key) throws Exception {
KeyGenerator kGen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(key);
kGen.init(128, sr);
SecretKey sKey = kGen.generateKey();
byte[] raw = sKey.getEncoded();
return raw;
}
/************************************* Decription *********************************************/
public String decrypt(String encryptedString) throws Exception {
byte[] rawKey = getRawKey(Key.getBytes("UTF-8"));
System.out.println("Decrypted Key in bytes : "+rawKey);
System.out.println("Key in decryption :"+rawKey);
SecretKeySpec sKeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
byte[] decrypted = cipher.doFinal(toByte(encryptedString));
System.out.println("Decrypted mess in bytes---------->" +decrypted);
return new String(decrypted);
}
public 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 String HEX = "0123456789ABCDEF";
private void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
public 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;
}
}
我正在使用sendTextMessage()函数发送短信。我读到加密/解密不依赖于操作系统,但在这种情况下并非如此。在配置密码时(在AES中),我是否遗漏了任何重要的内容?请告诉我。
答案 0 :(得分:1)
这是setSeed()。它没有做你认为它做的事情:它只是将给定种子的熵添加到底层算法。您可能会发现它在两个平台上都返回了不同的东西。 SHA1PRNG 是伪随机函数,但如果它已经播种,则可能会返回不同的结果。
答案 1 :(得分:0)
如果问题出在密钥长度上,您可以从密码中派生一个密钥,而不是直接使用密码。您可以使用哈希(如SHA-1,MD5等)并将其裁剪为正确的大小(128,192或256位),或使用PBEKeySpec
代替SecretKeySpec
。
用于消除密钥长度的问题。如果填充问题出在明文中,我建议您使用CipherInputStream
和CipherOutputStream
,它们比Cipher.doFinal
使用的程序员更友好。
答案 2 :(得分:0)
问题在于SecureRandom的生成。它在不同的平台上提供不同的结果。这是因为engineNextBytes()方法中的SHA1PRNG_SecureRandomImpl.java第320行(在Gingerbread源代码中)修复了错误
bits = seedLength << 3 + 64;
已更改为
bits = (seedLength << 3) + 64;
使用SecretKeyFactory()生成安全密钥而不是安全随机。
public class Crypto {
Cipher ecipher;
Cipher dcipher;
byte[] salt = { 1, 2, 4, 5, 7, 8, 3, 6 };
int iterationCount = 1979;
Crypto(String passPhase) {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC").generateSecret(keySpec);
ecipher = Cipher.getInstance(key.getAlgorithm());
dcipher = Cipher.getInstance(key.getAlgorithm());
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
// TODO: handle exception
//Toast.makeText(this, "I cought ", Toast.LENGTH_LONG).show();
}
}
public String encrypt(String str) {
String rVal;
try {
byte[] utf8 = str.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
rVal = toHex(enc);
} catch (Exception e) {
// TODO: handle exception
rVal = "Exception Caught "+e.getMessage();
}
return rVal;
}
public String decrypt(String str) {
String rVal;
try {
byte[] dec = toByte(str);
byte[] utf8 = dcipher.doFinal(dec);
rVal = new String(utf8, "UTF8");
} catch(Exception e) {
rVal = "Error in decrypting :"+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));
}
}
答案 3 :(得分:0)
请勿依赖KeyGenerator
生成相同的密钥,因为您以相同的方式播种RNG。如果您预先共享密钥,请共享密钥,而不是种子。
您还应该完全指定加密转换:“AES / ECB / PKCS5Padding”
最后,ECB模式对于一般用途并不安全。
有关使用JCE正确执行加密的示例,请参阅another answer of mine。