Monday, December 18, 2006

"This stream does not support seek operations."

I ran into a problem while reading binary data from a site for my web-spidering application that I was developing a couple of months ago. I was able to read text strings from few sites but failed on many websites because the ResponseStream was not seekable. See this code snippet

 
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);         
HttpWebResponse myResponse = (HttpWebResponse) myRequest.GetResponse();
int length = myResponse.ContentLength;
The ContentLength property of the WebResponse object failed to retrieve the stream’s length and threw “This stream does not support seek operations” exceptions. I later realized that it was not actually a problem with the WebResponse object, but the way I intended to retrieve binary data from the web was not right. Ok, so how can I retrieve data out of this stream, say, a straight HTML text for further parsing? The best way to do this would be to copy this stream to a MemoryStream and finally convert it into a Byte Array.
 
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);         
HttpWebResponse myResponse = (HttpWebResponse) myRequest.GetResponse();
          
Stream respStream = myResponse.GetResponseStream();

MemoryStream memStream = new MemoryStream();
byte[] buffer = new byte[2048];

int bytesRead = 0;
do
{
    bytesRead = respStream.Read(buffer, 0, buffer.Length);
    memStream.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
respStream.Close();
buffer = memStream.ToArray();
string html = System.Text.Encoding.ASCII.GetString(buffer);

Here, I am instantiating a new MemoryStream object, reading fixed bytes from the stream and copying it over to the MemoryStream. The Stream.Read() method reads a maximum of "bytesRead" bytes from the current stream and store them in the buffer. In the above example it reads a maximum of 2048 bytes each time, stores them in a buffer and finally write that into the MemoryStream. The method returns a 0 if there is no more data to be read. One important thing to be noted here is that the Stream.Read() method can return fewer bytes than requested (< 2048) even if end of the stream has not been reached.

MemoryStream.ToArray() method finally converts it into a Byte Array. If the retrieved data is of plain-text type, which can be know from its headers, can be converted into a string using the System.Text.Encoding.ASCII.GetString(buffer) method. Else, write the byte array to a file using the FileStream object.

You will find this implementation very useful if you’re planning to download something and later resume broken downloads in your web-spidering applications….!

Sunday, December 3, 2006

TripleDES Encryption in .NET

Encryption of sensitive data is very important in most of the software applications today. In this feed I’ll show you how to encrypt and decrypt a string data using the encryption classes contained within .NET. The method I’m going to employ here is a “private-key” algorithm that uses one key to encrypt and the same key to decrypt the data. I’ll be using the TripleDES encryption algorithm which is considered to be very secure. It performs three times as much encryption as the standard DES.

DES, Data Encryption Standard, encrypts data using 64-bit or 8-byte blocks and employs 16 rounds of encryption to every block of data. It uses a key size of 56 bits, 8 bits reduced from 64 bits which serve as parity bits. As mentioned earlier, TripleDES, which performs 3 times the encryption as DES requires 168-bit key and encrypts each block three times. That is, each block of data is actually encrypted 48 times, making TripleDES more secure.

In this example, instead of using a 24-byte private key directly, I’m converting a pass phrase into a TripleDES key using the Hash Computation algorithm found in MD5CryptoServiceProvider class. I am doing this because the pass phrase makes more sense when you want to share the private key among those whom you want to share your secure data with. You definitely don’t want to memorize a private key of this kind {12, 26, 13, 44, 95,16,17,38,29, 10, 11, 22, 43, 24, 15, 56, 37, 78, 29, 27, 23, 52, 43, 4} to decrypt or encrypt your data.

Let’s look at the code now. To begin with, we’ll add a few namespaces.

using System;
using System.Text;
using System.Security.Cryptography;
Add an initialization vector as the private member of that class. 
private string Key = "";
private readonly byte[] IVector = new byte[8] { 27, 9, 45, 27, 0, 72, 171, 54 };

An initialization vector is used to mask the encryption method in private-key algorithms as they are known to process data in blocks. In most general terms, a block cipher will move to the next block after encrypting each block of data using the same key. Say, if the alternate block has the same data, then the encrypted equivalent also would be having the same encrypted data because they were encrypted with the same key. An initialization vector, in combination with the private key, uses the previous block’s information in encrypting subsequent blocks thereby generating different encrypted data even though they’re the same.

The above initialization vector contains 8 bytes. This can be replaced with your choice. Take a look at the Encrypt Method.

 
private string Encrypt(string inputString)
{

    byte[] buffer = Encoding.ASCII.GetBytes(inputString);
    TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
    MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
    tripleDes.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(Key));
    tripleDes.IV = IVector;
    ICryptoTransform ITransform = tripleDes.CreateEncryptor();        
    return Convert.ToBase64String(ITransform.TransformFinalBlock(buffer, 0, buffer.Length));
}

I’m first converting the plain text string to a byte Array since many cryptographic methods expect the data to be in this format. I’m then instantiating couple of objects, firstly, TripleDESCryptoServiceProvider which accepts the initialization vector and the private key, and secondly, MD5CryptoServiceProvider which is used to compute the Hash and create a valid TripleDES private key from the Pass Phrase that I was telling you about. The ICryptoTransform defines the basic operations of cryptographic transformations. The TransformFinalBlock method transforms the input byte array into an encrypted byte array by applying the private key and the initialization vector. This is finally converted into a Base64String and returns the encrypted string to the calling method.

The process of decrypting the data is very much similar to encrypting the data because they use exactly the same private key. The Decrypt method shown below does the decryption process.

 
private string Decrypt(string inputString)
{
    byte[] buffer = Convert.FromBase64String(inputString);
    TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
    MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
    tripleDes.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(Key));
    tripleDes.IV = IVector;
    ICryptoTransform ITransform = tripleDes.CreateDecryptor();
    return Encoding.ASCII.GetString(ITransform.TransformFinalBlock(buffer, 0, buffer.Length));
}

This completes the encryption/decryption process of a string data by employing the classes and methods contained in the System.Security.Cryptography namespace. The screenshots of the sample application that I created is shown below.

You can create your own Encryptor/Decryptor class library with these methods and develop more secure enterprise applications. Some of the areas of interest would be like encrypting the Passwords before saving it to the database or encrypting the QueryStrings in your web applications.

Hope this was helpful….

Wednesday, September 27, 2006

Caching in Windows Application

I was working on a Windows Service lately that generated hundreds of documents by processing data retrieved from several database tables. Each time, the service accessed at least 10 lookup tables apart from getting data from various other ones to generate a single document. One thing that concerned me most was its sluggish performance that resulted from its repeated calls to the lookup/reference tables.


I was wondering if there was a way to add caching feature to my windows service, where all the lookup tables are stored locally for a specified duration of time and minimize the overall database calls. You know, caching is one of many such features that are strongly tied to ASP.NET web applications only. Guys at Microsoft encourage you to use Caching Application Block or the latest Enterprise library to enjoy the same features in windows applications.
I stumbled upon a Microsoft Knowledge base article a while ago that suggests using alternative mechanisms such as ASP.NET Cache, 'coz the cache application block had inconsistencies with multithreaded applications. Exceptions occurred when several threads tried to update the cache at the same instance. This got me thinking; why not use the ASP.NET cache in my Windows service application. I'm telling you, this worked like a charm, enjoying the benefits of caching that a ASP.NET web application would provide.
Here's what I did…
I created a new Class Library Project named WinCaching in C#. Added a reference to System.Web.dll. (Convince your Code QA/review team, why you're referencing this namespace from a windows app)
In this class I exposed a public property called Cache which returns the HttpContext.Current.Cache or HttpRuntime.Cache based on the type of application it is. Say, if I'm accessing this property in a WinForms application, the HttpContext.Current.Cache would usually be null, eventually returning the HttpRuntime cache to the caller. The HttpRuntime class provides a bunch of ASP.NET run-time features to the current WinForms or Windows Service applications.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Caching;

namespace WinCaching
{
    public class Caching
    {

        public static Cache Cache
        {
            get
            {
                return (System.Web.HttpContext.Current == null) ? System.Web.HttpRuntime.Cache : 
System.Web.HttpContext.Current.Cache;
            }
        }
    }
}

All the other classes that needs to use the caching feature in your application will have to do so by accessing this property. I'll show you how…
Create a WinForms application, add a reference to the WinCaching class library that we created above.
To insert data into the cache with expiration time of 60 minutes you can write as
WinCaching.Caching.Cache.Insert("TestKey", txtName.Text, null, DateTime.Now.AddMinutes(60), TimeSpan.Zero);

Similarly, to retrieve the same data, you can access the property as

string s = WinCaching.Caching.Cache["TestKey"].ToString();

This way, you can reuse the same library for your caching needs in Windows as well as Web applications. Hope this trick helps you in improving your application's performance.