加密字符串PHP代碼的服務器端。 我使用PKCS8而不是PKCS1,這樣我就可以在Android端解密。Android的PHP設備解密RSA加密字符串失敗,解密結果不正確
加密的代碼如下: 我使用phpseclib。
include('libs/PHPSecLib/Crypt/RSA.php');
...碼查找存儲在數據庫中省略公鑰和私鑰...
$rsa = new Crypt_RSA();
$rsa->loadKey($row['pref_pub_key']); // public key stored in MySQL BLOB.
$plaintext = 'Testing 123';
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS8); //USE PKCS8
$ciphertext = $rsa->encrypt($plaintext);
echo $ciphertext;
$rsa->loadKey($row['pref_priv_key']); // private key stored in MySQL BLOB
echo $rsa->decrypt($ciphertext);
$query = "UPDATE preferences SET pref_license = ?;
//execute query to store the encrypted text in pref_license BLOB field.
try {
$stmt = $db->prepare($query);
$stmt->bindParam(1,$ciphertext);
$stmt->bindParam(2,$ref);
$db->errorInfo();
$result = $stmt->execute();
}
catch (PDOException $ex) {
$response["success"] = 0;
$response["message"] = "Database Error. Couldn't update Pref post with License!" . $ex->getMessage();
echo $response["message"];
die(json_encode($response));
}
我基本加密字符串,並將其存儲在一個BLOB字段,供日後參考。
我產生了私有公有密鑰對,並存儲在以下列方式BLOB,併發送專用密鑰到Android設備:
include('libs/PHPSecLib/Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS8);
extract($rsa->createKey());
//echo $privatekey . '<br/><br/>' . $publickey; //I can see that it worked!
if (!empty($_POST)) {
//initial update query to store the keys in BLOBS on SERVER MYSQL
$query = "UPDATE preferences SET pref_priv_key = ?, pref_pub_key = ?
WHERE pref_device_serial = ?";
//execute query
try {
$stmt = $db->prepare($query);
$stmt->bindParam(1,$privatekey);
$stmt->bindParam(2,$publickey);
$stmt->bindParam(3,$_POST['p_device_serial']);
$db->errorInfo();
$result = $stmt->execute();
}
catch (PDOException $ex) {
$response["success"] = 0;
$response["message"] = "Database Error. Couldn't update Pref post!" . $ex->getMessage();
die(json_encode($response));
}
}
//then I send the $privatekey to the Android device and save it there.
//to then later decrypt the serverside encrypted string.
$response["success"] = 1;
$response["pk"] = $privatekey;
$response["message"] = "Key Pair successfully generated.";
echo json_encode($response);
在Android設備上,我用ANS的AsyncTask來請求加密的字符串和然後讀取來自本地SQLite BLOB字段中的專用密鑰,並嘗試解密字符串:
class GetLicense extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(LicenseActivity.this);
pDialog.setMessage("Retrieving License Data...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
protected String doInBackground(String... args) {
int success;
String elicense;
try {
getPref = LicenseActivity.this.openOrCreateDatabase("aaa.db", Context.MODE_PRIVATE, null);
Cursor c = getPref.rawQuery("SELECT * FROM preferences", null);
Log.d("request!", "starting");
if (c != null) {
if (c.moveToFirst()) {
do {
String Preferences_Id = c.getString(c.getColumnIndex(SupaAttendDb.KEY_ROWID));
String Preferences_UUID = c.getString(c.getColumnIndex(SupaAttendDb.KEY_Preferences_PREFUUID));
String Preferences_Device_Serial = c.getString(c.getColumnIndex(SupaAttendDb.KEY_Preferences_PREFDEVICESERIAL));
sPK = c.getString(c.getColumnIndex(SupaAttendDb.KEY_Preferences_PREFPK));
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("p_uuid", Preferences_UUID));
try {
//Get Encrypted License from server
JSONObject json = jsonParser.makeHttpRequest(
GET_LICENSE_URL, "POST", params);
// full json response
// json success element
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
sData = json.getString(TAG_LICENSE);
..then我保存許可證到Android的SQLite。代碼不需要... 在onPostExecute中,我格式化PrivateKey,然後嘗試解密sData,但獲取不正確的數據,而不是「測試123」。
protected void onPostExecute(String file_url) {
pDialog.dismiss();
String privKeyPEM = sPK.replace("-----BEGIN PRIVATE KEY-----\r\n", "");
privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] b = Base64.decode(privKeyPEM,Base64.DEFAULT);
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(b); //This decodes properly without any exceptions.
PrivateKey privateKey2 = null;
try {
privateKey2 = keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
byte[] decryptedData = null;
Cipher cipher = null;
try {
cipher = Cipher.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE,privateKey2);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] sD = Base64.decode(sData, Base64.DEFAULT);// Here I try to get the encrypted string retrieved from server into a byte[].
try {
decryptedData = cipher.doFinal(sD); // no errors, but I get the incorrect unencrypted string.
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
if (decryptedData != null){
String decrypted = new String(decryptedData);
//decryptedData = Base64.encode(decryptedData,Base64.DEFAULT);
Toast.makeText(LicenseActivity.this, decrypted, Toast.LENGTH_LONG).show();
}
}
}
我知道我只是在做東西的代碼,我嘗試和解碼加密的字符串這最後有點笨,然後進行解密。 希望你能指出我正確的方向,對不起長時間囉嗦。
哦,是的,我可以告訴大家,我檢索用下面的PHP服務器的許可證:
require("config.inc.php");
if (!empty($_POST)) {
//initial query
$query = "SELECT pref_uuid, pref_license, pref_device_serial FROM preferences WHERE pref_uuid = :p_uuid";
$query_params = array(':p_uuid' => $_POST['p_uuid']);
//execute query
try {
$stmt = $db->prepare($query);
$db->errorInfo();
$result = $stmt->execute($query_params);
}
catch (PDOException $ex) {
$response["success"] = 0;
$response["message"] = "Database Error. Couldn't retrieve License details!" . $ex->getMessage();
die(json_encode($response));
}
if(!$result) {
$response["success"] = 0;
$response["message"] = "Database Error. Couldn't return Licenses!" . $ex->getMessage();
die(json_encode($response));
}
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$response["license"] = base64_encode($row['pref_license']); // I encode it here before I send the encrypted string off to android device.
$response["message"] = "License Record successfully retrieved";
$response["success"] = 1;
echo json_encode($response);
}
這是最低工作的例子嗎?如果是這樣,那麼! – KevinDTimm
[PKCS#8](https://tools.ietf.org/html/rfc5208)是「私鑰信息語法規範」。雖然它支持加密私鑰,但不應該直接使用它加密字符串。相反,使用PKCS#1(1.5填充或OAEP,這更好)或使用PKCS#7/CMS進行加密。 –
親愛的Maarten Bodewes,我使用的是PKCS#1,但Android並不明顯支持它,因此我被建議更改爲PKCS#8。 –