2015-11-20 23 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)强烈偏好。