The data encryption and security features included with .NET appear in the System.Security.Cryptography namespace. Most of the classes in this namespace implement various well-known encryption algorithms that have been accepted by organizations and governments as dependable encryption standards. For instance, the DESCryptoServiceProvider class provides features based on the Data Encryption Standard (DES) algorithm, an algorithm originally developed by IBM in the mid-1970s.
Symmetric cryptography uses a single secret key to both encrypt and decrypt a block of data. Although these algorithms are often quite fast (when compared to asymmetric cryptography), the need to share the full secret key with others in order to share data may make them inherently less secure. Still, for many applications, "secret key encryption" is sufficient.
The .NET Framework includes support for four symmetric encryption algorithms.
The various "provider" classes are tools that must be used together with other cryptography classes to work properly. For instance, this sample code (based on code found in the MSDN documentation) uses the DESCryptoServiceProvider and CryptoStream classes, both members of System.Security.Cryptography, to jointly encrypt and decrypt a block of text.
Imports System Imports System.IO Imports System.Text Imports System.Security.Cryptography Class CryptoMemoryStream Public Shared Sub Main() ' ----- Encrypt then decrypt some text. Dim key As New DESCryptoServiceProvider Dim encryptedVersion() As Byte Dim decryptedVersion As String ' ----- First, encrypt some text. encryptedVersion = Encrypt("This is a secret.", key) ' ----- Then, decrypt it to get the original. decryptedVersion = Decrypt(encryptedVersion, key) End Sub Public Shared Function Encrypt(origText As String, _ key As SymmetricAlgorithm) As Byte() ' ----- Uses a crytographic memory stream and a ' secret key provider (DES in this case) ' to encrypt some text. Dim baseStream As New MemoryStream Dim secretStream As CryptoStream Dim streamOut As StreamWriter Dim encryptedText() As Byte ' ----- A memory stream just shuffles data from ' end to end. Adding a CryptoStream to it ' will encrypt the data as it moves through ' the stream. secretStream = New CryptoStream(baseStream, _ key.CreateEncryptor(), CryptoStreamMode.Write) streamOut = New StreamWriter(secretStream) streamOut.WriteLine(origText) streamOut.Close() secretStream.Close() ' ----- Move the encrypted content into a useful ' byte array. encryptedText = baseStream.ToArray() baseStream.Close() Return encryptedText End Function Public Shared Function Decrypt(encryptedText() As Byte, _ key As SymmetricAlgorithm) As String ' ----- Clearly, this is the opposite of the ' Encrypt() function, using a stream reader ' instead of a writer, and the key's ' "decryptor" instead of its "encryptor." Dim baseStream As MemoryStream Dim secretStream As CryptoStream Dim streamIn As StreamReader Dim origText As String ' ----- Build a stream that automatically decrypts ' as data is passed through it. baseStream = New MemoryStream(encryptedText) secretStream = New CryptoStream(baseStream, _ key.CreateDecryptor(), CryptoStreamMode.Read) streamIn = New StreamReader(secretStream) ' ----- Move the decrypted content back to a string. origText = streamIn.ReadLine() streamIn.Close() secretStream.Close() baseStream.Close() Return origText End Function End Class
This code combines a DES encryption class with a Stream, a common tool in .NET applications for transferring data from one state or location to another. (Streams are a primary method used to read and write files.) Streams are not too hard to use, but the code still seems a little convoluted. Why doesn't the DESCryptoServiceProvider class simply include Encrypt and Decrypt methods? That's my question, at least. I'm sure it has something to do with keeping the class generic for use in many data environments. Still, as chunky as this code is, it's sure a lot easier than writing the encryption code myself. And it's general enough that I could swap in one of the other secret key algorithms without very much change in the code.
In secret key cryptography, you can use any old key you wish to support the encryption and decryption process. As long as you keep it a secret, the content of the key itself isn't really too important. The same cannot be said, though, of asymmetric (public key) cryptography. Because separate keys are used to encrypt and decrypt the data, specific private and public keys must be crafted specifically as a pair. You can't just select random public and private keys and hope that they work together.
The components used to support asymmetric cryptography include "generators" that emit public and private key pairs. Once generated, these keys can be used in your code to mask sensitive data. And due to the large key size, it's very difficult for anyone to hack into your encrypted data.
Public key encryption is notoriously slow; it takes forever and a day to encode large amounts of data using the source key. This is one of the reasons that the Founding Fathers didn't use public key encryption on the Declaration of Independence. Because of the sluggish performance of asymmetric encryption, many secure data systems use a combination of public-key and secret-key encryption to protect data. The initial authorization occurs with public-key processes, but once the secure channel opens, the data passed between the systems gets encrypted using faster secret-key methods.
.NET includes two public key cryptography classes for your encrypting and decrypting pleasure.
I won't be using asymmetric encryption in the Library Project. While the code needed to use these providers is interesting, and while the background information on prime number generation and large number factorization is fascinating, such discussions are beyond the scope of this book.
Although hashing algorithms do not give you the ability to encrypt and decrypt data at will, they are useful in supporting systems that secure and verify data content. In fact, hashing is the one cryptography component that we will directly code in the Library Project, so stay alert.
Coming up with a hashing algorithm is easy. It took the best minds of the National Security Agency and the Massachusetts Institute of Technology to come up with reliable secret-key and public-key encryption systems, but you can develop a hashing algorithm in just a few minutes. A few years ago, I wrote my own hashing algorithm that I used for years in business applications. That fact alone should prove how simple and basic they can be. Here's a hashing algorithm I just made up while I was sitting here.
Public Function HashSomeText(ByVal origText As String) As Long ' ----- Create a hash value from some data. Dim hashValue As Long = 0& Dim counter As Long For counter = 1 To Len(origText) hashValue += Asc(Mid(origText, counter, 1)) If (hashValue > (Long.MaxValue * 0.9)) Then _ hashValue /= 2 Next counter Return hashValue End Function
In the code, I just add up the ASCII values of each character in the text string, and return the result. I do a check in the loop to make sure I don't exceed 90% of the maximum Long value; I don't want to overflow the hashValue variable and generate an error. Although HashSomeText does generate a hashed representation of the input data, it also has some deficiencies.
Perhaps you want something a little more robust. If so, .NET includes several hashing tools.
Each of these algorithms uses a secret key that must be included each time the hash is generated against the same set of input data. As long as the input data is unchanged, and the secret key is the same, the resulting hash value will also remain unchanged. By design, even the smallest change in the input data generates major changes in the output hash value.