Cryptography

This section describes how the .NET Framework supports common cryptographic tasks. The reader should be familiar with the basics of cryptography, a description of which is outside the scope of this book. There is only a surface-level similarity between the cipher support in .NET and the Java Cryptographic Extension (JCE); however, the basic principles behind both are the same.

Encrypting and Decrypting Data

The .NET Framework supports encryption algorithms that can be broken down into two groups: symmetric and asymmetric. Symmetric algorithms use the same key to encrypt and decrypt data, whereas asymmetric algorithms use a public and a private key.

Symmetric algorithms are usually used to encrypt large amounts of data; the processing requirements are less than for asymmetric encryption but are considered to be less secure because both the originator and the recipient of the encrypted data must possess a copy of the same key. Asymmetric encryption requires more computation, but the originator and the recipient don’t have to use the same key; asymmetric encryption is often used to encrypt the keys for symmetric schemes.

Symmetrical Encryption

The .NET Framework supports the following symmetrical encryption algorithms:

  • DES

  • TripleDES

  • RC2

  • Rijndael (also known as AES)

The base class for all symmetrical algorithms is System.Security.Cryptography.SymmetricAlgorithm. This class provides the basic members for encrypting data as well as creating keys and initialization vectors (IVs), which are nonsecret binary inputs to the algorithms. Each of the supported algorithms is represented by an abstract class and a default implementation class; the abstract class allows alternative implementations of algorithms to be used, such as those that accelerate encryption by using hardware. Table 17-5 lists the abstract and default implementation classes for each algorithm; all classes are members of the System.Security.Cryptography namespace.

Table 17-5. Symmetric Encryption Classes

Abstract Class

Implementation Class

DES

DESCryptoServiceProvider

RC2

RC2CryptoServiceProvider

Rijndael

RijndaelManaged

TripleDES

TripleDESCryptoServiceProvider

The key and IV can be generated using the GenerateKey and GenerateIV methods or set using the Key and IV properties. Reading and writing encrypted data are supported through the streams model using the System.Security.Cryptography.CryptoStream class. See Chapter 10, for general information on streams. The CryptoStream constructor takes three arguments, as detailed in Table 17-6.

Table 17-6. CryptoStream Constructor Arguments

Constructor Argument Type

Description

System.IO.Stream

The Stream that should be used for reading or writing.

System.Security.Cryptography.ICryptoTransform

A class that can perform cryptographic transformations (encrypting and decrypting data). Transformers can be obtained using the CreateDecryptor and CreateEncryptor methods from the SymmetricAlgorithm class.

System.Security.Cryptography.CryptoStreamMode

An enumeration value that specifies whether the CryptoStream instance will be used to read or write data.

The following example demonstrates how to write encrypted data to a MemoryStream and then read it back, using the Triple DES algorithm:

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;

class DESExample {

    DESExample() {
        byte[] x_secret_message
            = Encoding.Default.GetBytes("C# for Java Developers");

        // create the provider and generate the key and IV
        TripleDESCryptoServiceProvider x_3des
            = new TripleDESCryptoServiceProvider();
        x_3des.GenerateKey();
        x_3des.GenerateIV();

        // create the memory stream to hold the encrypted data
        MemoryStream x_memory_stream = new MemoryStream();

        // create the cryto stream
        CryptoStream x_crypto_stream = new CryptoStream(
            x_memory_stream,
            x_3des.CreateEncryptor(x_3des.Key, x_3des.IV),
            CryptoStreamMode.Write);

        // write the data to the crypto stream
        x_crypto_stream.Write(x_secret_message, 0,
            x_secret_message.Length);
        x_crypto_stream.Flush();

        // create a crypto stream to read the data
        x_crypto_stream = new CryptoStream(
            x_memory_stream,
            x_3des.CreateDecryptor(x_3des.Key, x_3des.IV),
            CryptoStreamMode.Read);

        // read and print the secret message
        x_crypto_stream.Read(x_secret_message, 0, x_secret_message.Length);
        Console.WriteLine(Encoding.Default.GetString(x_secret_message));
    }

    static void Main(string[] args) {
        new DESExample();
    }
}

Asymmetrical Encryption

The .NET Framework provides support for the asymmetrical encryption algorithms DSA and RSA. The class hierarchy for asymmetrical encryption follows the same model as for symmetrical algorithms. The abstract class System.Security.Cryptography.AsymmetricAlgorithm provides the basic members, which are accompanied by abstract and concrete implementations for each of the algorithms, as detailed in Table 17-7.

Table 17-7. Asymmetric Encryption Classes

Abstract Class

Implementation Class

System.Security.Cryptography.DSA

System.Security.Cryptography.DSACryptoServiceProvider

System.Security.Cryptography.RSA

System.Security.Cryptography.RSACryptoServiceProvider

A public/private key pair is generated automatically when the implementation classes are instantiated; the key information can be extracted in the following ways:

  • By using the ExportParameters method, which returns a class representing the key information (either DSAParameters or RSAParameters)

  • By using the ToXmlString method, which returns an XML description of the key pair

Both methods of obtaining the key information take a bool argument to specify whether the private key element should be included in the output. ImportParameters and FromXmlString allow previously generated keys to be imported.

Unlike the symmetrical algorithms, the RSA and DSA classes do not support encrypting and decrypting data through streams; the asymmetrical algorithm classes work on byte arrays. The following example demonstrates how to use the RSA algorithm to encrypt data and then decrypt it:

using System;
using System.Security.Cryptography;
using System.Text;

class RSAExample {

    RSAExample() {
        byte[] x_secret_message
            = Encoding.Default.GetBytes("C# for Java Developers");
        // create the RSA provider
        RSACryptoServiceProvider x_rsa_encryptor
            = new RSACryptoServiceProvider();
        // extract the parameters so we can decrypt the data later
        RSAParameters x_key_info = x_rsa_encryptor.ExportParameters(true);

        // encrypt the data
        byte[] x_encrypted_data
            = x_rsa_encryptor.Encrypt(x_secret_message, false);

        // create the RSA provider
        RSACryptoServiceProvider x_rsa_decryptor
           = new RSACryptoServiceProvider();
        x_rsa_decryptor.ImportParameters(x_key_info);

        // decrypt the data
        x_secret_message
           = x_rsa_decryptor.Decrypt(x_encrypted_data, false);
        Console.WriteLine(Encoding.Default.GetString(x_secret_message));
    }

    static void Main(string[] args) {
        new RSAExample();
    }
}

Hash Codes

Hash codes create fixed-length binary strings to uniquely identify a set of binary data; hash codes can be used to determine that the data that has been hashed has not been altered. The .NET Framework supports the following hashing algorithms:

  • MD5

  • SHA-1

  • SHA-256

  • SHA-384

  • SHA-512

The base class for all hash code algorithms is System.Security.Cryptography.HashAlgorithm, and following the model for other cryptographic functions, the .NET Framework provides an abstract class and an implementation class for each algorithm. Table 17-8 lists the classes.

Table 17-8. Hash Code Classes

Abstract Class

Implementation Class

System.Security.Cryptography.MD5

System.Security.Cryptography.MD5CryptoServiceProvider

System.Security.Cryptography.SHA1

System.Security.Cryptography.SHA1CryptoServiceProvider

System.Security.Cryptography.SHA256

System.Security.Cryptography.SHA256Managed

System.Security.Cryptography.SHA384

System.Security.Cryptography.SHA384Managed

System.Security.Cryptography.SHA512

System.Security.Cryptography.SHA512Managed

Hash codes are generated using the ComputeHash method derived from the HashAlgorithm class; this method will generate a hash code either from a byte array or by reading data from an instance of System.IO.Stream.

There are no class members to verify a hash code directly; to validate a hash code, the ComputeHash method must be called with the candidate data and the result compared with the original code. The following example demonstrates how to generate an MD5 hash code and print it to the console:

using System;
using System.Security.Cryptography;
using System.Text;

class MD5Demo {

    MD5Demo() {
        byte[] x_message
            = Encoding.Default.GetBytes("C# for Java Developers");

        // create the MD5 hash code provider
        MD5CryptoServiceProvider x_md5_provider
            = new MD5CryptoServiceProvider();

        // generate the hash code for the message
        byte[] x_hashcode = x_md5_provider.ComputeHash(x_message);

        // print out the hashcode
        foreach (byte x_byte in x_hashcode) {
            Console.Write(x_byte);
        }
    }

    static void Main(string[] args) {
        new MD5Demo() ;
    }
}

Digital Signatures

Digital signatures provide verification that data has originated from a certain individual; digital signatures rely on asymmetrical cryptography, and the processing that is required to generate a signature means that digital signatures are usually used to sign a hash code generated from the source data. See the preceding section in this chapter for more information on generating hash codes.

The base class for signatures is System.Security.Cryptography.AsymmetricSignatureFormatter. Unlike the other classes in the cryptography library, the signature classes do not provide abstract and implementation classes for each algorithm. The .NET Framework supports the signature formats RSA PKCS #1 version 1.5 and DSA PKCS #1 version 1.5.

For each signature format, the .NET Framework includes a formatter class (to produce a signature) and a deformatter class (to validate a signature). The constructors for the formatter and deformatter classes accept an instance of an asymmetrical algorithm implementation class, as detailed in Table 17-9.

Table 17-9. Digital Signature Formatter Classes

Signature Format

Formatter/Deformatter Class

Constructor Algorithm Class

RSA PKCS #1

RSAPKCS1SignatureFormatter

RSACryptoServiceProvider

 

RSAPKCS1SignatureDeformatter

 

DSA PKCS #1

DSASignatureFormatter

DSACryptoServiceProvider

 

DSASignatureDeformatter

 

The following example demonstrates how to produce an RSA digital signature for an MD5 hash code and then verify the signature:

using System;
using System.Security.Cryptography;
using System.Text;

class RSASignatureDemo{

    RSASignatureDemo() {
        byte[] x_message
            = Encoding.Default.GetBytes("C# for Java Developers");

        // create the MD5 hash code provider
        MD5CryptoServiceProvider x_md5_provider
            = new MD5CryptoServiceProvider();

        // generate the hash code for the message
        byte[] x_hashcode = x_md5_provider.ComputeHash(x_message);
        RSACryptoServiceProvider x_rsa_provider
            = new RSACryptoServiceProvider();
        RSAPKCS1SignatureFormatter x_formatter
            = new RSAPKCS1SignatureFormatter(x_rsa_provider);
        x_formatter.SetHashAlgorithm("MD5");

        byte[] x_signature = x_formatter.CreateSignature(x_hashcode);

        // print out the hashcode
        foreach (byte x_byte in x_signature) {
            Console.Write(x_byte);
        }

        RSAPKCS1SignatureDeformatter x_deformatter
            = new RSAPKCS1SignatureDeformatter(x_rsa_provider);
        x_deformatter.SetHashAlgorithm("MD5");
        bool x_verified = x_deformatter.VerifySignature(x_hashcode,
            x_signature);
        Console.WriteLine("Verified: " + x_verified);
    }

    static void Main(string[] args) {
        new RSASignatureDemo () ;
    }
}

Note that the SetHashAlgorithm method must be called to specify the format of the hash code that is to be signed or verified. Table 17-10 lists the mapping between the hash code algorithms and the string names that can be used with this method.

Table 17-10. String Representations of Hash Code Algorithms

Hash Algorithm

String Name

MD5

MD5

SHA-1

SHA1

SHA-256

SHA256

 

SHA-256

SHA-348

SHA348

 

SHA-348

SHA-512

SHA512

 

SHA-512

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset