安全通信 PHP (phpseclib) 和 C# (Unity 3D)
Secure communication PHP (phpseclib) and C# (Unity 3D)
我正在尝试在 PHP 服务器和 Unity 3D 游戏(在网络播放器中)之间建立安全的 RSA 连接。在过程结束时 $rsa->decrypt() return "false" :-(
服务器生成 RSA 密钥并将 public 密钥发送到 Unity:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$keys = $rsa->createKey(512);
extract($keys);
$rsa->loadKey($publickey);
$_SESSION["privatekey"] = $privatekey;
$this->payload->Modulus = base64_encode($rsa->modulus);
$this->payload->Exponent = base64_encode($rsa->publicExponent);
这会生成 JSON:
{"Modulus":"MTE5MjcyOTYyNjQzMTIzODQ1MTI4MjE2ODA3OTY2MDE5MDQwODQ1NTc0MDIzMDI0NDQ5MjAzMDY4NDgxNTkyNzk5MTc0MzYxMzI4MDA3Njk0MjI4NjAyMzAwODA4MDI5MzkwOTk2MjUyMTg5OTkwNDgwNzg3MDcwMjk4MjkxMjcxNjQ1NzMzNDg0MTcxNTc0MDM3ODM0NjE3ODE=","Exponent":"NjU1Mzc="}
统一编码器:
var N = JSON.Parse (generatedJSON); //im using SimpleJSON library
var publicKey = new RSAParameters ();
publicKey.Modulus = Convert.FromBase64String(N ["Modulus"].Value);
publicKey.Exponent = Convert.FromBase64String(N ["Exponent"].Value);
var csp = new RSACryptoServiceProvider(512);
csp.ImportParameters(publicKey);
var plainTextData = "Hello Wordl"; //here come AES key generator (not implemented yet)
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
var cypherText = Convert.ToBase64String(bytesCypherText);
统一回复:
Nqsno9tTXWr4UfwoXQcHwzwnusvdKWpVGoakSsVECh3lH/3bNaPKY9LzZ9iZIs8RI9e5EI+GvegnxrW5xoqnyrDHbF8AuWh9Hndnn0OS5SV/kiYeBT6Wn9pxwjq5MoixM3geushHpvGTDQV0NOLcsXTdv8tG0CvFZip31GpMp9C/OalxolpaUvk65YBJ0dJcyNiuD08PQJAupJXKnVgfLZ0i1GrjQ7guHO6OmEUKDyQcZ5Sf/6yJry3Mhv2R4ioR/jU+mL4tLKuix5+/XKmBjg==
和服务器解码器:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$rsa->loadKey($_SESSION["privatekey"]);
$message = $_POST["unityResponse"];
$ciphertext = base64_decode($message);
$this->payload->message = $rsa->decrypt($ciphertext);
Return "Decryption error in..." :(
我认为一般问题出在 C# 中...你能帮我吗?
已解决!
另一种方式 - XML 密钥格式
服务器代码:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_XML);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_XML);
$keys = $rsa->createKey(1024);
extract($keys);
$rsa->loadKey($publickey);
$_SESSION["privatekey"] = $privatekey;
$this->payload->publickey = $publickey;
生成 JSON:
{"publickey":"<RSAKeyValue>\r\n <Modulus>sCL/O7uUl4T32nUxZhKj1svDG88k4jkGsh/7IiFX/kTbj3mXmtYPLn5xTyLxEt9FxA/aoVxBmh1k7wA7lvcu5z4Avw6+AA/j793iDEhGdfvmXmHxm05xkjYO+LZ449YGDst9DUDO8SDA948Rld+eA187d/nhVPPAmun7RbLXBrs=</Modulus>\r\n <Exponent>AQAB</Exponent>\r\n</RSAKeyValue>"}
Unity 网络播放器代码:
var N = JSON.Parse (generatedJSON);
var csp = new RSACryptoServiceProvider(1024);
csp.FromXmlString (N ["publickey"]);
var plainTextData = "Hello from Web Player";
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
var cypherText = Convert.ToBase64String(bytesCypherText);
最后服务器解密:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_XML);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_XML);
$rsa->loadKey($_SESSION["privatekey"]);
$cypherText= $_POST["cypherText"];
$bytesCipherText = base64_decode($message);
$this->payload->encrypted = $rsa->decrypt($bytesCipherText);
你得到 JSON:
{"message":"Hello from Web Player"}
感谢完美的 phpsec 库!这是史诗!
我在这里分享我的示例 Unity 项目。希望它对某些人有用;)
GitHub: unity-php-secure-communication
<?php
<?php
/**
* test with curl:
*
* // Generate keypair : return XML public key
* curl -c cookies.txt -d "keygen=1" http://exemple.com//encrypt.php
*
* // Test encrypt/decrypt : return encrypted and decrypted `my text to encode`
* curl -b cookies.txt -d "test=my text to encode" http://exemple.com//encrypt.php
*
* // Test encrypt : return encrypted
* curl -b cookie.txt -d "encrypt=my text to encode" http://exemple.com//encrypt.php > encrypted.txt; cat encrypted.txt
*
* // Test decrypt : return decrypted `my text to encode`
* curl -b cookie.txt -d "decrypt=`cat encrypted.txt`" http://exemple.com//encrypt.php
*/
include 'vendor/autoload.php';
use phpseclib\Crypt\RSA;
function generateKeyPair(){
if (!isset($_SESSION['publickey'])){
$rsa = new RSA();
$rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_XML);
$rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_XML);
$keys = $rsa->createKey();
$_SESSION['privatekey'] = $keys['privatekey'];
$_SESSION['publickey'] = $keys['publickey'];
}
return $_SESSION['publickey'];
}
function encrypt($cleartext){
$rsa = new RSA();
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
$rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_XML);
$rsa->loadKey($_SESSION['publickey']);
$bytesCipherText = $rsa->encrypt($cleartext);
return rawurlencode(base64_encode($bytesCipherText));
}
function decrypt($encrypted){
$rsa = new RSA();
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_XML);
$rsa->loadKey($_SESSION['privatekey']);
$bytesCipherText = base64_decode(rawurldecode($encrypted));
return $rsa->decrypt($bytesCipherText);
}
if (isset($_POST['session_id'])) {
session_id($_POST['session_id']);
}
session_start();
if (isset($_POST['keygen'])) {
echo generateKeyPair();
exit();
}
if (isset($_POST['encrypt'])) {
echo encrypt($_POST['encrypt']);
exit();
}
if (isset($_POST['decrypt'])) {
echo decrypt($_POST['decrypt']);
exit();
}
if (isset($_POST['test'])) {
generateKeyPair();
$ciphertext = encrypt($_POST['test']);
echo "encrypted: $ciphertext\n\n";
$clearText = decrypt($ciphertext);
echo "decrypted: $clearText\n";
exit();
}
using System;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Networking;
using UnityEngine.UI;
public class EncryptController : MonoBehaviour
{
public string ScriptUrl = "http://example.com/encrypt.php";
public InputField ClearTextInputField;
public InputField EncryptedTextInputField;
public InputField ClearResponseInputField;
public Text SessionIdText;
public Text PublicKeyText;
public void OnKeygenButtonClick()
{
StartCoroutine(GenerateRsaKeyPair());
}
public void OnEncryptButtonClick()
{
if (PublicKeyText.text.Length < 100)
{
Debug.LogError("You must generate RSA key pair before");
return;
}
var csp = new RSACryptoServiceProvider(1024);
csp.FromXmlString(PublicKeyText.text);
var plainTextData = ClearTextInputField.text;
var bytesPlainTextData = Encoding.Unicode.GetBytes(plainTextData);
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
var cypherText = Convert.ToBase64String(bytesCypherText);
EncryptedTextInputField.text = cypherText;
}
public void OnDecryptButtonClick()
{
if (PublicKeyText.text.Length < 100)
{
Debug.LogError("You must generate RSA key pair before");
return;
}
StartCoroutine(SendEncryptedText(EncryptedTextInputField.text));
}
IEnumerator GenerateRsaKeyPair()
{
var form = new WWWForm();
form.AddField("keygen", 1);
form.AddField("session_id", AnalyticsSessionInfo.sessionId.ToString());
SessionIdText.text = "sessionId=" + AnalyticsSessionInfo.sessionId.ToString();
using (var www = UnityWebRequest.Post(ScriptUrl, form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
Debug.LogError(www.error);
}
else
{
LogHeaders(www);
Debug.Log(www.downloadHandler.text);
PublicKeyText.text = www.downloadHandler.text;
}
}
}
IEnumerator SendEncryptedText(string text)
{
var form = new WWWForm();
form.AddField("decrypt", text);
form.AddField("session_id", AnalyticsSessionInfo.sessionId.ToString());
SessionIdText.text = "sessionId=" + AnalyticsSessionInfo.sessionId.ToString();
using (var www = UnityWebRequest.Post(ScriptUrl, form))
{
//www.SetRequestHeader("cookie", SessionIdText.text);
yield return www.SendWebRequest();
if (www.isNetworkError)
{
Debug.LogError(www.error);
}
else
{
LogHeaders(www);
// Print Body
Debug.Log(www.downloadHandler.text);
ClearResponseInputField.text = www.downloadHandler.text;
}
}
}
private void LogHeaders(UnityWebRequest www)
{
var sb = new StringBuilder();
foreach (var dict in www.GetResponseHeaders())
{
sb.Append(dict.Key).Append(": \t[").Append(dict.Value).Append("]\n");
if (dict.Key == "Set-Cookie")
{
SessionIdText.text = dict.Value + " (from response headers)";
}
}
Debug.Log(sb.ToString());
}
}
我正在尝试在 PHP 服务器和 Unity 3D 游戏(在网络播放器中)之间建立安全的 RSA 连接。在过程结束时 $rsa->decrypt() return "false" :-(
服务器生成 RSA 密钥并将 public 密钥发送到 Unity:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$keys = $rsa->createKey(512);
extract($keys);
$rsa->loadKey($publickey);
$_SESSION["privatekey"] = $privatekey;
$this->payload->Modulus = base64_encode($rsa->modulus);
$this->payload->Exponent = base64_encode($rsa->publicExponent);
这会生成 JSON:
{"Modulus":"MTE5MjcyOTYyNjQzMTIzODQ1MTI4MjE2ODA3OTY2MDE5MDQwODQ1NTc0MDIzMDI0NDQ5MjAzMDY4NDgxNTkyNzk5MTc0MzYxMzI4MDA3Njk0MjI4NjAyMzAwODA4MDI5MzkwOTk2MjUyMTg5OTkwNDgwNzg3MDcwMjk4MjkxMjcxNjQ1NzMzNDg0MTcxNTc0MDM3ODM0NjE3ODE=","Exponent":"NjU1Mzc="}
统一编码器:
var N = JSON.Parse (generatedJSON); //im using SimpleJSON library
var publicKey = new RSAParameters ();
publicKey.Modulus = Convert.FromBase64String(N ["Modulus"].Value);
publicKey.Exponent = Convert.FromBase64String(N ["Exponent"].Value);
var csp = new RSACryptoServiceProvider(512);
csp.ImportParameters(publicKey);
var plainTextData = "Hello Wordl"; //here come AES key generator (not implemented yet)
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
var cypherText = Convert.ToBase64String(bytesCypherText);
统一回复:
Nqsno9tTXWr4UfwoXQcHwzwnusvdKWpVGoakSsVECh3lH/3bNaPKY9LzZ9iZIs8RI9e5EI+GvegnxrW5xoqnyrDHbF8AuWh9Hndnn0OS5SV/kiYeBT6Wn9pxwjq5MoixM3geushHpvGTDQV0NOLcsXTdv8tG0CvFZip31GpMp9C/OalxolpaUvk65YBJ0dJcyNiuD08PQJAupJXKnVgfLZ0i1GrjQ7guHO6OmEUKDyQcZ5Sf/6yJry3Mhv2R4ioR/jU+mL4tLKuix5+/XKmBjg==
和服务器解码器:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$rsa->loadKey($_SESSION["privatekey"]);
$message = $_POST["unityResponse"];
$ciphertext = base64_decode($message);
$this->payload->message = $rsa->decrypt($ciphertext);
Return "Decryption error in..." :(
我认为一般问题出在 C# 中...你能帮我吗?
已解决!
另一种方式 - XML 密钥格式
服务器代码:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_XML);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_XML);
$keys = $rsa->createKey(1024);
extract($keys);
$rsa->loadKey($publickey);
$_SESSION["privatekey"] = $privatekey;
$this->payload->publickey = $publickey;
生成 JSON:
{"publickey":"<RSAKeyValue>\r\n <Modulus>sCL/O7uUl4T32nUxZhKj1svDG88k4jkGsh/7IiFX/kTbj3mXmtYPLn5xTyLxEt9FxA/aoVxBmh1k7wA7lvcu5z4Avw6+AA/j793iDEhGdfvmXmHxm05xkjYO+LZ449YGDst9DUDO8SDA948Rld+eA187d/nhVPPAmun7RbLXBrs=</Modulus>\r\n <Exponent>AQAB</Exponent>\r\n</RSAKeyValue>"}
Unity 网络播放器代码:
var N = JSON.Parse (generatedJSON);
var csp = new RSACryptoServiceProvider(1024);
csp.FromXmlString (N ["publickey"]);
var plainTextData = "Hello from Web Player";
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
var cypherText = Convert.ToBase64String(bytesCypherText);
最后服务器解密:
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_XML);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_XML);
$rsa->loadKey($_SESSION["privatekey"]);
$cypherText= $_POST["cypherText"];
$bytesCipherText = base64_decode($message);
$this->payload->encrypted = $rsa->decrypt($bytesCipherText);
你得到 JSON:
{"message":"Hello from Web Player"}
感谢完美的 phpsec 库!这是史诗!
我在这里分享我的示例 Unity 项目。希望它对某些人有用;)
GitHub: unity-php-secure-communication
<?php
<?php
/**
* test with curl:
*
* // Generate keypair : return XML public key
* curl -c cookies.txt -d "keygen=1" http://exemple.com//encrypt.php
*
* // Test encrypt/decrypt : return encrypted and decrypted `my text to encode`
* curl -b cookies.txt -d "test=my text to encode" http://exemple.com//encrypt.php
*
* // Test encrypt : return encrypted
* curl -b cookie.txt -d "encrypt=my text to encode" http://exemple.com//encrypt.php > encrypted.txt; cat encrypted.txt
*
* // Test decrypt : return decrypted `my text to encode`
* curl -b cookie.txt -d "decrypt=`cat encrypted.txt`" http://exemple.com//encrypt.php
*/
include 'vendor/autoload.php';
use phpseclib\Crypt\RSA;
function generateKeyPair(){
if (!isset($_SESSION['publickey'])){
$rsa = new RSA();
$rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_XML);
$rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_XML);
$keys = $rsa->createKey();
$_SESSION['privatekey'] = $keys['privatekey'];
$_SESSION['publickey'] = $keys['publickey'];
}
return $_SESSION['publickey'];
}
function encrypt($cleartext){
$rsa = new RSA();
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
$rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_XML);
$rsa->loadKey($_SESSION['publickey']);
$bytesCipherText = $rsa->encrypt($cleartext);
return rawurlencode(base64_encode($bytesCipherText));
}
function decrypt($encrypted){
$rsa = new RSA();
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_XML);
$rsa->loadKey($_SESSION['privatekey']);
$bytesCipherText = base64_decode(rawurldecode($encrypted));
return $rsa->decrypt($bytesCipherText);
}
if (isset($_POST['session_id'])) {
session_id($_POST['session_id']);
}
session_start();
if (isset($_POST['keygen'])) {
echo generateKeyPair();
exit();
}
if (isset($_POST['encrypt'])) {
echo encrypt($_POST['encrypt']);
exit();
}
if (isset($_POST['decrypt'])) {
echo decrypt($_POST['decrypt']);
exit();
}
if (isset($_POST['test'])) {
generateKeyPair();
$ciphertext = encrypt($_POST['test']);
echo "encrypted: $ciphertext\n\n";
$clearText = decrypt($ciphertext);
echo "decrypted: $clearText\n";
exit();
}
using System;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.Networking;
using UnityEngine.UI;
public class EncryptController : MonoBehaviour
{
public string ScriptUrl = "http://example.com/encrypt.php";
public InputField ClearTextInputField;
public InputField EncryptedTextInputField;
public InputField ClearResponseInputField;
public Text SessionIdText;
public Text PublicKeyText;
public void OnKeygenButtonClick()
{
StartCoroutine(GenerateRsaKeyPair());
}
public void OnEncryptButtonClick()
{
if (PublicKeyText.text.Length < 100)
{
Debug.LogError("You must generate RSA key pair before");
return;
}
var csp = new RSACryptoServiceProvider(1024);
csp.FromXmlString(PublicKeyText.text);
var plainTextData = ClearTextInputField.text;
var bytesPlainTextData = Encoding.Unicode.GetBytes(plainTextData);
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
var cypherText = Convert.ToBase64String(bytesCypherText);
EncryptedTextInputField.text = cypherText;
}
public void OnDecryptButtonClick()
{
if (PublicKeyText.text.Length < 100)
{
Debug.LogError("You must generate RSA key pair before");
return;
}
StartCoroutine(SendEncryptedText(EncryptedTextInputField.text));
}
IEnumerator GenerateRsaKeyPair()
{
var form = new WWWForm();
form.AddField("keygen", 1);
form.AddField("session_id", AnalyticsSessionInfo.sessionId.ToString());
SessionIdText.text = "sessionId=" + AnalyticsSessionInfo.sessionId.ToString();
using (var www = UnityWebRequest.Post(ScriptUrl, form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
Debug.LogError(www.error);
}
else
{
LogHeaders(www);
Debug.Log(www.downloadHandler.text);
PublicKeyText.text = www.downloadHandler.text;
}
}
}
IEnumerator SendEncryptedText(string text)
{
var form = new WWWForm();
form.AddField("decrypt", text);
form.AddField("session_id", AnalyticsSessionInfo.sessionId.ToString());
SessionIdText.text = "sessionId=" + AnalyticsSessionInfo.sessionId.ToString();
using (var www = UnityWebRequest.Post(ScriptUrl, form))
{
//www.SetRequestHeader("cookie", SessionIdText.text);
yield return www.SendWebRequest();
if (www.isNetworkError)
{
Debug.LogError(www.error);
}
else
{
LogHeaders(www);
// Print Body
Debug.Log(www.downloadHandler.text);
ClearResponseInputField.text = www.downloadHandler.text;
}
}
}
private void LogHeaders(UnityWebRequest www)
{
var sb = new StringBuilder();
foreach (var dict in www.GetResponseHeaders())
{
sb.Append(dict.Key).Append(": \t[").Append(dict.Value).Append("]\n");
if (dict.Key == "Set-Cookie")
{
SessionIdText.text = dict.Value + " (from response headers)";
}
}
Debug.Log(sb.ToString());
}
}