【发布时间】:2012-04-04 20:05:48
【问题描述】:
各位程序员,你好,
我按照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 实现的样子: 导入 java.security.NoSuchAlgorithmException; 导入 javax.crypto.Cipher; 导入 javax.crypto.NoSuchPaddingException; 导入 javax.crypto.SecretKey; 导入 javax.crypto.spec.IvParameterSpec; 导入 javax.crypto.spec.SecretKeySpec;
导入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);从这个字节数组创建一个新字符串我得到一个看起来像[B@44e8c0c8的输出......这是怎么回事?有什么想法吗??
【问题讨论】:
-
您有什么理由不只是使用 SSL 进行数据传输?
-
实际上,我只是想确保我返回的字符串不是以明文形式提交的,因为它是一些感官数据;)
-
SSL 并不是一个真正的选择,因为客户也没有要求它,并且它说我应该加密/解密服务器和客户端之间的字符串......
-
“据说我应该加密/解密服务器和客户端之间的字符串”——什么?!那没有意义。您是否想说“客户端应该加密发送给服务器的消息,服务器应该解密来自客户端的消息,反之亦然,但是当消息在两者之间时,第三方应该无法拦截它并且解密”?因为这就是 SSL 所做的。如果客户端不请求 SSL,但请求在传输过程中对数据进行加密,则使用 SSL。它解决了请求的问题。他们没有告诉您避免使用 SSL(如果他们这样做了,他们也不应该)。
-
不,他们没有告诉我要避免使用 SSL,但是没有任何证书的预算(即使它是地球上最便宜的东西),因为他们不会为任何事情提供任何额外的钱.我也被这个问题困住了,我很想在放弃之前找出问题所在,然后从头开始……
标签: php android encryption