Cryptographic Objects in C#: Part 1 - Hashing Functions (Page 2 of 5 )
The following program has two classes: one to hash passwords and the other to encrypt files or streams. Message digests are implemented in .NET in two forms: MD5 and SHA1. Both are equally useful, MD5 returns 16 bytes based on any input content and this is unique for that content. SHA1 returns 20 bytes. These digests can be used as follows:
Verifying the contents of a file being transferred by computing the digest based on the file contents - in this way if the file contents have changed there will be a discrepancy which will be apparent in the digest calculated previously to the current digest.
Using a username/password to provide a secure login mechanism. The user would type these two into a login prompt and the concatenation of the two words would be hashed and compared to a stored hash value to determine authentication.
Hashing is especially useful for controlling access to resources on a website. As such ASP.NET can be used in conjunction with the C# objects below to create a user repository in a database. First the user enters a username and a password. These two strings are then concatenated and the result will be passed to an MD5 or SHA1 object. A unique hash would be computed and this hash could be compared to one that was stored earlier in the database when the user account was created.
The simplicity of this scheme is that the user is the only one who needs to know the password.
A malicious person viewing the contents of the database will see the username with the password stored next to the username as a hash - they will never know more than 50% of what is required to use the account. In effect all details can be hashed including the credit card number with the username for secondary access if someone has forgotten their password.
After a successful database hash is matched with one computed on the fly then a token can be given which allows access to certain resources on the website. In effect this is similar to how Microsoft has implemented hashing from within the web.config page (which is one of the two key pages now to any ASP.NET site along with the global.asax).
The section that interests us at the moment is the line:
This means that all passwords will have SHA1 hashes computed and stored for them. The token discussed in the previous paragraphs is given to the web user in the form of a cookie. We won't be discussing this here but the CookieAuthentication object has static methods that allow it to control the login process.
The hashing object wrappers below can be used to gain greater clarity in the hashing process and possibly to replace use of the web.config to do the same. You can, as you will see below, hash any number of things (including file contents); hashing multiple strings can be done by just using string concatenation followed by computation of the hash itself.
The second class is used to generate symmetric keys. The algorithms used are DES, Triple DES and RC2 - these keys can be used to encrypt any volume of data. A key is generated by any of the 3 above algorithms and is then used to encrypt some plaintext. The result is called cipher text. Symmetric encryption can be used for the following:
Encrypt the contents of a file
Encrypt the contents of stream (i.e. a data stream being transmitted over the internet).
The above key algorithms are just used to generate the key itself. The encryption is done by XORing the key bits to the bits of the plaintext. XOR is used as the key can be XORed again to the cipher text to return to the original plaintext. Cipher block chaining is used to add the bits of the previous cipher text to the plaintext following. In this way there will be no repetition in the cipher text and the key won't be able to be derived by looking at the similarities within the cipher text itself.
From the diagram you can see that the plaintext is encrypted in the first block (denoted by gray) and the resulting cipher text is Xored with the plaintext from the next block (denoted by yellow) before encryption.
Xor is a binary operation that can be done on a bit. A Xor truth table would look like the following:
Unlike a conventional Or operation it produces true when either input bit is 1 but not both. As all text characters can be represented in ASCII (an 8 bit notation) it is the bits in the ASCII representation of the character that are XORed with the bits of the key to provide the results given in the truth table above. As you can see above, if a one bit key (1) encrypts a one bit plaintext 1 the result would be 0. To decrypt this all you would need to do is the XOR operation again so 0 Xor 1 would be 1 thus arriving at the original plaintext.
To begin the project a reference must be set in the project pane to the System.Security.Cryptography namespace.
Then to import the Crypto library in the System.Security.Cryptography namespace to avoid prefixing the cryptographic objects:
This namespace has a wealth of uses. Some we will cover in this article and others we'll save for the future. It contains implementations of RSA which will be used in part II to create a key-exchange program. Most of you will be familiar with the internet use of SSL. Well, effectively SSL uses Private/Public key cryptography, i.e. a digital certificate (issued by a certified authority) to allow a web browser to generate a symmetric key and send data securely to the web server (so that only the browser and server know the key). This whole processor is called key-exchange and objects exist in the Cryptography namespace to allow for the formatting of these keys and implementations of the key-exchange.
Some support classes exist to allow for the generation and maintenance of keys also, including classes which allow changeable bit padding for encryption and other classes that allow one to customize encryption for the task at hand.
We will also have to reference the namespace System.Text specifically because we will need to use the Encoding objects static methods to convert between strings and byte arrays. We will also refer to System.IO since we will be reading and writing to files.
using System.Text; using System.IO;
These base classes can now be accessed without the need for the namespace prefix:
FileStream f = FileStream("temp.txt", FileMode.Create, FileAccess.Write);
These two classes are found within the System.IO namespace and are invaluable for reading and writing byte array to files. As such they are used throughout the code to read from plaintext files and to write out to cipher text files.