2011-05-19 58 views
3

我遇到了從我們的SQL Server(2008R2)數據庫中的NVARCHAR字段中檢索加密數據的問題,看起來對於某些記錄,我的C#.NET應用程序中的數據字符串值與數據庫記錄中的數據字符串值不同。這很難證明,但我最終發現,通過查看字符串的byte []表示確實存在差異。.NET錯誤與字符串轉換爲字節[]?

玩得更遠我能夠生產這個測試應用程序,讓我有點擔心。我拿了一個字節數組(爲了簡化安裝而從十六進制轉換而來),將它轉換爲一個帶有Unicode編碼器的字符串,然後返回到一個字節數組,並看到生成的字節數組與原始數組不同!在下面的代碼中,第一個十六進制字符串在第二個工作時失敗。

我的方法在這裏有什麼問題(我不是說試圖將字節數組轉換爲字符串)還是在.NET框架中可能存在錯誤?

using System; 

namespace ByteArrayTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WindowWidth = 80; 
      Console.Clear(); 

      foreach (string s in new string[] 
       { 
        "00CD6C8300C2A2C09B9E6B1F258F7B1101000000AB4CB23EBE32F0DD", 
        "00CD6C8300C2A2C09B9E6B1F258F7B1101000000E12617F83C3F7F6A" 
       } 
      ) 
      { 
       byte[] b1 = System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary.Parse(s).Value; 
       string tmp = System.Text.Encoding.Unicode.GetString(b1); 

       byte[] b2 = System.Text.Encoding.Unicode.GetBytes(tmp); 

       Console.WriteLine("Orig: {0}", s); 

       string s2 = BitConverter.ToString(b2).Replace("-", ""); 
       Console.WriteLine("Conv: {0}", s2); 

       Console.WriteLine(s == s2 ? "EQUAL :-)" : "** NOT EQUAL **"); 
       Console.WriteLine(); 
      } 

      Console.WriteLine("Press ENTER to exit..."); 
      Console.ReadLine(); 
     } 
    } 
} 

我使用VS2010和.NET下框架4和3.5,這一結果測試此是:

Orig: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000AB4CB23EBE32F0DD 
Conv: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000AB4CB23EBE32FDFF 
** NOT EQUAL ** 

Orig: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000E12617F83C3F7F6A 
Conv: 00CD6C8300C2A2C09B9E6B1F258F7B1101000000E12617F83C3F7F6A 
EQUAL :-) 

問候,

回答

8

如果你想存儲任意不透明的二進制數據不是真的文本在NVARCHAR字段中,應該使用base64編碼對其進行編碼。試圖把它作爲UTF-16的文本編碼(這就是你在這裏做的)是一個根本不好的主意,並且很可能會丟失數據。作爲其中一個這種情況發生的例子,你可能會得到一個字符串,其中包含一半的一個surrogate pair沒有另一半。

我假設你的「加密數據」 儲存由只調用Encoding.Unicode.GetString(bytes)其中bytes是加密的數據?如果是這樣,那肯定不是要走的路。用途:

string text = Convert.ToBase64String(bytes); 

,而是和檢索數據時,使用

byte[] bytes = Convert.FromBase64String(text); 

或者使用被設計用於在首位二進制數據的數據庫字段。

編輯:(複製我的評論)你給的例子最後失敗,將U + DDF0轉換爲U + FFFD。這實際上正是我上面提到的場景 - U + DDF0是一個「低代理」,但它沒有相應的「高代理」,所以Encoding.GetString將該字符轉換爲U + FFFD,即「替換人物」,這是(從Unicode chart

用於替換傳入的字符,它的值是採用Unicode

IIRC未知或不可表示

,您可以指定哪些Encoding做,當它遇到不好的二進制數據(這實際上是你給它的),並有可能使它拋出異常。 「

+2

」或者,使用首先爲二進制數據設計的數據庫字段。「 - 聽起來很好的建議! – 2011-05-19 06:14:55

+0

感謝喬恩,是的,我們意識到保存加密數據的數據庫字段可能應該是VARBINARY類型,但是我說過,我想我更想知道我在上面發佈的具體示例。 – MattA 2011-05-19 06:16:16

+0

@Mitch:有些時候,使用字符串表示會使生活更輕鬆 - 例如,剪切和粘貼非常簡單。但是,是的,使存儲反映你試圖存儲通常是一個很好的計劃:) – 2011-05-19 06:16:44