2015-11-20 25 views
1

我必須從用C#編寫的外部現有webservice請求數據。 這個web服務需要一些數據加密(連接使用SSL連接,一些數據是加密的)在c#和PHP之間使用AES加密/解密數據 - 解密數據從255,254開始

在php網站上,openssl用於解密。

  • 算法:AES
  • 填充:PKCS7
  • 模式:CBC
  • 密鑰大小

    以下設置在C#站點 (這是用於AesCryptoServiceProvider的默認值),用於:256

PKCS7的填充工作如下: 01如果丟失1個字節 02 02如果丟失2個字節 等等

所以這個值不會被填充。

我在做什麼錯?

我用c#,PHP和Ruby選中此 - 255解密後的數據開始時,254

要重現使用以下參數:

數據:123456789鍵:First1 鹽(四):數據

using System; 
using System.Security.Cryptography; 
using System.Text; 
using System.IO; 

namespace crypto_test 
{ 
    class MainClass 
    { 
     public static void Main(string[] args) 
     { 

       bool running = true; 
       while (running) 
       { 
        Console.WriteLine("Enter data:"); 
        var data = Console.ReadLine(); 
        Console.WriteLine("Enter key:"); 
        var key = Console.ReadLine(); 
        Console.WriteLine("Enter iv:"); 
        var iv = Console.ReadLine(); 
        Console.WriteLine("Enter d for decode"); 
        var decode = (Console.ReadLine() == "d"); 

        string encoded=Crypt(data, key, iv, decode); 
        Console.WriteLine(encoded); 
        if (!decode) 
        { 
         encoded= Crypt(encoded, key, iv, true); 
         Console.WriteLine(encoded); 
        } 

        Console.WriteLine("quit to exit"); 
        running = !(Console.ReadLine() == "quit"); 
       } 

     } 

     public static string Crypt(string value, string password, string salt, bool decrypt) 
     { 
      DeriveBytes rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt)); 
      SymmetricAlgorithm algorithm = new AesCryptoServiceProvider(); 
      byte[] rgbKey = rgb.GetBytes(algorithm.KeySize >> 3); 
      byte[] rgbIV = rgb.GetBytes(algorithm.BlockSize >> 3); 

      Console.WriteLine("rbKey: size:{0} key:{1}", (algorithm.KeySize >> 3), GetHex(rgbKey)); 
      Console.WriteLine("rgbIV: size:{0} key:{1}", (algorithm.BlockSize >> 3), GetHex(rgbIV)); 

      ICryptoTransform transform = decrypt ? algorithm.CreateDecryptor(rgbKey, rgbIV) : algorithm.CreateEncryptor(rgbKey, rgbIV); 
      Console.WriteLine("Mode {0}", algorithm.Mode); 
      Console.WriteLine("PAdding {0}", algorithm.Padding); 

      using (MemoryStream buffer = new MemoryStream()) 
      { 
       using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write)) 
       { 
        try 
        { 
         if (decrypt) 
         { 
          byte[] data = Convert.FromBase64String(value); 
          stream.Write(data,0,data.Length); 
         } 
         else 
         { 
          using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode)) 
          { 
           writer.Write(value); 
          } 
         } 
        } 
        catch (Exception e) 
        { 
         Console.WriteLine(e.ToString()); 
        } 
       } 

       byte[] buff = buffer.ToArray(); 
       if (decrypt) 
       { 
        return Encoding.Unicode.GetString(buff) + "\r\n" + GetHex(buff); 
       } 
       else 
        return Convert.ToBase64String(buff); 
      } 
     } 

     public static string GetHex(byte[] data) 
     { 
      StringBuilder sb = new StringBuilder(); 
      for (int i = 0; i < data.Length; ++i) 
       sb.Append(data[i].ToString("X2")); 
      return sb.ToString(); 
     } 
    } 
} 

我還沒有找到一個相當於Rfc2898DeriveBytes到現在爲止, 所以我複製了密鑰和IV

PHP

<?php 

$salt='Data'; 
$pass='First1'; 
$data='123456789'; 

$encrypted_base64='VKNd9Pi+cttaM6ne8pzAuFbH1U0gJiJ2Wlbbr1rU5z8vbIfAS6nb0/5py4p54aK7'; 
$encrypted=base64_decode($encrypted_base64); 
$key = pack('H*', "30EE7F95F0EF4835F048A481424F2F52EE21B7CEB97F8CC437E5949DB53797D9"); 
$iv = pack('H*', "B29F5ECF7057065758102385509F0637"); 
$cipher='AES-256-CBC'; 
$decrypted = openssl_decrypt($encrypted,$cipher, $key,true,$iv); 
for($i =0; $i<strlen($decrypted);++$i) 
{ 
    echo "char:" . ord($decrypted[$i])."<br/>"; 
} 
echo $decrypted 
?> 

紅寶石:

require ('openssl') 
require ('base64') 

while true 


enc_data='VKNd9Pi+cttaM6ne8pzAuFbH1U0gJiJ2Wlbbr1rU5z8vbIfAS6nb0/5py4p54aK7' 

data = Base64.decode64(enc_data) 

key_hex='30EE7F95F0EF4835F048A481424F2F52EE21B7CEB97F8CC437E5949DB53797D9' 
iv_hex='B29F5ECF7057065758102385509F0637' 


key = [key_hex].pack('H*') 
iv = [iv_hex].pack('H*') 

decipher = OpenSSL::Cipher::AES.new(256, :CBC) 
decipher.decrypt 
decipher.key = key 
decipher.iv = iv 
plain = decipher.update(data) + decipher.final 

puts plain 
puts plain.bytes 

end 
+0

問題是,如果我再次解碼數據,它開始255,254,我不知道爲什麼。我添加了代碼來重現它。 – lumos0815

回答

2

好消息,你的解密似乎工作確定。

你在解密的密文中看到的是UTF-16 LE的字節順序標記,它被Microsoft錯誤地指示爲Encoding.Unicode。你需要做任何一件事兩件事:

  1. 解碼文本解碼器,groek UTF-16 LE包括字節順序標記;
  2. 編碼使用更合理的UTF-8編碼(在C#代碼中)。

就我個人而言,我會對(2)強烈偏好。