views:

430

answers:

1

Hi everybody. I need advice. I zip and crypt SOAP message on web service and client side.

Client is winforms app.

If I only crypt SOAP message, it works good.

If I only zip SOAP message it also works good.

I use SOAP extension on crypt and zip SOAP.

I use AES - Advanced Encryption Standard - Rijndael and on compresion I use SharpZipLib from http://sourceforge.net/projects/sharpdevelop/.

The problem is I send dataset on client.

  1. Firstly I zip and secondly encrypt SOAP on web service side.

  2. Send on client.

  3. On client side I load XML from stream. But it finish with this error : Data at the root level is invalid. Line 1, position 2234.

Here is the code, where I load XML from stream:

        var doc = new XmlDocument();
        using (var reader = new XmlTextReader(inputStream))
        {
            doc.Load(reader);
        }

Any advice ? Thank you...

Here are methods on web service side which zip and crypt SOAP :

    //encrypt string
    private static string EncryptString(string @string, string initialVector, string salt, string password,
                         string hashAlgorithm, int keySize, int passwordIterations)
    {
        byte[] initialVectorBytes = Encoding.ASCII.GetBytes(initialVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(@string);

        var derivedPassword = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, passwordIterations);
        byte[] keyBytes = derivedPassword.GetBytes(keySize / 8);
        var symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initialVectorBytes);

        using (var memStream = new MemoryStream())
        {
            var cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();

            var serializer = new XmlSerializer(typeof(byte[]));
            var sb = new StringBuilder();
            TextWriter writer = new StringWriter(sb);
            serializer.Serialize(writer, memStream.ToArray());
            writer.Flush();

            var doc = new XmlDocument();
            doc.LoadXml(sb.ToString());
            if (doc.DocumentElement != null) return doc.DocumentElement.InnerXml;
        }
        return "";
    }

    //zip string
    private static byte[] ZipArray(string stringToZip)
    {
        byte[] inputByteArray = Encoding.UTF8.GetBytes(stringToZip);
        var ms = new MemoryStream();

        // SharpZipLib.Zip,
        var zipOut = new ZipOutputStream(ms);
        var zipEntry = new ZipEntry("ZippedFile");
        zipOut.PutNextEntry(zipEntry);


        zipOut.SetLevel(7);
        zipOut.Write(inputByteArray, 0, inputByteArray.Length);
        zipOut.Finish();
        zipOut.Close();

        return ms.ToArray();
    }


    //zip and encrypt SOAP
    public virtual Stream OutSoap(string[] soapElement, Stream inputStream)
    {

            #region Load XML from SOAP

            var doc = new XmlDocument();

            using (XmlReader reader = XmlReader.Create(inputStream))
            {
                doc.Load(reader);
            }

            var nsMan = new XmlNamespaceManager(doc.NameTable);
            nsMan.AddNamespace("soap",
                               "http://schemas.xmlsoap.org/soap/envelope/");

            #endregion Load XML from SOAP

            #region Zip SOAP

            XmlNode bodyNode = doc.SelectSingleNode(@"//soap:Body", nsMan);

            bodyNode = bodyNode.FirstChild.FirstChild;

            while (bodyNode != null)
            {
                if (bodyNode.InnerXml.Length > 0)
                {
                    // Zip
                    byte[] outData = ZipArray(bodyNode.InnerXml);

                    bodyNode.InnerXml = Convert.ToBase64String(outData);

                }
                bodyNode = bodyNode.NextSibling;
            }

            #endregion Zip SOAP

            #region Crypt SOAP

            foreach (string xPathQuery in soapElement)
            {
                XmlNodeList nodesToEncrypt = doc.SelectNodes(xPathQuery, nsMan);
                if (nodesToEncrypt != null)
                    foreach (XmlNode nodeToEncrypt in nodesToEncrypt)
                    {
                        //Encrypt
                        nodeToEncrypt.InnerXml = EncryptString(nodeToEncrypt.InnerXml,
                                                               user.IV, user.Salt, user.Password, user.HashType,
                                                               user.KeySize, user.PasswordIterations);
                    }
            }

            #endregion Crypt SOAP

            inputStream.Position = 0;
            var settings = new XmlWriterSettings { Encoding = Encoding.UTF8 };
            using (XmlWriter writer = XmlWriter.Create(inputStream, settings))
            {

                 doc.WriteTo(writer);
                 return inputStream;
            }

    }

Here is a code on client side which decrypt and uzip SOAP :

   //decrypt string
   private static string DecryptString(string @string, string initialVector, string salt, string password,
                         string hashAlgorithm, int keySize, int passwordIterations)
    {
        byte[] initialVectorBytes = Encoding.ASCII.GetBytes(initialVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt);
        byte[] cipherTextBytes = Convert.FromBase64String(@string);

        var derivedPassword = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, passwordIterations);
        byte[] keyBytes = derivedPassword.GetBytes(keySize / 8);
        var symmetricKey = new RijndaelManaged { Mode = CipherMode.CBC };
        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initialVectorBytes);

        using (var memStream = new MemoryStream(cipherTextBytes))
        {
            var cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read);

            var plainTextBytes = new byte[cipherTextBytes.Length];
            int byteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

            return Encoding.UTF8.GetString(plainTextBytes, 0, byteCount);
        }
    }


    //unzip string
    private static byte[] UnzipArray(string stringToUnzip)
    {

        byte[] inputByteArray = Convert.FromBase64String(stringToUnzip);
        var ms = new MemoryStream(inputByteArray);
        var ret = new MemoryStream();

        // SharpZipLib.Zip
        var zipIn = new ZipInputStream(ms);
        var theEntry = zipIn.GetNextEntry();
        var buffer = new Byte[2048];
        int size = 2048;

        while (true)
        {
            size = zipIn.Read(buffer, 0, buffer.Length);
            if (size > 0)
            {
                ret.Write(buffer, 0, size);
            }
            else
            {
                break;
            }
        }
        return ret.ToArray();
    }


    public virtual Stream  InSoap(Stream inputStream, string[] soapElement)
    {

        #region Load XML from SOAP

        var doc = new XmlDocument();
        using (var reader = new XmlTextReader(inputStream))
        {
            doc.Load(reader);
        }
        var nsMan = new XmlNamespaceManager(doc.NameTable);
        nsMan.AddNamespace("soap",
                           "http://schemas.xmlsoap.org/soap/envelope/");

        #endregion Load XML from SOAP


        #region Decrypt SOAP

        foreach (string xPathQuery in soapElement)
            {
                XmlNodeList nodesToEncrypt = doc.SelectNodes(xPathQuery, nsMan);
                if (nodesToEncrypt != null)
                    foreach (XmlNode nodeToEncrypt in nodesToEncrypt)
                    {
                        nodeToEncrypt.InnerXml = DecryptString(nodeToEncrypt.InnerXml, saltPhrase, passwordPhrase, initialVector,
                                          hashAlgorithm, passwordIterations, keySize);
                    }
            }

         #endregion Decrypt SOAP

         #region UnZip SOAP

         XmlNode node = doc.SelectSingleNode("//soap:Body", nsMan);
         node = node.FirstChild.FirstChild;


         while (node != null)
            {
                if (node.InnerXml.Length > 0)
                {

                    byte[] outData = UnzipArray(node.InnerXml);
                    string sTmp = Encoding.UTF8.GetString(outData);

                    node.InnerXml = sTmp;
                }

                node = node.NextSibling;
            }

         #endregion UnZip SOAP

        var retStream = new MemoryStream();
        doc.Save(retStream);
        return retStream;
    }

strong text

A: 

I'm not sure why your unencrypted xml won't parse, but I think you're first step should be to dump the decrypted data to the terminal to see exactly what text you're getting back. Perhaps the process corrupts your data somehow, or you have an encoding issue.

Alternatively, you could configure your server to use https and gzip compression to achieve the same goal. You won't loose any security with this approach and this is by far the more standard way to do things. You can also have a look at MS's support for the WS-Security standard

Dana the Sane