2011-05-19 63 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