C# 往返Unicode转换返回不同的字节[]数组

C# 往返Unicode转换返回不同的字节[]数组,c#,arrays,string,rsa,type-conversion,C#,Arrays,String,Rsa,Type Conversion,我正在修补RSA数据签名 我使用的是纯文本字符串,我将其转换为字节数组。然后生成私有证书,对字节数组进行签名,然后生成公钥 接下来,我将使用相同的字节数组来验证签名 但我想在两个步骤之间将签名转换为字符串-想法是稍后将其附加到正在签名的文件中 static void TestSigning(string privateKey) { string data = "TEST_TEST-TEST+test+TEst"; Console.WriteLine("==

我正在修补RSA数据签名

我使用的是纯文本字符串,我将其转换为字节数组。然后生成私有证书,对字节数组进行签名,然后生成公钥

接下来,我将使用相同的字节数组来验证签名

但我想在两个步骤之间将签名转换为字符串-想法是稍后将其附加到正在签名的文件中

static void TestSigning(string privateKey)
    {
        string data = "TEST_TEST-TEST+test+TEst";
        Console.WriteLine("==MESSAGE==");
        Console.WriteLine(data);
        byte[] dataByte = Encoding.Unicode.GetBytes(data);
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.FromXmlString(privateKey);
            var publicKey = rsa.ToXmlString(false);
            byte[] signature = rsa.SignData(dataByte, CryptoConfig.MapNameToOID("SHA512"));
            string signatureString = Encoding.Unicode.GetString(signature);
            byte[] roundtripSignature = Encoding.Unicode.GetBytes(signatureString);
            Console.WriteLine("==TEST==");
            Console.WriteLine(signature.Length.ToString());
            Console.WriteLine(roundtripSignature.Length.ToString());
            using (var checkRSA = new RSACryptoServiceProvider())
            {
                checkRSA.FromXmlString(publicKey);
                bool verification = checkRSA.VerifyData(
                    dataByte, 
                    CryptoConfig.MapNameToOID("SHA512"),
                    roundtripSignature);
                Console.WriteLine("==Verification==");
                Console.WriteLine(verification.ToString());
                Console.ReadKey();
            }
        }
    }
现在是有趣的部分 如果我使用UTF8编码,我会得到不同长度的字节数组

256是原始尺寸

484是往返票

UTF7也返回不同的大小 256对679

ASCII和Unicode都返回正确的大小256 vs 256

我试过使用

var sb = new StringBuilder();
        for (int i = 0; i < signature.Length; i++)
        {
            sb.Append(signature[i].ToString("x2"));
        }
var sb=new StringBuilder();
for(int i=0;i
去拿绳子。然后我使用Encoding.UTF8.GetBytes()方法

这次我得到了以下尺寸: 256对512 如果我从toString()中删除格式,我会得到: 256对670

签名验证始终失败。 如果我使用“签名”而不是roundtripSignature,效果很好


我的问题是:为什么尽管使用了相同的编码类型,我还是得到了不同的字节数组和字符串?这种转换不应该是无损的吗?

Unicode不是一个好的选择,因为至少,\0、CR、LF(以及其他控制代码)会把事情搞砸。(有关更多信息,请参阅)


正如@JamesKPolk所说,您需要使用合适的二进制到文本编码。Base64和hex/Base16是最常见的,但也有。

加密正在进行打包,因此数据中的重复位是压缩的。因此,在MSB设置为零的情况下使用UTF7将更改文件大小。是的,无论您正在进行何种编码,在过程的开始和结束时,未加密的数据大小都应该相同。您应该能够打开xml文本文件,看看有什么区别可以帮助隔离问题。签名字节不是任何字符集的编码,因此您的方法不可靠。将加密输出转换为字符串的标准方法是base64编码。@JamesKPolk谢谢!就这样。这么简单的解决方案,我却找不到。不知何故,我假设这些集合的每个位组合都有一个字符。