加密后的XML中的非法十六进制字符解密

时间:2014-07-03 11:10:30

标签: c# .net xml wcf security

我出于某些原因使用双向加密手动加密WCF消息,我不能使用WCF的默认内置安全机制。

没有加密,一切正常,但加密后,我在WCF XML消息中看到一些非法字符。

如果我使用正则表达式删除这些非法字符,即使使用加密,一切也能正常工作。

问题:

我的加密有什么问题?

加密

    public override ArraySegment<Byte> WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
    {
        Int32 messageLength;

        Byte[] messageBytes;

        using (MemoryStream unEncryptedXmlStream = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(unEncryptedXmlStream))
            {
                message.WriteMessage(writer);
            }

            using (Rijndael crypObj = Rijndael.Create())
            {
                crypObj.IV = UTF8Encoding.Default.GetBytes("1234567890123456");
                crypObj.Key = UTF8Encoding.Default.GetBytes("1234567890123456");

                using (MemoryStream encryptedStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(encryptedStream, crypObj.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        unEncryptedXmlStream.Position = 0;

                        cryptoStream.Write(unEncryptedXmlStream.ToArray(), 0, (Int32)unEncryptedXmlStream.Length);

                        cryptoStream.FlushFinalBlock();

                        messageBytes = encryptedStream.ToArray();

                        messageLength = (Int32)encryptedStream.Position;
                    }
                }
            }
        }

        Int32 totalLength = messageLength + messageOffset;

        Byte[] totalBytes = bufferManager.TakeBuffer(totalLength);

        Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);

        ArraySegment<Byte> byteArray = new ArraySegment<Byte>(totalBytes, messageOffset, messageLength);

        return byteArray;
    }

解密

    public override Message ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType)
    {
        Stream encryptedXmlStream = stream;

        XElement reader = null;

        encryptedXmlStream.Position = 0;

        using (Rijndael crypObj = Rijndael.Create())
        {
            crypObj.IV = UTF8Encoding.Default.GetBytes("1234567890123456");
            crypObj.Key = UTF8Encoding.Default.GetBytes("1234567890123456");

            using (CryptoStream cryptoStream = new CryptoStream(encryptedXmlStream, crypObj.CreateDecryptor(), CryptoStreamMode.Read))
            {
                Byte[] buffer = new Byte[(Int32)encryptedXmlStream.Length];

                cryptoStream.Read(buffer, 0, (Int32)encryptedXmlStream.Length);

                //reader = XElement.Parse(Encoding.UTF8.GetString(buffer)); // exception

                reader = XElement.Parse(CleanInvalidXmlChars(Encoding.UTF8.GetString(buffer))); // everything works fine again, even with encryption & decryption
            }
        }

        String action = reader.Descendants()
            .First(element => element.Name.LocalName == "Action").Value;

        return Message.CreateMessage(MessageVersion, action, reader.Descendants()
            .First(element => element.Name.LocalName == "Body").Elements().Single().CreateReader());
    }

删除非法字符:

    private static String CleanInvalidXmlChars(String input)
    {
        String pattern = @"[^\x09\x0A\x0D\x20-\xD7FF\xE000-\xFFFD\x10000-x10FFFF]";
        return Regex.Replace(input, pattern, "");
    }

易于调试和测试控制台应用程序:

https://drive.google.com/file/d/0B8_dFKbcEQ47b2VnSG0zcTZiRlk/edit?usp=sharing

要下载,请按Ctrl + S

提前致谢

1 个答案:

答案 0 :(得分:1)

撇开您的安全方法,核心问题是您无法在XML文档中拥有所需的所有字符。要解决此问题,您应该在写入XML(example)之前在Base64中对加密文本进行编码。不要使用任何正则表达式,因为这会更改密码文本,这意味着您将无法对其进行解密。

发件人

  • 加密邮件(string - &gt; byte[]
  • Base64编码(byte[] - &gt; string
  • 写入xml

接收机

  • 从xml(string
  • 中读取
  • 从Base64解码(string - &gt; byte[]
  • 解密(byte[] - &gt; string