title: Compression and encryption SOAP - ASP.NET web service
body: <p>I need advice. I zip and crypt SOAP message on web service and client side. </p>
  
  <p>Client is winforms app.</p>
  
  <p>If I only crypt SOAP message, it works good. </p>
  
  <p>If I only zip SOAP message it also works good.</p>
  
  <p>I use SOAP extension on crypt and zip SOAP.</p>
  
  <p>I use  AES - Advanced Encryption Standard - Rijndael and on compresion I use SharpZipLib from <a href="http://sourceforge.net/projects/sharpdevelop/" rel="nofollow noreferrer">http://sourceforge.net/projects/sharpdevelop/</a>.</p>
  
  <p>The problem is  I send dataset on client.</p>
  
  <ol>
  <li><p>Firstly I zip and  secondly encrypt SOAP on web service side.</p></li>
  <li><p>Send on client.</p></li>
  <li><p><strong>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.</strong></p></li>
  </ol>
  
  <p>Here is the code, where I load XML from stream:</p>
  
  <pre><code>        var doc = new XmlDocument();
          using (var reader = new XmlTextReader(inputStream))
          {
              doc.Load(reader);
          }
  </code></pre>
  
  <p>Any advice ? Thank you...</p>
  
  <p>Here are methods on web service side which zip and crypt SOAP :</p>
  
  <pre><code>    //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 &gt; 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;
              }
  
      }
  </code></pre>
  
  <p>Here is a code on client side which decrypt and uzip SOAP :</p>
  
  <pre><code>   //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 &gt; 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 &gt; 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;
      }
  </code></pre>
  
  <p><strong>strong text</strong></p>