你好其他程序员,
我按照http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php上的教程将PHP加密的String
发送回我的Android客户端,我想再次解密它。加密/解密部分在我的PHP服务器上像魅力一样运行,我也能够将加密的字符串传递到我的Android客户端,但我无法弄清楚如何在Android中解密字符串......我得到的只是是一些神秘的(哈哈)标志......
问题描述: 我将通过REST Api在Android客户端上生成的IV和加密密钥发送到我的PHP服务器,该服务器处理一些数据库查询并使用给定的IV和加密密钥加密字符串,然后将其返回到Android客户端。 客户端能够读出返回的值并获取加密的字符串,但加密不是等待...
我严格遵循上层教程,但我无法弄清楚问题会是什么......
这是PHP加密的代码:
class MCrypt {
private $iv;
private $key;
private $mode;
function __construct() {
$this->mode = 'cbc';
}
public function setIV($iv) {
$this->iv = $iv;
}
public function setKey($key) {
//$this->key = $this->hex2bin($key);
$this->key = $key;
}
public function getIV() {
return $this->iv;
}
public function getKey() {
return $this->key;
}
public function encrypt($value) {
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', $this->mode, $iv);
mcrypt_generic_init($td, $this->key, $iv);
$encrypted = mcrypt_generic($td, $value);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return bin2hex($encrypted);
}
public function decrypt($value) {
$value = $this->hex2bin($value);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', $this->mode, $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $value);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata) {
$bindata = '';
for($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
以下是我实施它的方式:
$value = "some data I want to read out";
// create new MCrypt object
$mcrypt = new MCrypt();
// set IV to hash
$mcrypt->setIV($data['iv']);
// set key to salt
$mcrypt->setKey($data['key']);
// encrypt the key
$enc = $mcrypt->encrypt($value);
return array("data"=>$enc);
因此,这将返回正确编码的字符串(使用PHP解密函数进行测试,该函数将字符串解码为等待结果)。
这是JAVA实现的样子: import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec;
import android.util.Log;
公共课MCrypt { private static final String TAG = MCrypt.class.getSimpleName();
private String iv;
private String key;
private IvParameterSpec mIvParameterSpec;
private SecretKeySpec mSecretKeySpec;
private Cipher mCipher;
public MCrypt(String iv, String key) {
Log.v(TAG, "IV Bytes.length=" + iv.getBytes().length);
this.iv = cut(iv, 16);
Log.i(TAG, "IV = " + this.iv + ", Bytelength=" + this.iv.getBytes().length);
this.key = key;
mIvParameterSpec = new IvParameterSpec(this.iv.getBytes());
mSecretKeySpec = new SecretKeySpec(this.key.getBytes(), "AES");
try {
mCipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Got Exception while initializing mCipher: " + e.toString(), e);
} catch (NoSuchPaddingException e) {
Log.e(TAG, "Got Exception while initializing mCipher: " + e.toString(), e);
}
}
public String getIV() {
return this.iv;
}
public byte[] decrypt(String code) throws Exception {
if(code == null || code.length() == 0) {
throw new Exception("Emtpy string given");
}
byte[] decrypted = null;
try {
mCipher.init(Cipher.DECRYPT_MODE, mSecretKeySpec, mIvParameterSpec);
decrypted = mCipher.doFinal(hexToBytes(code));
} catch(Exception e) {
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
private byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private String cut(String s, int n) {
byte[] sBytes = s.getBytes();
if(sBytes.length < n) {
n = sBytes.length;
}
int n16 = 0;
boolean extraLong = false;
int i = 0;
while(i < n) {
n16 += (extraLong) ? 2 : 1;
extraLong = false;
if((sBytes[i] & 0x80) == 0) {
i += 1;
}
else if((sBytes[i] & 0xC0) == 0x80) {
i += 2;
}
else if((sBytes[i] & 0xE0) == 0xC0) {
i += 3;
} else {
i += 4;
extraLong = true;
}
}
return s.substring(0, n16);
}
}
如果我现在想要/解密一个字符串(例如“Hello World”),我会得到这个字符串:af8d89fa962794d5b945b74c4b6fd9b6,由PHP实现解码为“Hello World”,但JAVA只是给出了一些有趣的迹象。 ..
我知道这是很多代码,但我对此问题的任何帮助表示感谢!
提前感谢您的耐心和时间阅读主题;)
所以,到目前为止,我得到的是这些'神秘的'符号而不是预期的解密输出实际上是字节数组本身的地址,即使我尝试使用String str = new String(byteArray);
从这个字节数组创建一个新的String我得到一个看起来像[B@44e8c0c8
的输出......这里发生了什么?任何想法??
答案 0 :(得分:1)
所以,经过长时间的研究和(最后)重启我的电脑后,我找到了我想与你分享的问题解决方案:
首先,我将hex2Bin(String str)
函数更改为以下内容:
private byte[] hex2ByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
之后,我仍然一遍又一遍地得到同样的错误,Android只会显示字节数组的地址而不是解密的字符串,所以我咨询了哈利波特,他告诉我魔法能够得到这个排序现在,我希望与您分享......最重要的是......如果您每天使用Eclipse / Motodev Studio超过几个小时,重新启动计算机 - 它将为您节省一些时间和金钱,当然;)
答案 1 :(得分:0)
您遇到此问题可能是因为当您在PHP中调用encrypt
方法时,它使用一个密钥进行加密,但在Java代码中解密加密字符串时,您必须生成密钥这将与PHP密钥的不同,因此您将在解密的字符串中获取这些特殊字符
您可以将对象从PHP传递到Java代码或使用PHP-Java桥接