【问题标题】:Problems with encrypt/decrypt between Android and PHPAndroid和PHP之间的加密/解密问题
【发布时间】: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


【解决方案1】:

您遇到这个问题可能是因为当您在 PHP 中调用 encrypt 方法时,它使用一个密钥进行加密,但是 当您在 Java 代码中解密加密字符串时,您必须生成密钥,该密钥将与 PHP 密钥的不同,因此您将在解密字符串中获取这些特殊字符

您可以将对象从 PHP 传递到 Java 代码或使用 PHP-Java 桥

【讨论】:

    【解决方案2】:

    所以,经过长时间的研究和(最终)重新启动我的计算机,我找到了我想与你分享的问题的解决方案:

    首先,我将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 工作超过几个小时,请重新启动你的电脑——它会为你节省一些时间当然还有钱;)

    【讨论】:

    • 嗨,我写了那个代码。如果您对代码有任何其他问题,请告诉我,我会尽力提供帮助
    • @SERPRO,我在我的项目中使用你的代码。但我希望为每个查询随机生成 IV,并通过 PHP 或 Java 将其插入我的数据库中。我该怎么做呢?
    • @input 你可以修改它,但是你需要将生成的 IV 从 PHP 传递给 JAVA 或其他方式,否则加密/解密将不匹配。您可以使用php.net/manual/en/function.mcrypt-create-iv.php 在 PHP 中生成随机 IV
    猜你喜欢
    • 2012-06-26
    • 2011-09-30
    • 2012-07-12
    • 2018-09-28
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 2023-03-23
    • 2011-08-29
    相关资源
    最近更新 更多