2015-05-21 87 views
0

我有一個實現加密的C#應用​​程序。我正在努力在PHP中添加一些功能來處理這個應用程序。我在應用程序中使用Rijndael Managed加密。我能夠在PHP中解密字符串沒有問題,但是當我嘗試加密字符串時,它與C#應用程序中創建的內容不匹配。我搜颳了stackoverflow,並嘗試了一堆組合,但似乎無法讓事情正常工作。問題匹配PHP加密到C#

我的C#代碼加密的字符串如下:

public static string Encrypt(string plainText, byte[] key, byte[] iv) 
    { 
     RijndaelManaged crypto = new RijndaelManaged(); 
     crypto.Key = key; 
     crypto.IV = iv; 
     byte[] textBytes = System.Text.Encoding.Unicode.GetBytes(plainText);   
     ICryptoTransform Encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV); 
     MemoryStream mem_stream = new MemoryStream(); 
     CryptoStream cryptoStream = new CryptoStream(mem_stream, Encryptor, CryptoStreamMode.Write); 
     cryptoStream.Write(textBytes, 0, textBytes.Length); 
     cryptoStream.FlushFinalBlock(); 
     byte[] CipherBytes = mem_stream.ToArray(); 
     mem_stream.Close(); 
     cryptoStream.Close(); 
     string Encrypt_Data = Convert.ToBase64String(CipherBytes); 
     return Encrypt_Data; 
    } 

在PHP我使用以下代碼:

class Encryption { 
    protected $cipher = MCRYPT_RIJNDAEL_128; 
    protected $mode = MCRYPT_MODE_CBC; 

    public function getKey() 
    { 
     return implode(array_map('chr', .....); 
    } 

    function addPadding($string) 
    { 
     $blocksize = mcrypt_get_block_size($this->cipher, $this->mode); 
     $padding = $blocksize - (strlen($string) % $blocksize); 
     $string .= str_repeat(chr($padding), $padding); 
     return $string; 
    } 

    function Encrypt($string, $iv) 
    { 
     $value = rtrim(base64_encode(mcrypt_encrypt($this->cipher, $this->getKey(), $this->addPadding($string), $this->mode, $iv))); 
     return $value; 
    } 

    function Decrypt($string, $iv) 
    { 
     return rtrim(mcrypt_decrypt($this->cipher, $this->getKey(), base64_decode($string), $this->mode, $iv)); 
    } 

} 

兩者都使用相同的私鑰(一個字節陣列32個字節長)。我使用的現有樣本來測試它,如下圖所示:

$iv = hex2bin('B773705230CFADC864401FF2EB1FCF14'); 
$first = 'Jx7Khz4v+AQE3lUkIQF/SA=='; 

$enc = new Encryption; 
$decrypted = $enc->Decrypt($first, $iv); 
print_r(unpack('C*', $decrypted)); 
print_r(unpack('C*', 'Jackson')); 
$encrypted = $enc->Encrypt('Jackson', $iv); 

echo 'C# Encrypted: '.$first."\n"; 
echo 'Decrypted: '.$decrypted."\n"; 
echo 'PHP Encrypted: '.$encrypted; 

這是它變得有趣。我得到的解密字符串很好(它打印出傑克遜),但它的字節數組很奇怪。這似乎是如何填充初始字符串可能導致問題。

Array 
(
    [1] => 74 
    [2] => 0 
    [3] => 97 
    [4] => 0 
    [5] => 99 
    [6] => 0 
    [7] => 107 
    [8] => 0 
    [9] => 115 
    [10] => 0 
    [11] => 111 
    [12] => 0 
    [13] => 110 
    [14] => 0 
    [15] => 2 
    [16] => 2 
) 
Array 
(
    [1] => 74 
    [2] => 97 
    [3] => 99 
    [4] => 107 
    [5] => 115 
    [6] => 111 
    [7] => 110 
) 
C# Encrypted: Jx7Khz4v+AQE3lUkIQF/SA== 
Decrypted: Jackson 
PHP Encrypted: /qIq5gSWFPbLpGJMkGg+Zw== 

這顯然與填充有關。我只是不確定爲什麼似乎有0的其他字節。我顯然在某處丟失了某些東西。我已經在c#中設置了加密的數據,並且數據已經被加密,所以改變C#代碼幾乎是不可能的,除非我在應用程序中有一個幫助函數,可以在存儲到數據庫中之前調整這些值。......

非常感謝您的幫助。

編輯:用溶液

更新凱文指出不同的是在C#應用UTF-16和UTF-8在PHP之間。爲了解決這個問題,我不得不做出的加密功能的微小變化如下所述的字符串轉換爲正確的編碼:

function Encrypt($string, $iv) 
    { 
     $string = iconv('UTF-8', 'UTF-16LE', $string); 
     $value = rtrim(base64_encode(mcrypt_encrypt($this->cipher, $this->getKey(), $this->addPadding($string), $this->mode, $iv))); 
     return $value; 
    } 
+2

0的原因是您正在爲源字符串使用Unicode編碼(每個字符16位)。如果您使用UTF8或ASCII(每個字符8位),那麼0將不再出現在陣列中。我還注意到你說你使用的是32字節密鑰(即256位),在PHP中你的密碼是MCRYPT_RIJNDAEL_128,表示128位密鑰(16字節)。確保你的密鑰是相同的(我認爲他們是因爲你可以在PHP中解密)。 – Kevin

+0

這絕對看起來是這樣。我使用'$ string = mb_convert_encoding($ string,'utf-16','utf-8');'並且它添加了零,但是它們是向後的(0,74,0,97等)。任何想法?關於128,我使用的是256位密鑰和128位塊大小。 – jmgardn2

+0

只是不確定密碼名稱中的128。所有AES加密使用128位塊大小,除非您更改它,我不會推薦。 0在Linux機器上倒退的原因是Windows和Linux之間的差異。 – Kevin

回答

1

的原因陣列中的0是您正在使用Unicode編碼(每個字符16位)將源字符串轉換爲數組。如果您使用UTF8或ASCII(每個字符8位),那麼0將不再出現在陣列中。你只需確保你在兩邊使用相同的編碼(在發送端創建數組並在接收端編碼字符串)。然後只要你的鑰匙和IV匹配雙方,你應該很好去。