我正在尝试加密客户端(C#)上的数据,然后通过POST将其传输到服务器并在服务器端(PHP)对其进行解码。
对于此测试目的,我还附加到POST,客户端使用所有值来匹配服务器 值是:
这些参数我在服务器端重新使用,这意味着我使用相同的纯文本,相同的密码短语和相同的IV 但结果不匹配
客户端的加密文本与服务器端的加密文本不匹配,其中两个文本都是从相同的输入参数生成的
这是控制台输出,您可以清楚地看到发生了什么: https://dl.dropboxusercontent.com/u/15715229/ConsoleOutput.JPG
正如您所看到的,服务器使用相同的“in”参数生成不同的哈希...
我做错了什么?
这是我的代码:
C#代码:
static void Main(string[] args)
{
string url = "http://localhost/temp.php";
WebClient web = new WebClient();
string plainText = "This is sentence I want to encrypt";
string passPhrase = "MyPassPhrase";
string IV = DateTime.Now.ToLongTimeString() + "InVector";
Console.WriteLine("");
Console.WriteLine("----- Start Client -----");
Console.WriteLine("Plain text = " + plainText);
Console.WriteLine("PassPhrase = " + passPhrase);
Console.WriteLine("IV = " + IV);
string encryptedText = Encrypt(plainText, passPhrase, IV);
Console.WriteLine("Encrypted Text = " + encryptedText);
string decryptedText = Decrypt(encryptedText, passPhrase, IV);
Console.WriteLine("Decrypted Text = " + decryptedText);
Console.WriteLine("----- End Client -----");
Console.WriteLine("");
NameValueCollection postData = new NameValueCollection();
postData.Add("plainText", plainText);
postData.Add("encryptedText", encryptedText);
postData.Add("passPhrase", passPhrase);
postData.Add("IV", IV);
string webData = Encoding.UTF8.GetString(web.UploadValues(url, "POST", postData));
Console.WriteLine("----- Start Server Respond -----");
Console.WriteLine(webData);
Console.WriteLine("----- End Server Respond -----");
}
public static string Encrypt(string plainText, string passPhrase, string IV)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(IV);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = Encoding.UTF8.GetBytes(passPhrase);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
public static string Decrypt(string cipherText, string passPhrase, string IV)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(IV);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
byte[] keyBytes = Encoding.UTF8.GetBytes(passPhrase);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
我的PHP代码:
<?php
if(isset($_POST['plainText']))
{
$plainText = $_POST['plainText'];
$clientEncryptedText = $_POST['encryptedText'];
$passPhrase = $_POST['passPhrase'];
$iv = $_POST['IV'];
echo "Plain text = ".$plainText."\n";
echo "PassPhrase = ".$passPhrase."\n";
echo "IV = ".$iv."\n";
$encryptedText = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $passPhrase, $plainText, MCRYPT_MODE_CBC, $iv ));
echo "Server Encrypted Text = ".$encryptedText."\n";
echo "Client Encrypted Text = ".$clientEncryptedText."\n";
$decryptedText = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $passPhrase, base64_decode($encryptedText), MCRYPT_MODE_CBC, $iv );
echo "Server Decrypted Text = ".$decryptedText."\n";
$decryptedText = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $passPhrase, base64_decode($clientEncryptedText), MCRYPT_MODE_CBC, $iv );
echo "Decrypted text from Client = ".$decryptedText."\n";
}
else
{
echo "POST is not set";
}
你能告诉我我做错了什么,在哪里?在客户端(C#)或服务器(PHP)?
此致 Vadims Briksins
答案 0 :(得分:1)
您的密码短语不是适当长度的密钥。 IV同样如此。因此,会发生某种填充,截断或散列。 PHP和C#很可能采用不同的方式。此外,您没有指定是否要在C#中使用AES-128或AES-256 - 因此,您可能在C#中使用AES-256,而使用AES-128进行解密。理论上,C#也可以使用不同的块大小(可能不会)。填充也可能有所不同,这可能会在以后引起问题。
确保您的IV与使用的块大小匹配(应该是128位= 16字节),并且密码/密钥匹配您选择的任何密钥大小。
如果你在实践中使用真正的密码短语,你需要使用类似PBKDF2的东西来从中获取密钥。
您还可以添加完整性检查(例如,将HMAC与单独的键一起使用)。
另外,如果您不需要,请不要自己实施加密。检查SSL / TLS是否可以为您解决问题,然后尽可能使用它。如果您愿意,可以使用硬编码的自签名证书,并且它符合您的要求,但使用现有的加密协议通常比构建自己的加密协议更好。
答案 1 :(得分:0)
终于把它排序了。整天都在与它斗争,现在很乐意与你分享代码。
代码100%正常工作 - 经过测试和验证!
C#CryptoMaster.cs文件(客户端)的内容:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace EncryptionClient
{
class CryptoMaster
{
private string encryptedText;
public void StartEncryption()
{
Console.WriteLine("");
Console.WriteLine("----- Client Start -----");
string plainText = "Hello, this is a message we need to encrypt";
Console.WriteLine("Plain Text = " + plainText);
string passPhrase ="Pass Phrase Can be any length";
string saltValue = DateTime.Now.ToLongTimeString(); //slat should be 8 bite len, in my case im using Time HH:MM:SS as it is dynamic value
string hashAlgorithm = "SHA1";
int passwordIterations = 1;
string initVector = "InitVector Should be 32 bite len";
int keySize = 256;
encryptedText = Encrypt(plainText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
Console.WriteLine("Encrypted Text = " + encryptedText);
string decryptedText = Decrypt(encryptedText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
Console.WriteLine("Decripted Text = " + decryptedText);
Console.WriteLine("----- Client End -----");
SendDataToWebServer(plainText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
}
private void SendDataToWebServer(string plainText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
NameValueCollection POST = new NameValueCollection();
//NOTE: I'm Including all this data to POST only for TESTING PURPOSE
//and to avoid manual entering of the same data at server side.
//In real live example you have to keep sensative data hidden
POST.Add("plainText", plainText);
POST.Add("passPhrase", passPhrase);
POST.Add("saltValue", saltValue);
POST.Add("hashAlgorithm", hashAlgorithm);
POST.Add("passwordIterations", passwordIterations+"");
POST.Add("initVector", initVector);
POST.Add("keySize", keySize+"");
POST.Add("encryptedText", encryptedText);
WebClient web = new WebClient();
string URL = "http://localhost/Encryptor.php";
Console.WriteLine("");
string serverRespond = Encoding.UTF8.GetString(web.UploadValues(URL, "POST", POST));
Console.WriteLine("----- Server Start -----");
Console.WriteLine(serverRespond);
Console.WriteLine("----- Server End -----");
}
public string Encrypt(string plainText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations);
byte[] keyBytes = password.GetBytes(keySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.BlockSize = 256;
symmetricKey.KeySize = 256;
symmetricKey.Padding = PaddingMode.Zeros;
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string cipherText = Convert.ToBase64String(cipherTextBytes);
return cipherText;
}
public static string Decrypt(string cipherText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations);
byte[] keyBytes = password.GetBytes(keySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.BlockSize = 256;
symmetricKey.KeySize = 256;
symmetricKey.Padding = PaddingMode.Zeros;
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
return plainText;
}
}
}
PHP Encryptor.PHP文件(服务器端)的内容:
<?php
error_reporting(0);
if (isset($_POST['plainText'])) {
$plainText = $_POST['plainText'];
$passPhrase = $_POST['passPhrase'];
$saltValue = $_POST['saltValue'];
$hashAlgorithm = $_POST['hashAlgorithm'];
$passwordIterations = $_POST['passwordIterations'];
$initVector = $_POST['initVector'];
$keySize = $_POST['keySize'];
$clientEncryptedText = $_POST['encryptedText'];
$key = getKey($passPhrase,$saltValue, $passwordIterations, $keySize, $hashAlgorithm);
echo "Plain Text = ".$plainText."\n";
echo "Client Encrypted Text = ".$clientEncryptedText."\n";
$encryptedText = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $plainText, MCRYPT_MODE_CBC, $initVector));
echo "Server Encrypted Text = ".$encryptedText."\n";
$decryptedText = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($encryptedText), MCRYPT_MODE_CBC, $initVector), "\0");
echo "Server Decrypted Text = ".$decryptedText."\n";
$decryptedText = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($clientEncryptedText), MCRYPT_MODE_CBC, $initVector), "\0");
echo "Client Decrypted Text = ".$decryptedText;
}
function getKey( $passPhrase, $saltValue, $passwordIterations, $keySize, $hashAlgorithm ) {
$hl = strlen(hash($hashAlgorithm, null, true));
$kb = ceil($keySize / $hl);
$dk = '';
for ( $block = 1; $block <= $kb; $block ++ ) {
$ib = $b = hash_hmac($hashAlgorithm, $saltValue . pack('N', $block), $passPhrase, true);
for ( $i = 1; $i < $passwordIterations; $i ++ )
$ib ^= ($b = hash_hmac($hashAlgorithm, $b, $passPhrase, true));
$dk .= $ib;
}
return substr($dk, 0, $keySize);
}
?>