8

Encrypting and Decrypting Soap Data

 

This chapter dapples with Encrypting and Decrypting Soap Headers. It presupposes that you would possess some basic knowledge of the elements contained in an XML document. To put it precisely, it expects you to be cognizant of the process of accessing the contents of the nodes that constitute an XML document. This is for the reason that a SOAP payload is merely an XML document consisting of nodes, which in turn, also have nodes. These nodes are required to be accessed prior to modifying their contents.

 

The opening program in this chapter elucidates and establishes how you can gain access to a node in an XML file, in order to extract the relevant information from it. We have created a new directory named ddd in the root, and created the following two files in this directory:

 

a.cs

using System;

using System.IO;

using System.Xml;

public class zzz

{

public static void Main()

{

FileStream s = new FileStream("a.txt", FileMode.Open, FileAccess.Read);

XmlTextReader r = new XmlTextReader (s);

XmlDocument d = new XmlDocument();

d.Load(r);

XmlNamespaceManager m = new XmlNamespaceManager(d.NameTable);

m.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode n;

n = d.SelectSingleNode("//soap:Body", m);

System.Console.WriteLine(n.InnerText + " " + n.Name);

n = n.FirstChild;

System.Console.WriteLine(n.InnerText + " " + n.Name);

n = d.SelectSingleNode("//soap:Body", m);

n = n.FirstChild.FirstChild;

System.Console.WriteLine(n.InnerText + " " + n.Name);

}

}

 

a.txt

<?xml version="1.0" encoding="utf-8" ?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<soap:Body>

<abcResponse xmlns="http://tempuri.org/">

<abcResult>vijay mukhi</abcResult>

</abcResponse>

</soap:Body>

</soap:Envelope>

 

Compile the .cs file using the csc compiler, and then, run the executable. The output generated is shown below.

 

Output

vijay mukhi soap:Body

vijay mukhi abcResponse

vijay mukhi abcResult

 

This program kicks-off and gets going by creating object 's', which is an instance of a FileStream class. This constructor accepts three parameters:

•     The name of the file - a.txt,

•     The mode to decide whether the File should be created or not - FileMode.Open

•     Whether the file is to be opened for reading or writing - FileAccess.Read.

 

The file a.txt is a clone of one of the SOAP responses received earlier by the client from the server.

 

Now, in order to access specific parts of the SOAP response packet, an object r of type XmlTextReader is created.  The XmlTextReader class requires either a Stream object or a class derived from the Stream class as a parameter. Hence, the constructor is supplied with the FileStream object 's'.

 

Once we have introduced a class that can read our XML file from disk, we require the services of another class named XmlDocument, which shall facilitate access to this XML file. The Load function in the XmlDocument object d is passed an XmlTextReader object. Now, when the object d is used, it allows access to each individual node in the file.

 

Every XML Document has a NameTable object, which stores the names of the elements and attributes, in the form of atomized strings. The data type of the NameTable is XmlNameTable.

 

The XmlNamespaceManager class deals with namespaces, which is perfectly suited to our requirement. The constructer is given a NameTable property as a parameter. The namespace prefixes are associated with the URIs using this Namespace manager. On a perusal of the a.txt file, you would notice that all the elements are prefaced by the namespace 'soap', which has a URI of http://schemas.xmlsoap.org/soap/envelope/. Therefore, this pair must be registered with the Namespace manager.

 

The XmlNode object is used to represent a node in the XML file. The SelectSingleNode function in the object is employed to return the first node for the specified parameter. In this case, the first node is returned as 'Body', with a namespace prefix of 'soap'. The second parameter to the function is the namespace manager 'm', which is conversant with the 'soap' namespace prefix. In order to verify the outcome of our actions so far, we display the InnerText and the Name properties of the node that we are currently pointing to.

 

The InnerText property provides the final content, which could include the child elements; while the Name property provides the full name, including the namespace prefix soap. Thus, the InnerText  is 'vijay mukhi', and the Name is 'soap:Body'.

 

Each node is blessed with children and grandchildren. The FirstChild property provides a handle to the first child, abcResponse. The InnerText property offers the same answer as before, i.e. 'vijay mukhi', since the node of abcResult contains this text. In order to access the grandchild abcResult, the FirstChild of the abcResponse node is employed. We have printed out its name for the purpose of verification.  Thus, we now have a mechanism to access the different nodes embodied in the XML file.

 

a.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

public class zzz

{

public static void Main()

{

string s;

s = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n<soap:Body><abcResponse xmlns=\"http://tempuri.org/\">\n<abcResult>vijay mukhi</abcResult>\n </abcResponse></soap:Body></soap:Envelope>";

byte[] ms = Encoding.UTF8.GetBytes(s);

MemoryStream ms1 = new MemoryStream(ms);

XmlTextReader r = new XmlTextReader(ms1);

XmlDocument d = new XmlDocument();

d.Load(r);

XmlNamespaceManager m = new XmlNamespaceManager(d.NameTable);

m.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode n;

n = d.SelectSingleNode("//soap:Body", m);

n = n.FirstChild;

System.Console.WriteLine(n.InnerText + " " + n.Name);

}

}

 

Output

vijay mukhi abcResponse

 

This example is at a slight variance with the earlier one. Instead of opening a file containing the xml code, it now contains a String s, which represents the entire XML file.

 

The string has to be converted into an array of bytes. To achieve this, we utilise the static GetBytes function. The array of bytes received from the function, is then supplied to the MemoryStream constructor.

 

The MemoryStream class, derived from the Stream object, represents a stream in memory, and not on disk. Thus, we are entitled to supply the MemoryStream object to the XmlTextReader constructor. The rest of the program is identical to the earlier one.

 

a.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

public class zzz

{

public static void Main()

{

string s;

s = "ABC";

byte[] ms = Encoding.UTF8.GetBytes(s);

MemoryStream ms1 = new MemoryStream(ms);

byte[] ms2 = ms1.ToArray();

StringBuilder s1 = new StringBuilder();

for(int i=0; i<ms2.Length; i++)

{

if(i==(ms2.Length-1))

s1.Append(ms2[i]);

else

s1.Append(ms2[i] + " ");

}

Console.WriteLine(s1);

}

}

 

Output

65 66 67

 

In the above program, a string variable 's' is initialized to ABC. Now, we intend to convert the string into an array of bytes. For this, we use the GetBytes function. The output is stored in the byte array called 'ms'. This byte array represents our string. It is thereafter, supplied to a MemoryStream object named 'ms1'.

 

After having converted the string into a stream, we embark on the reverse procedure, i.e. we use the ToArray function of the MemoryStream class, to convert a stream back into an array of bytes. Thereafter, the StringBuilder class is used to display this array.

 

The byte array has a size of 3, since the string has three characters. Now, using the 'for' loop, the individual strings are appended to the StringBuilder object s1, thereby, concatenating all of them. Since we desire to insert a space between the individual numbers, an extra space is subjoined while adding the number to the StringBuilder object. However, no space is added after the last character. Finally, the three numbers, along with the spaces, are displayed using the WriteLine function with s1 .

 

Having grappled with these essentials, we now progress onto the very heart of the chapter, i.e. Encryption and Decryption.

 

 

DES is an acronym for Data Encryption Standard. It is one of the most widely used standards for encryption. Other symmetric algorithms, such as RC2, also exist.

 

Symmetric algorithms use the same key or password for encryption and decryption; while the Asymmetric algorithms, such as private key and public key, use different passwords or keys for encryption and decryption. A password and key are synonyms, wherein, passwords are English-like and can easily be committed to the memory; however, keys cannot be memorized.

 

One of the most widely used techniques in the world of security is authentication of messages, where algorithms like MD5 or Message Digest 5 are implemented. On the basis of the message text, a MD5 hash number is generated for the document. This document is then sent across the wire, along with the number in an encrypted form. In the event of a single byte of the file being tampered with, the hash would change, thereby, apprising the receiver of the fact that the document has been modified in transit.

 

Given below is an example of DES, where bytes are encrypted and the new value is displayed.

 

a.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

using System.Security.Cryptography;

public class zzz

{

public static void Main()

{

Byte[] k = {1, 2, 3, 4, 5, 6, 7 , 8};

Byte[] k1 = {4,5,6,7,8,9,10,11};

DESCryptoServiceProvider d = new DESCryptoServiceProvider();

MemoryStream ms1 = new MemoryStream();

CryptoStream s = new CryptoStream (ms1, d.CreateEncryptor( k, k1 ), CryptoStreamMode.Write);

byte[] b = Encoding.UTF8.GetBytes("ABCD");

s.Write(b, 0,b.Length);

s.FlushFinalBlock();

byte[] b1 = ms1.ToArray();

StringBuilder s1 = new StringBuilder();

for(int i=0; i<b1.Length; i++)

{

if(i==(b1.Length-1))

s1.Append(b1[i]);

else

s1.Append(b1[i] + " ");

}

Console.WriteLine(s1);

}

}

 

Output

96 216 128 107 226 104 164 58

 

We commence by creating an object of type DESCryptoServiceProvider, which is in the namespace of System.Security.Cryptography. This namespace has infinite classes for encoding and decoding data, hashing, generating random numbers, et al. The class DESCryptoServiceProvider is the only pathway granting access to the classes that deal with the DES standard.

 

Therefore, we first create an object of type DESCryptoServiceProvider, and then, set up a memory stream. To comprehend DES, we also need to create an object 's', of the class CryptoStream. The constructor of this class is supplied with three parameters.

 

The first parameter is a stream, which shall hold the results of the encryption. Since we are not too keen on saving this output to a file on disk, we have specified a memory stream named 'ms1'.

 

The second parameter is of type ICryptoTransform. The value specified here determines the cryptographic transform that is required to be carried out. One such value that can be specified is 'hashing'. The CreateEncryptor function in object 'd', accepts two parameters:

•     An 8-byte key or password in k

•     An 8-byte initialization in k1.

 

In real life, the password should be larger, and should normally contain some random digits. Thus, the output generated would be used to encrypt the string "ABCD".

 

The last parameter is an enum CryptoStreamMode that can take either of the two values, Read or Write. As we wish to write into the stream, the value given here is CryptoStreamMode.Write.

 

The string "ABCD" is then converted into an array of bytes. This is because, in the .Net world, an array of bytes is given preference over a string. As humans, we love to work with strings, but here, who pays heed to our preferences? The array is then written to the CryptoStream, using the Write function. There are three parameters to the Write function:

•     The byte array b.

•     The starting point.

•     The length of the byte array.

 

As always, the bytes are flushed.

 

The next task is to ascertain the contents of the MemoryStream object ms1, which was passed to the constructer of the CryptoStream class. ms1 now contains the string "ABCD" in its encrypted form.

 

To do so, the function ToArray of the Memory Stream is utilized to return the data that it contains, in the form of a series of bytes. The output displayed is the encrypted form of the string "ABCD". Since we wish to insert a space between each number that is displayed, we pursue an approach similar to the one that we had adopted earlier, in the case of the StringBuilder class. The encrypted form of the string "ABCD" is displayed, along with the spaces that we have inserted.

 

a.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

using System.Security.Cryptography;

public class zzz

{

public static void Main()

{

Byte[] k = {1, 2, 3, 4, 5, 6, 7 , 8};

Byte[] k1 = {4,5,6,7,8,9,10,11};

DESCryptoServiceProvider des = new DESCryptoServiceProvider();

string s = "96 216 128 107 226 104 164 58";

char[] c = {' '};

string[] ss = s.Split(c);

byte[] b = new byte[ss.Length];

for(int i=0; i<b.Length; i++)

{

b[i] = Byte.Parse(ss[i]);

}

MemoryStream ms = new MemoryStream();

CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor ( k, k1 ), CryptoStreamMode.Write);

cs.Write(b, 0,b.Length);

cs.FlushFinalBlock();

byte [] b2 = ms.ToArray();

string s1 = Encoding.UTF8.GetString(b2);

Console.WriteLine(s1);

}

}

 

Output

ABCD

 

This program, in a sense, is a continuation of the earlier program. The encrypted data is now decrypted, using the DES standards.

 

The string 's' is initialized to the encrypted form of the string "ABCD", as displayed in the earlier program. Since the spaces are also part of the string, the first task is to get rid of these spaces. They were inserted in the earlier program, for visual clarity of the numbers. In order to remove these spaces, we have created a single byte array of chars, containing only one character, i.e. 'space'.

 

The 'split' function that is part of the String class, accepts one parameter, and splits a string on the occurrence of a specific character or characters, in the array of chars. In our case, the string is split into 8 strings, since there are a total of 7 spaces. These 8 numbers are accommodated in a new string array named 'ss'.

 

Finally, we need to copy these 8 strings into the array of bytes named 'b'. The Byte class has a static Parse function, which converts a string stored in an array location into a byte.

 

Thereafter, just like before, a memory stream object ms is created to contain the new value in the memory. The CryptoStream object 'cs' is created, but it now employs the CreateDecryptor function, since we want to decrypt the content’s. The last enum parameter is Write, because we intend to write the decrypted string to the memory stream.

 

The Write function in the CryptoStream class obtains the array of bytes from the byte array containing the encrypted data, and then, uses the DES standard to decrypt it.

 

As we are keen on witnessing the outcome of our actions, we convert the Memory Stream object ms into a byte array 'b2', and then, use the GetString function to convert this byte array into a string.

 

The output reveals the string "ABCD", thus proving beyond doubt, that the string "ABCD" was encrypted into some unintelligible mumbo-jumbo using DES, and thereafter, the mumbo-jumbo was decrypted back to the string "ABCD".

           

a.aspx

<HTML>

<HEAD>

<script language="c#" runat=server>

public void Page_Load()

{

zzz a = new zzz();

l.InnerHtml = a.abc();

}

</script>

</HEAD>

<BODY>

<b id="l" runat="server"/>

</HTML>

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod]

[vijay]

public string abc()

{

return "ABCD";

}

}

 

aaa.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Security.Cryptography;

[AttributeUsage(AttributeTargets.Method)]

public class vijay : SoapExtensionAttribute

{

public override Type ExtensionType

{

get

{

return typeof(mukhi);

}

}

public override int Priority

{

get

{

return 0;

}

set

{

}

}

}

public class mukhi : SoapExtension

{

Stream o;

Stream n;

Byte[] k = {1, 2, 3,4,5, 6, 7 , 8};

Byte[] k1 = {4,5,6,7,8,9,10,11};

public override object GetInitializer(LogicalMethodInfo m, SoapExtensionAttribute a)

{

return a;

}

public override object GetInitializer(Type t)

{

return typeof(vijay);

}

public override void Initialize(object i)

{

return;

}

public override void ProcessMessage(SoapMessage m)

{

if ( m.Stage == SoapMessageStage.BeforeDeserialize)

{

abc("BeforeDeserialize");

TextReader r = new StreamReader(o);

TextWriter w = new StreamWriter(n);

w.WriteLine(r.ReadToEnd());

w.Flush();

n.Position = 0;

}

if ( m.Stage == SoapMessageStage.AfterSerialize)

{

abc("AfterSerialize " + n.Position);

n.Position = 0;

XmlTextReader rr = new XmlTextReader(n);

XmlDocument d1 = new XmlDocument();

d1.Load(rr);

XmlNamespaceManager nm = new XmlNamespaceManager(d1.NameTable);

nm.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode no = d1.SelectSingleNode("//soap:Body", nm);

abc(no.Name + " " + no.InnerText);

no = no.FirstChild.FirstChild;

abc(no.Name + " " + no.InnerText);

DESCryptoServiceProvider de = new DESCryptoServiceProvider();

byte[] inp = Encoding.UTF8.GetBytes(no.InnerText);

MemoryStream ms1 = new MemoryStream();

CryptoStream cs = new CryptoStream(ms1, de.CreateEncryptor( k, k1 ), CryptoStreamMode.Write);

abc("Memory Stream Before" + ms1.Position);

cs.Write(inp, 0, inp.Length);

abc("Memory Stream Before" + ms1.Position);

cs.FlushFinalBlock();

abc("Memory Stream Before" + ms1.Position);

byte[] ou = ms1.ToArray();

string s1 = "";

abc(ou.Length.ToString());

for(int i = 0; i< ou.Length ; i++)

s1 = s1 + ou[i].ToString();

no.InnerText = s1;

abc(ou[0].ToString());

abc(s1);

MemoryStream ms = new MemoryStream();

d1.Save(ms);

abc("Position of ms " + ms.Position );

ms.Position = 0;

n = ms;

TextReader r1 = new StreamReader(n);

TextWriter w2 = new StreamWriter(o);

string s3 = r1.ReadToEnd();

w2.WriteLine(s3);

abc(s3);

w2.Flush();

}

}

public override Stream ChainStream( Stream stream )

{

o = stream;

n = new MemoryStream();

return n;

}

public void abc(string s)

{

FileStream fs = new FileStream("c:\\a.txt", FileMode.Append, FileAccess.Write);

StreamWriter w = new StreamWriter(fs);

w.WriteLine(s);

w.Flush();

w.Close();

}

}

 

SOAP response

<abcResponse xmlns="http://tempuri.org/">

<abcResult>9621612810722610416458</abcResult>

</abcResponse>

 

Browser Output

9621612810722610416458

 

a.txt

BeforeDeserialize

AfterSerialize 360

soap:Body ABCD

abcResult ABCD

Memory Stream Before0

Memory Stream Before0

Memory Stream Before8

8

96

9621612810722610416458

Position of ms 381

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abcResponse xmlns="http://tempuri.org/">

      <abcResult>9621612810722610416458</abcResult>

    </abcResponse>

  </soap:Body>

</soap:Envelope>

 

The above program is a protracted one, but all the same, it is absorbing, since it demonstrates the actions on the server-side, during encryption of a string value, which is to be dispatched to the client. It is our humble advice to you to ensue the steps outlined by us, while running this program. It is because, we are of the firm opinion that it is the safest and the most steadfast pathway, steering clear of any perplexity in understanding the concept.

 

The aspx file calls a function abc from the class zzz. The return value of this function is passed to the InnerHtml property of the bold element, which has an id of l. At this stage, we cannot run this aspx file in the browser, since no class named zzz exists in the bin folder. We will not create this zzz class; instead, we shall task the asmx file with this errand.

 

The asmx file has a function named abc, which returns the string ABCD. In addition to this, an attribute of 'vijay' is added to it. Since no code for 'vijay' is available at the moment, we get an error on loading the asmx. Hence, the WSDL file is not created.

 

Error

Compiler Error Message: CS0246: The type or namespace name 'vijay' could not be found (are you missing a using directive or an assembly reference?)

 

So, comment out the attribute 'vijay', and reload the asmx file.

 

[WebMethod]

//[vijay]

public string abc()

{

return "ABCD";

}

 

Save the wsdl contents in a file named aa.wsdl in the bin folder, and not in wwwroot folder. Add the port number 8080 to the localhost, and then, run the batch file named a.bat. This will create a dll named zzz.dll, which contains the code of the class zzz.

 

a.bat

cd \inetpub\wwwroot\bin

wsdl aa.wsdl

csc /t:library zzz.cs

 

Run the trace utility from the Soap Toolkit, if it is not already active, and then, in the browser window, load the aspx file as :

 

http://localhost/a.aspx

 

The browser window will display the string "ABCD". Further, the SOAP response packet will display the value of "ABCD", which is being sent across.

 

Now, instead of sending the string "ABCD" in its pristine form, we wish the server to encrypt it, and then, send it across to the browser.

 

To accomplish this, the attribute of 'vijay' is utilised. Remove the comments from the attribute 'vijay' in the a.asmx file, and thereafter, create the file aaa.cs in the bin folder. Now, compile the code in this file, and you will obtain a dll file.

 

\inetpub\wwwroot\bin>csc /t:library aaa.cs

 

Now, reload the asmx file to create the wsdl file. Change the port number to 8080 and run the batch file.

 

In aaa.cs, there exist a large number of 'using' statements. Although, quite a few of them are redundant, with no utility at all, the one positive aspect of a few extra statements strewn around is that, their presence is innocuous. The Attribute AttributeUsage restricts the use of the attribute 'vijay' only on methods.

 

Next, we create the actual attribute class 'vijay', derived from SoapExtensionAttribute. The code in this class is not substantial, except for the read-only property of ExtensionType, which returns the class 'mukhi'. The class 'vijay' handles the parameters that are passed from the attribute that gets forwarded to the 'mukhi' class.

 

Let us now proceed and press onto the main code in the class 'mukhi', wherein, our primary focus shall be on the ProcessMessage function. In this function too, our main object of interest is the AfterSerialize event. This is because, the SOAP packet has already been created. The main task that remains to be accomplished is, the encryption of the response that is being sent over.

 

But prior to that, the stream object passed to the ChainStream function as a parameter is stored in a public Stream variable named 'o'. The data that is written to MemoryStream object o, would be utilized by SOAP every now and then. Thereafter, the Memory Stream object 'n' is initialized and supplied as the return value of the function.

 

Although we have no business to transact with the BeforeDeserialize event, the presence of this event is mandatory, since the Stream object 'n' would remain empty in its absence. This would result in the loss of the SOAP request data.

 

In the BeforeDeserialize event, a TextReader object 'r' is created, using the Stream object 'o'. Moreover, a TextWriter object 'w' is also created, using the empty MemoryStream 'n'.

 

The entire SOAP request that reads from the TextReader 'r', is then written to the Writer. If the Stream 'w' in not flushed, nothing could possibly be written. As the SOAP infrastructure expects the file pointer to be positioned at the beginning, this basic housekeeping activity is also performed in the BeforeDeserialize event. The function abc can be used to corroborate our actions at each stage.

 

The main task rests in the AfterSerialize event, where the entire SOAP response that has been generated, is initially read. As the file pointer is at byte 360 ( revealed by the function abc), the pointer is repositioned at the beginning, by setting the Position property to 0.

 

Here, an XmlTextReader object 'rr' is created from the Stream object 'n', and then, an Xml Document object 'd1' is instantiated. Thereafter, the Load function in the document class is used, to read the SOAP response 'rr' into the XmlDocument object. The namespace of 'soap' is added to the Namespace manager, along with its url. The object no of type XmlNode is then made to represent the first node body in the SOAP response.

 

The function abc displays the name of the node body and its content, using the properties of Name and InnerText. Since, the abcresult node is the only node of interest to us at this point in time, the value within FirstChild in the FirstChild member is used. The function abc prints the values, and we stand vindicated, since our stance has been verified.

 

Next, we create an instance of the wrapper class DESCryptoServiceProvider. A wrapper or helper class shields us from the trivia or the nitty-gritty of the class. These repugnant details are carefully wrapped up by this wrapper class.

 

The InnerText property of XmlNode contains the string that we desire to encrypt. Since it is in a string form, it has to be converted into an array of bytes. The GetBytes function converts the string into bytes, and thereafter, stores them into an array named 'inp'.

 

Now, arises the requirement of a MemoryStream object, which is to be provided to the CryptoStream class. The CryptoStream class is the class that is used to encrypt the bytes. The CryptoStream constructor takes three parameters, which are as follows:

•     The first parameter is the MemoryStream object.

•     The second parameter is the encryption that needs to be performed. Therefore, the function comprises of an 8-bye key in 'k', and a 8-byte initialization in 'k1'.

•     The third parameter is the mode which represents either a read or a write.

 

Once the CryptoStream object cs is created, we use the Write function to write the array 'inp', which accommodates the contents of the tag abcResult, in the byte form. The second parameter to the Write function is the incipient point in the array. A value of zero indicates the beginning of the array. The last parameter is the length of the array, which needs to be written. The FlushFinalBlock function is like the Flush function, which actually does the writing.

 

Now, the MemoryStream ms1 contains the encrypted bytes. The output of the function abc provides ample evidence of the fact that, although the Write function may be writing, it is actually the Flush function that writes the bytes to the MemoryStream.

 

The ToArray function is used to convert the encrypted bytes in the Memory Stream object, into an array of bytes. Now, this 8-byte array has to be converted into an ASCII string. So, we use a loop construct, wherein each and every byte of the array is concatenated to the string s1. This string, which is the encrypted version of our SOAP response, is then written to disk.

 

The InnerText property of the XmlNode is also initialized to this string, resulting in the initialization of the XML document.

 

The XML document is then saved in the MemoryStream object named 'ms'. This new MemoryStream contains the same XML file that the SOAP infrastructure had created. However, there is a minor variation here, i.e. the contents of abcResult tag are encrypted.

 

The File pointer in the new MemoryStream, which is at Position 381 due to the saving, is now repositioned at the beginning of the file. Then, the MemoryStream 'n' is equated to 'ms', and a new TextReader object is created.

 

The TextWriter object uses the stream 'o', since it is this stream that should contain the final SOAP payload. The stream 'o' in this event is used for writing the output that is to be sent across. The stream 'n' is used to read the SOAP packet that is generated.

 

The string s3 is used to store the SOAP response, which is read from the reader. Then subsequently, it is written out to the Writer, or to the Stream 'o'.

 

Yet another way of achieving this is, to read the bytes from the memory stream, convert them into a string, and then, to write them with the help of the w2 object. The string s3 substantiates the fact that, the SOAP response that is sent across, comprises of contents that are encrypted.

 

a.aspx

<HTML>

<HEAD>

<script language="c#" runat=server>

public void Page_Load()

{

zzz w = new zzz();

l.InnerHtml = w.abc("hi");

}

</script>

</HEAD>

<BODY>

<b id="l" runat="server"/>

</HTML>

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod]

[vijay(Enc=EM.Response,Dec=DM.Request)]

public string abc( string a)

{

return "vijay " + a;

}

}

 

zzz.cs

using System.Diagnostics;

using System.Xml.Serialization;

using System;

using System.Web.Services.Protocols;

using System.Web.Services;

[System.Web.Services.WebServiceBindingAttribute(Name="HelloWorldSoap", Namespace="http://tempuri.org/")]

public class zzz: System.Web.Services.Protocols.SoapHttpClientProtocol

{

public zzz()

{

this.Url = "http://localhost:8080/a.asmx";

}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/abc")]

[vijay(Enc=EM.Request,Dec=DM.Response)]

public string abc(string a)

{

object[] results = this.Invoke("abc", new object[]{a});

return ((string)(results[0]));

}

}

 

aaa.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Security.Cryptography;

[AttributeUsage(AttributeTargets.Method)]

public class vijay : SoapExtensionAttribute

{

EM emode= EM.None;

DM dmode= DM.None;

public override Type ExtensionType

{

get

{

return typeof(mukhi);

}

}

public override int Priority

{

get

{

return 0;

}

set

{

}

}

public EM Enc

{

get

{

return emode;

}

set

{

emode= value;

}

}

public DM Dec

{

get

{

return dmode;

}

set

{

dmode= value;

}

}

}

public enum DM

{

None,

Response,

Request

}

public enum EM

{

None,

Response,

Request

}

public class mukhi : SoapExtension

{

Stream o;

Stream n;

DM dmode;

EM emode;

Byte[] k = {1, 2, 3, 4, 5, 6, 7, 8};

Byte[] k1 = {10,11 , 12, 13, 14, 15, 16, 17};

public mukhi()

{

abc("Constructor");

}

public override object GetInitializer(LogicalMethodInfo m, SoapExtensionAttribute a)

{

abc("GetInitializer " + m.ToString());

return a;

}

public override object GetInitializer(Type t)

{

abc("GetInitializer 1");

return typeof(mukhi);

}

public override void Initialize(object i)

{

vijay a = (vijay) i;

dmode = a.Dec;

emode = a.Enc;

abc("Initialize " + i.ToString() + " " + a.Dec.ToString() + " " + a.Enc.ToString());

return;

}

public override void ProcessMessage(SoapMessage m)

{

if ( m.Stage == SoapMessageStage.AfterSerialize)

{

abc("AfterSerialize " + emode.ToString() + " " + n.Position );

n.Position = 0;

if ((emode == EM.Request) || (emode == EM.Response))

{

abc("AfterSerialize if");

n.Position = 0;

XmlTextReader rr = new XmlTextReader(n);

XmlDocument d1 = new XmlDocument();

d1.Load(rr);

XmlNamespaceManager nm = new XmlNamespaceManager(d1.NameTable);

nm.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode no = d1.SelectSingleNode("//soap:Body", nm);

no = no.FirstChild.FirstChild;

DESCryptoServiceProvider de = new DESCryptoServiceProvider();

abc(no.InnerText);

byte[] inp = Encoding.UTF8.GetBytes(no.InnerText);

MemoryStream ms1 = new MemoryStream();

CryptoStream cs = new CryptoStream(ms1, de.CreateEncryptor( k, k1 ), CryptoStreamMode.Write);

cs.Write(inp, 0, inp.Length);

cs.FlushFinalBlock();

byte[] ou = ms1.ToArray();

StringBuilder s = new StringBuilder();

for(int i=0; i<ou.Length; i++)

{

if(i==(ou.Length-1))

s.Append(ou[i]);

else

s.Append(ou[i] + " ");

}

no.InnerText = s.ToString();

MemoryStream ms = new MemoryStream();

d1.Save(ms);

ms.Position = 0;

n = ms;

}

TextReader r = new StreamReader(n);

TextWriter w = new StreamWriter(o);

string s5 = r.ReadToEnd();

abc(s5);

w.WriteLine(s5);

w.Flush();

}

if ( m.Stage ==  SoapMessageStage.BeforeDeserialize)

{

abc("BeforeDeserialize " + dmode.ToString());

MemoryStream ds = new MemoryStream();

if ((dmode == DM.Request) || (dmode == DM.Response))

{

abc("BeforeDeserialize if");

TextReader r = new StreamReader(o);

TextWriter w = new StreamWriter(ds);

string s6 = r.ReadToEnd();

w.WriteLine(s6);

abc(s6);

w.Flush();

abc("Position of ds " + ds.Position);

ds.Position = 0;

XmlTextReader r0 = new XmlTextReader(ds);

XmlDocument d1 = new XmlDocument();

d1.Load(r0);

XmlNamespaceManager nm = new XmlNamespaceManager(d1.NameTable);

nm.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode no = d1.SelectSingleNode("//soap:Body", nm);

no = no.FirstChild.FirstChild;

DESCryptoServiceProvider de = new DESCryptoServiceProvider();

string s3 = no.InnerText;

abc(s3);

char[] c = {' '};

string[] ss = s3.Split(c);

byte[] b = new byte[ss.Length];

abc(ss.Length.ToString());

for(int i=0; i<b.Length; i++)

{

b[i] = Byte.Parse(ss[i]);

}

byte[] inp = b;

MemoryStream ms1 = new MemoryStream();

CryptoStream cs = new CryptoStream(ms1,de.CreateDecryptor( k, k1 ), CryptoStreamMode.Write);

cs.Write(inp, 0, inp.Length);

cs.FlushFinalBlock();

byte[] ou = ms1.ToArray();

string s1 = Encoding.UTF8.GetString(ou);

no.InnerText = s1;

abc(s1);

MemoryStream ms = new MemoryStream();

if ( dmode == DM.Request)

d1.Save("c:\\z.txt");

else

d1.Save("c:\\y.txt");

d1.Save(ms);

ms.Position = 0;

TextReader r1 = new StreamReader(ms);

TextWriter w1 = new StreamWriter(n);

w1.WriteLine(r1.ReadToEnd());

w1.Flush();

}

else

{

abc("BeforeDeserialize else");

TextReader r = new StreamReader(o);

TextWriter w = new StreamWriter(n);

w.WriteLine(r.ReadToEnd());

w.Flush();

}

n.Position = 0;

}

}

public override Stream ChainStream( Stream stream )

{

abc("ChainStream");

o = stream;

n = new MemoryStream();

return n;

}

public void abc(string s)

{

FileStream fs = new FileStream("c:\\a.txt", FileMode.Append, FileAccess.Write);

StreamWriter w = new StreamWriter(fs);

w.WriteLine(s);

w.Flush();

w.Close();

}

}

 

a.txt

Constructor

GetInitializer System.String abc(System.String)

Constructor

Initialize vijay Response Request

ChainStream

AfterSerialize Request 326

AfterSerialize if

hi

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abc xmlns="http://tempuri.org/">

      <a>214 134 72 131 106 41 82 55</a>

    </abc>

  </soap:Body>

</soap:Envelope>

Constructor

GetInitializer System.String abc(System.String)

Constructor

Initialize vijay Request Response

ChainStream

BeforeDeserialize Request

BeforeDeserialize if

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abc xmlns="http://tempuri.org/">

      <a>214 134 72 131 106 41 82 55</a>

    </abc>

  </soap:Body>

</soap:Envelope>

Position of ds 355

214 134 72 131 106 41 82 55

8

hi

ChainStream

AfterSerialize Response 364

AfterSerialize if

vijay hi

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abcResponse xmlns="http://tempuri.org/">

      <abcResult>225 92 58 159 62 55 111 215 225 255 97 209 232 130 31 99</abcResult>

    </abcResponse>

  </soap:Body>

</soap:Envelope>

ChainStream

BeforeDeserialize Response

BeforeDeserialize if

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abcResponse xmlns="http://tempuri.org/">

      <abcResult>225 92 58 159 62 55 111 215 225 255 97 209 232 130 31 99</abcResult>

    </abcResponse>

  </soap:Body>

</soap:Envelope>

 

Position of ds 416

225 92 58 159 62 55 111 215 225 255 97 209 232 130 31 99

16

vijay hi

 

z.txt

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abc xmlns="http://tempuri.org/">

      <a>hi</a>

    </abc>

  </soap:Body>

</soap:Envelope>

 

y.txt

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body>

    <abcResponse xmlns="http://tempuri.org/">

      <abcResult>vijay hi</abcResult>

    </abcResponse>

  </soap:Body>

</soap:Envelope>

 

Output in Browser

Vijay hi

 

a.bat

del *.dll

csc /t:library aaa.cs

csc /t:library zzz.cs /r:aaa.dll

 

This program sheds light on the concepts of encryption and decryption at their best.

 

The client program sends a SOAP request, which holds the encrypted value of "hi", to the server. The server receives the encrypted parameter, decrypts it and transmits it further, to the SOAP system. The function in the extension dll receives the parameter as 'hi', and reciprocates by sending the return value of 'vijay hi', in an encrypted form. Then, the SOAP framework creates a SOAP packet, containing the return value in an encrypted form, and then, sends it to the client. The client receives this encrypted value, and decrypts it prior to flaunting it in the browser window. This roller coaster ride is an endeavor to unravel the mystery behind all the actions transpired above.

 

We set out by grappling with the aspx file, as the first step. The function abc in this file accepts a string parameter and then, returns a string. Subsequently, the browser displays this string. The SOAP request and response packets that flow to and fro, neither display the input string as "hi", nor do they disclose the response value of "vijay hi", which is received from the server. All that they display, is a series of numbers, floating from one end to the other.

 

SOAP request

<soap:Body>

<abc xmlns="http://tempuri.org/">

  <a>214 134 72 131 106 41 82 55</a>

</abc>

  </soap:Body>

 

SOAP response

<soap:Body>

<abcResponse xmlns="http://tempuri.org/">

<abcResult>225 92 58 159 62 55 111 215 225 255 97 209 232 130 31 99</abcResult>

</abcResponse>

</soap:Body>

 

The asmx file has a function named abc in the class zzz. This function accepts one string parameter named 'a', and it returns a string that contains the word 'vijay', concatenated to this string parameter.

 

It also has an attribute named 'vijay', which in turn, owns two parameters named Enc and Dec, which are short forms for the terms Encrypt and Decrypt, respectively. Thus, the class attribute 'vijay' now possesses two properties. The values of these properties determine what needs to be done. EM and DM are enums, both of which specify that the request or response is to be either encrypted or decrypted. The third value in the enum is 'none'.

 

In our case, the values specified here are indicative of the fact that, the Response is to be encrypted, and the Request is to be decrypted.

 

The asmx file is located on the server. Thus, it represents the processing that is to be done at the server end. It is the bounden duty of the server to decrypt the data that has been encrypted by the client, and to encrypt the Response data, which shall subsequently be decrypted by the client.

 

Until now, the asmx file was being used to create the client program, in that, it was utilized for running the wsdl utility on the wsdl file, and for creating the .cs file. But for the moment, we shall write the client program manually, since we have to place the attribute named 'vijay'.

 

Candidly speaking, we employed the webserver for creation of the client program, and subsequently, we eliminated the code that was unnecessary, and thus, redundant. Thereafter, the attribute named 'vijay' made its debut.

 

Akin to the server, this attribute also accepts two parameters, viz. Enc=EM.Request, Dec=DM.Response. These values signify that the Request is to be encrypted and the Response is to be decrypted. The code remains almost identical, except for the introduction of the attribute named 'vijay'. We have provided you with the bird's eye view, before diving any deeper into comprehending the code of the attribute named 'vijay'.

 

When the URL with the aspx file is written in the browser, a Get or Post is dispatched to the Web Server. Let us designate the name 'A' for the Web Server. Subsequent to the file being positioned on the web server 'A', the aspx program gets converted into C# code, and the function abc is called from the program named zzz.dll. Thereafter, this function sends a SOAP packet, containing data encrypted by the SOAP extension dll, to another server, which is named as 'B' merely on the whim. This server 'B' actually contains the code of the function abc.

 

On receiving the SOAP payload, the server B executes the asmx file. The SOAP extension dll decrypts the data and calls the function abc, while furnishing it with the original data value of 'hi'. The return value of the function i.e. 'vijay hi', is then encrypted, and dispatched back to the client dll named zzz.dll, which is located on the Web Server A. It is then decrypted by the code in the 'vijay' attribute extension dll, and the string 'vijay hi' is then returned back. Finally, the Web Server A creates an html file with the return value, and transports it to the browser. At times, this concept can be truly baffling!

 

The file aaa.cs is the extension dll, which contains the encryption and decryption code for both, the client and the server. Thus, it has to handle a situation wherein, only the Serialize events are triggered-off to encrypt the request from the client, and both the Serialize and Deserialize events are triggered-off for the response packets from the server.

 

The extension dll contains two enum classes called DM and EM, which symbolise Decryption and Encryption, respectively. These enum classes identify the values to be encrypted or decrypted, such as- the request, the response, or no value at all!

So, when we specify the enum value of EM.Response, the interpretation rendered by the program is that, the Response has to be encrypted.

 

The class 'vijay' has two properties named Enc and Dec. Only those programs that employ the attribute of 'vijay', are entitled to the use of Enc and Dec properties; and It is these properties that 'set' or 'get' the value that is stored in the variables 'emode' and 'dmode'. In the present context, these variables store the state of the properties Dec and Enc.

 

Next, the GetInitializer function returns the second parameter that is cached. Since you have already been enlightened about the motive behind this call, we choose to ignore it at this stage. The system calls this function twice, since there are two instances of the attribute 'vijay':

•     First, for the client in zzz.cs

•     And then, for the server in a.asmx.

 

The prototypes of both the functions have to be identical. Firstly, the constructor is called, followed by the GetInitializer function. Thereafter, the constructor is called yet again; but this time, it is for the client data. The same process is repeated for the server as well.

 

The Initialize function gets called each time. Here, the parameter i represents the 'vijay' object. The value of the a.Dec property is Response, whereas, the value of the a.Enc property is Request. The values unearthed by the function abc, vindicate our claim. It is because, in the client zzz.cs, the parameters of the attribute 'vijay' are specified as Enc=EM.Request and Dec=DM.Response.

 

Thus, the Initialize function is called for the packet received from the client. In this function, the values of the properties Dec and Enc, are saved in the variables dmode and emode, respectively. This concludes the process of transferring data from the attribute 'vijay', pertaining to the client.

 

In the ProcessMessage function, it is the AfterSerialize event which is called first, since the data originates from the client. The ChainStream function sets up the Streams, prior to this event being fired. The Position parameter of the Stream object n is set to 0, because when the packet is received, the stream pointer is at the end of the Stream, at position 326. This number corresponds to the size of the SOAP payload.

 

Now, emode contains the value of Request, since the packet has to be encrypted. Just to jog your memory a little, this is so because, in the parameter of the 'vijay' attribute in the client program named zzz.cs, the value of ENC is set to EM.Request.

 

Now, in order to populate the byte array, the code that was specified earlier, has to be entered. In order to pay our respects to the original programmer who wrote this class, the StringBuilder class is used to concatenate the bytes from the byte array. Here, we iterate through the byte array and utilise the Append function to add a byte to the StringBuilder class named 's'. We have added a space between the encrypted values, in order to brandish the output in a more aesthetic manner. These spaces will have to be stripped off, prior to decryption of the numbers.

 

The InnerText is then initialized to the new output data, and the memory stream is created. Once the loop terminates, the contents of the stream 'n' are written to the Stream 'o'. The file a.txt displays the SOAP payload that is being sent over. Presently, only the first parameter will be encrypted. The code catering to encryption of multiple parameters is not entered.

 

Once the SOAP packet reaches the server, the decryption routine takes over. This is because, in the asmx file, the parameter supplied to the attribute 'vijay' is Dec=DM.Request. The ChainStream function is called prior to the firing of the BeforeDeSerialize event.

 

In this event, an empty MemoryStream object is created initially. Then, the value of the dmode variable is ascertained, to determine whether it is Request or Response.

 

Since the value contained in dmode is 'Request', we enter the 'if' statement, which will decrypt the SOAP payload sent from the client to the server. The encrypted SOAP request payload from the client, which is saved in the Stream 'o', is then transferred to the memory stream 'ds'. Since the Position property in the memory stream ds has changed to 355, it is reset to 0.

 

Now, we require an XmlDocument to accommodate the encrypted data in the MemoryStream 'ds'. Therefore, we create an XmlTextReader object named 'r0', and an XmlDocument object named 'd1'. The Load function is pressed into service to copy the XML data from the memory stream 'ds', to the XmlDocument 'd1'. After having provided for the other details, we access the first grandchild from the body. The XmlNode named 'no' represents this child node.

 

Thereafter, a wrapper object of class DESCryptoServiceProvider, is instantiated. Further, the encrypted text, which is contained in the node 'no', is assigned to a string s3, using the InnerText property. Since the text contains spaces, the Split function of the string is provided with the delimiter of the 'space' character, and the output is stored in a string array named 'ss'. There are a total of 7 spaces in the string s3. Therefore, the size of the string array ss is 8. Once this is achieved, we create a byte array named b, of length 8, and subsequently, iterate through a 'for' loop.

 

The static function Parse in the Byte class, converts the string into a byte, and stores it in a different member of the array. The member is decided on the basis of the value of the variable i. The loop continues till all the string bytes have been transferred into the array. We could have used the Byte array named 'b' for this purpose, but we decided to create a new one named 'imp'. Ask us not why!

 

The next task is to decrypt this data. In order to accomplish this, an empty MemoryStream object named 'ms1' is created and assigned to the CryptoStream constructor, while the object cs is being created. The second parameter is the CreateDecryptor function, with the same key and IV. This leads to the creation of an object, which will decrypt the byte array and place the contents in the MemoryStream ms1. The last parameter is the enum value of 'Write'.

 

Finally, the Write function in the stream is called, with the byte arrays that contain the encrypted values. The end result is that, the memory stream ms1 shall now contain the decrypted value. But hold your horses! This is attainable only when the stream is flushed. For this, the FlushFinalBlock function is put to use. The decrypted text from the MemoryStream ms1 is then acquired, using the ToArray function, which returns a byte array containing the word 'hi'. The bytes are converted into a string, using the GetString function. Ultimately, the value of 'hi' is displayed.

 

The task still remains unfinished, since an XmlDocument has yet to be created, with this new value. The InnerText of the XmlNode is set to 'hi', and a MemoryStream object 'ms' is created. Then, using the Save function, the entire XmlDocument is written to this object.

 

Finally, we employ the freshly created 'ms' MemoryStream as the Reader, and the MemoryStream 'n' as the Writer. All that is written to this stream, shall be passed on to the asmx program. The 'else' block is never called, since it is used only when the dmode variable has a value of None 0 no decryption. Thus, you would realize that both encryption and decryption, adhere to analogous rules.

 

The server calls the asmx file, with the value of the parameter 'a' as 'hi'. The asmx file returns 'vijay hi', which is used by the server to create a SOAP payload. The SOAP payload reaches the extension dll, where the AfterSerialize event gets called, but with the value of emode as Response. The SOAP payload is now encrypted and sent across.

 

On receiving the encrypted SOAP response, the client uses the extension dll and triggers off the BeforeDeSerialize event. The code contained in this block, converts the encrypted bytes to the value 'vijay hi', since the value of dmode is DM.Response. The files z.txt and y.txt, exhibit the actual SOAP payload that has been received by the server and the client, subsequent to the decryption.  The above illustration is indeed an enormous mental workout, but is worth comprehending.

 

Once you have ruminated and digested the above program, incorporate the following two modifications in the aaa.cs program:

•   Replace the two instances of the DESCryptoServiceProvider class, with the RC2CryptoServiceProvider class.

 

Change

DESCryptoServiceProvider de = new DESCryptoServiceProvider();  

To

RC2CryptoServiceProvider de = new RC2CryptoServiceProvider ();

 

The residual code remains unchanged. The eventual outcome is that, the algorithm adopted for the encryption of data is RC2, and not the DES. This is suggestive of the fact that, shifting from one algorithm to another, is indeed effortless.

 

SOAP request

<soap:Body>

<abc xmlns="http://tempuri.org/">

  <a>214 40 209 188 96 8 97 42</a>

  </abc>

</soap:Body>

 

SOAP response

<soap:Body>

<abcResponse xmlns="http://tempuri.org/">

  <abcResult>164 69 219 2 3 8 58 43 175 147 53 64 112 176 15 181</abcResult>

  </abcResponse>

  </soap:Body>

 

The SOAP payload here is different, since the encrypted data is at variance with the earlier data, however, this does not seem to hassle the program at all. Now, let us make rapid strides to the very last program of the chapter.

 

a.aspx

<HTML>

<HEAD>

<script language="c#" runat=server>

public void Page_Load()

{

zzz w = new zzz("RC2");

l.InnerHtml = w.abc("hi");

zzz w1 = new zzz("DES");

l1.InnerHtml = w1.abc("Bye");

}

</script>

</HEAD>

<BODY>

<b id="l" runat="server"/>

<p>

<b id="l1" runat="server"/>

</HTML>

 

zzz.cs

using System.Diagnostics;

using System.Xml.Serialization;

using System;

using System.Web.Services.Protocols;

using System.Web.Services;

[System.Web.Services.WebServiceBindingAttribute(Name="HelloWorldSoap", Namespace="http://tempuri.org/")]

public class zzz: System.Web.Services.Protocols.SoapHttpClientProtocol

{

public yyy b;

public zzz(string s)

{

b = new yyy();

b.type = s;

this.Url = "http://localhost:8080/a.asmx";

}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/abc")]

[vijay(Enc=EM.Request,Dec=DM.Response)]

[System.Web.Services.Protocols.SoapHeaderAttribute("b")]

public string abc(string a)

{

object[] results = this.Invoke("abc", new object[]{a});

return ((string)(results[0]));

}

}

public class yyy : SoapHeader

{

public string type;

}

 

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Web.Services.Protocols;

public class zzz

{

[WebMethod]

[vijay(Enc=EM.Response,Dec=DM.Request)]

public string abc( string a)

{

return "vijay " + a;

}

}

 

aaa.cs

using System;

using System.IO;

using System.Xml;

using System.Text;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Security.Cryptography;

[AttributeUsage(AttributeTargets.Method)]

public class vijay : SoapExtensionAttribute

{

EM emode= EM.None;

DM dmode= DM.None;

public override Type ExtensionType

{

get

{

return typeof(mukhi);

}

}

public override int Priority

{

get

{

return 0;

}

set

{

}

}

public EM Enc

{

get

{

return emode;

}

set

{

emode= value;

}

}

public DM Dec

{

get

{

return dmode;

}

set

{

dmode= value;

}

}

}

public enum DM

{

None,

Response,

Request

}

public enum EM

{

None,

Response,

Request

}

public class mukhi : SoapExtension

{

Stream o;

Stream n;

DM dmode;

EM emode;

static string ctype = "RC2";

Byte[] k = {1, 2, 3, 4, 5, 6, 7, 8};

Byte[] k1 = {10,11 , 12, 13, 14, 15, 16, 17};

public mukhi()

{

}

public override object GetInitializer(LogicalMethodInfo m, SoapExtensionAttribute a)

{

return a;

}

public override object GetInitializer(Type t)

{

return typeof(mukhi);

}

public override void Initialize(object i)

{

vijay a = (vijay) i;

dmode = a.Dec;

emode = a.Enc;

abc("Initialize " + i.ToString() + " " + a.Dec.ToString() + " " + a.Enc.ToString());

return;

}

public override void ProcessMessage(SoapMessage m)

{

if ( m.Stage == SoapMessageStage.AfterSerialize)

{

abc("AfterSerialize " + emode.ToString() + " " + n.Position );

n.Position = 0;

if ((emode == EM.Request) || (emode == EM.Response))

{

abc("AfterSerialize if");

n.Position = 0;

XmlTextReader rr = new XmlTextReader(n);

XmlDocument d1 = new XmlDocument();

d1.Load(rr);

XmlNamespaceManager nm = new XmlNamespaceManager(d1.NameTable);

nm.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode no = d1.SelectSingleNode("//soap:Body", nm);

no = no.FirstChild.FirstChild;

byte[] inp = Encoding.UTF8.GetBytes(no.InnerText);

MemoryStream ms1 = new MemoryStream();

abc("-------------------" + ctype);

byte[] ou = null;

if (emode == EM.Request)

{

XmlNode no1 = d1.SelectSingleNode("//soap:Header", nm);

no1 = no1.FirstChild.FirstChild;

abc("################" + no1.InnerText);

ctype = no1.InnerText;

}

if ( ctype == "DES")

{

DESCryptoServiceProvider de = new DESCryptoServiceProvider();

CryptoStream cs = new CryptoStream(ms1, de.CreateEncryptor( k, k1 ), CryptoStreamMode.Write);

cs.Write(inp, 0, inp.Length);

cs.FlushFinalBlock();

ou = ms1.ToArray();

}

else

{

RC2CryptoServiceProvider de = new RC2CryptoServiceProvider();

CryptoStream cs = new CryptoStream(ms1, de.CreateEncryptor( k, k1 ), CryptoStreamMode.Write);

cs.Write(inp, 0, inp.Length);

cs.FlushFinalBlock();

ou = ms1.ToArray();

}

StringBuilder s = new StringBuilder();

for(int i=0; i<ou.Length; i++)

{

if(i==(ou.Length-1))

s.Append(ou[i]);

else

s.Append(ou[i] + " ");

}

no.InnerText = s.ToString();

MemoryStream ms = new MemoryStream();

d1.Save(ms);

ms.Position = 0;

n = ms;

}

TextReader r = new StreamReader(n);

TextWriter w = new StreamWriter(o);

string s5 = r.ReadToEnd();

w.WriteLine(s5);

w.Flush();

}

if ( m.Stage ==  SoapMessageStage.BeforeDeserialize)

{

abc("BeforeDeserialize " + dmode.ToString());

MemoryStream ds = new MemoryStream();

if ((dmode == DM.Request) || (dmode == DM.Response))

{

abc("BeforeDeserialize if");

TextReader r = new StreamReader(o);

TextWriter w = new StreamWriter(ds);

string s6 = r.ReadToEnd();

w.WriteLine(s6);

w.Flush();

ds.Position = 0;

XmlTextReader r0 = new XmlTextReader(ds);

XmlDocument d1 = new XmlDocument();

d1.Load(r0);

XmlNamespaceManager nm = new XmlNamespaceManager(d1.NameTable);

nm.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode no = d1.SelectSingleNode("//soap:Body", nm);

no = no.FirstChild.FirstChild;

string s3 = no.InnerText;

char[] c = {' '};

string[] ss = s3.Split(c);

byte[] b = new byte[ss.Length];

for(int i=0; i<b.Length; i++)

{

b[i] = Byte.Parse(ss[i]);

}

byte[] inp = b;

MemoryStream ms1 = new MemoryStream();

byte[] ou = null;

abc(ctype);

if ( ctype == "DES")

{

DESCryptoServiceProvider de = new DESCryptoServiceProvider();

CryptoStream cs = new CryptoStream(ms1,de.CreateDecryptor( k, k1 ), CryptoStreamMode.Write);

cs.Write(inp, 0, inp.Length);

cs.FlushFinalBlock();

ou = ms1.ToArray();

}

else

{

RC2CryptoServiceProvider de = new RC2CryptoServiceProvider();

CryptoStream cs = new CryptoStream(ms1,de.CreateDecryptor( k, k1 ), CryptoStreamMode.Write);

cs.Write(inp, 0, inp.Length);

cs.FlushFinalBlock();

ou = ms1.ToArray();

}

string s1 = Encoding.UTF8.GetString(ou);

no.InnerText = s1;

MemoryStream ms = new MemoryStream();

if ( dmode == DM.Request)

d1.Save("c:\\z.txt");

else

d1.Save("c:\\y.txt");

d1.Save(ms);

ms.Position = 0;

TextReader r1 = new StreamReader(ms);

TextWriter w1 = new StreamWriter(n);

w1.WriteLine(r1.ReadToEnd());

w1.Flush();

}

else

{

abc("BeforeDeserialize else");

TextReader r = new StreamReader(o);

TextWriter w = new StreamWriter(n);

w.WriteLine(r.ReadToEnd());

w.Flush();

}

n.Position = 0;

}

}

public override Stream ChainStream( Stream stream )

{

//abc("ChainStream");

o = stream;

n = new MemoryStream();

return n;

}

public void abc(string s)

{

FileStream fs = new FileStream("c:\\a.txt", FileMode.Append, FileAccess.Write);

StreamWriter w = new StreamWriter(fs);

w.WriteLine(s);

w.Flush();

w.Close();

}

}

 

Output

vijay hi