Programming with Cryptographic Libraries

  1. Tutorial Overview
    1. OpenSSL: Cryptography Library and SSL/TLS Toolkit
    2. Overview of OpenSSL
    3. Lab Requirements
  2. .NET Cryptography Overview
    1. Cryptography with C#
    2. Symmetric Encryption
    3. Basic Encryption Example
    4. Program Explanation
  3. Message Authentication
    1. Hashing Algorithms
    2. Keyed Hashing Algorithms
  4. Digital Signatures
    1. Signing and Verifying Data
    2. Transmitting Cryptographic Parameters Between Applications
  5. Exercises
  6. References

Lab Overview

Data security has become important as more information is in a digital form. We need security services such as Confidentiality to protect data from unauthorized access. Data authentication is also another important security service, as it provides a method to prove the authenticity of data. In the world of digital communications, in addition to the first two services, data integrity is also essential. The data integrity service is not to protect the data from being tampered with, but it provides a way to prove whether it has been modified. These three services are important; however, other security services are becoming more attractive for the digital world such as anonymity and service availability. This tutorial is used in Cryptography TELECOM 2820/INFSCI 2170.

In this exercise, you will learn how to protect your data using confidentiality, which is commonly called encryption. You will use two different programming languages, C and Java, for encryption. You will also learn how difficult it is to crack an encrypted piece of code. Finally, you will learn how to create your own encryption mode and justify what you did. This tutorial is divided into five sections. The first section describes OpenSSL and the lab requirements. The second section covers using OpenSSL. The third section covers the use of Java Cryptography Extensions. The fourth and fifth sections are user exercises and resources.

OpenSSL: Cryptography Library and SSL/TLS Toolkit

Due to popular web transactions and a need to transmit confidential information, a secure transfer mode was created by Netscape Communications Corporation. They introduced the Secure Socket Layer (SSL) framework for Hypertext Transfer Protocol (HTTP) for securing web transactions on their web browser. As SSL become popular, it was immediately deployed for other web browsers. As the number of web services and users continue to grow the demand for secure transactions dramatically increased. This increase in secure transactions is not only for HTTP, but also for security services that us other protocols on the top of Transmission Control Protocol (TCP). Internet Engineering Task Force (IETF) has established a working group called Transport Layer Security (TLS) in 1996, with the goal to standardize the security protocol for the Transport Layer.

The OpenSSL Project was established to create a software library or toolkit for SSL/TLS. It is a collaborative effort to develop a robust, commercial-grade, fully featured, and Open Source toolkit implementing the SSL v2/v3 and TLS v1 protocols as well as a full-strength general purpose cryptography library. The project is managed by a worldwide community of volunteers that use the Internet to communicate, plan, and develop the OpenSSL toolkit and its related documentation. OpenSSL is based on the excellent SSLeay library developed from Eric A. Young and Tim J. Hudson around 1996. The OpenSSL toolkit is licensed under a dual-license (the OpenSSL license plus the SSLeay license) , which basically means that you are free to get and use it for commercial and non-commercial purposes as long as you fulfill the conditions of both licenses.

In this lab, you will be introduced to some concepts of OpenSSL's application programming interface (API), which will allow you to create your own program to solve a particular crypto problem such as encryption or decryption. To accomplish this you will also learn how to use the crypto library in OpenSSL.

Overview of OpenSSL

OpenSSL includes APIs for SSL/TLS protocol, in addition to several cryptographic algorithms for confidential services based on both secret key and public key cryptography. It also includes hash/MAC mechanisms for message integrity services and digital signature for non-repudiation services. Along with SSL/TLS, a digital certificate is an important part, which you will be able to create using OpenSSL. OpenSSL supports the creation of digital or public key certificates based on thee X.509 standard, the conversion between X.509 and ASN.1 encoding standards, and PEM certificates. The OpenSSL toolkit includes the following components:

•   Libssl.a: Implementation of SSLv2, SSLv3, TLSv1 and the required code to support both SSLv2, SSLv3 and TLSv1 in the one server and client.
•   libcrypto.a: General encryption and X.509 v1/v3 stuff needed by SSL/TLS but not actually logically part of it. It includes routines for the following:
      •   Ciphers: DES, RC2, RC4, RC5, Blowfish, IDEA, AES
      •   Digests: MD2, MD5, SHA-0, SHA-1, SHA-128, SHA-256, SHA-512, MDC2
      •   MAC: HMAC
      •   Public Key: RSA, DSA Diffie-Hellman key-exchange/key generation.
      •   X.509v3 certificates: X509 encoding/decoding into/from binary ASN.1 and a PEM based ASCII-binary encoding, base64 encoding
      •   RSA and DSA certificate generation
•   openssl: A command line tool that can be used for: creation of RSA, DH and DSA key parameters, creation of X.509 certificates, CSRs and CRLs, calculation of Message Digests Encryption and Decryption with Ciphers SSL/TLS Client and Server Tests, Handling of S/MIME signed or encrypted mail

Lab Requirements

To complete the C portion of this lab you will need a workstation in SIS Lab or a Windows-based machine that already has OpenSSL installed. The SIS workstations already have OpenSSL installed on them, so using them will require less work on your part. If you wish to install OpenSSL on your computer, please read the instructions at http://www.openssl.org.

To complete the Java portion you will need a workstation in SIS Lab or a Windows-based machine that already has the latest Java 2 Standard Edition (J2SE) installed. Again J2SE is already installed on the computers in the SIS lab. If you insist to install java on your computer, please read the instructions at http://java.sun.com/products/jce/downloads/index.html. If you require an overview of Java or C you should visit http://java.sun.com.


.NET Cryptography Overview

Cryptography with C# .NET Framework

The required main namespace for this lab exercise is System.Security.Cryptography, which provides modern cryptographic services such as symmetric and asymmetric encryption, hashing algorithms, and digital signatures. To see all the classes provided by this namespace, see the System.Security.Cryptography topic in the MSDN documentation at http://msdn.microsoft.com/library/.

Symmetric Encryption

In this section, we will learn how to encrypt data using symmetric algorithms. With classes defined under the System.Security.Cryptography Namespace, you can implement DES, RC2, Triple-DES, and Rinndael/AES cryptosystems with the key size and block size attributes described in the table below.

NameBlock SizeKey Length (bits)
DES6456
RC26440, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128 (56-bit keys, expressed as 64-bit )
Triple-DES64Numbers
Rijndael (AES)128, 192, 256128, 192, 256

Basic Encryption Example with C#

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;
 
class CryptoClass {
 
public byte[] Key;
public byte[] IV;
 
public int KeySize, BlockSize, FeedbackSize;
public CipherMode Mode;
public PaddingMode Padding;
 
public void Initialize() {
 
Key = new byte[] { 0xFC, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
0x09, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0xAA};
 
IV = new byte[] { 0x99, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
0x09, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16};
 
KeySize = 128;
BlockSize = 128;
FeedbackSize = 128; //This is for feedback mode only
Mode = CipherMode.ECB;
Padding = PaddingMode.Zeros;
 
} // end of Initialize
 
public string Encrypt(string plaintext) {
 
// get a byte array from a string of plaintext
byte[] x_plaintext = Encoding.Default.GetBytes(plaintext);
 
// create the encryption algorithm
SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
 
x_alg.KeySize = KeySize;
x_alg.BlockSize = BlockSize;
 
// This is for feedback mode only.
// The feedback size cannot be greater than the block size.
x_alg.FeedbackSize = FeedbackSize;
 
Console.WriteLine("KeySize = {0}",x_alg.KeySize);
Console.WriteLine("BlockSize = {0}",x_alg.BlockSize);
Console.WriteLine("FeedbackSize = {0}",x_alg.FeedbackSize);
 
// set Key
x_alg.Key = Key;
 
// set IV
x_alg.IV = IV;
 
// set padding and cipher modes
x_alg.Mode = Mode;
x_alg.Padding = Padding;
 
Console.WriteLine("\nMode: {0}",x_alg.Mode);
Console.WriteLine("Padding: {0}",x_alg.Padding);
 
// create an ICryptoTransform that can be used to encrypt data
ICryptoTransform x_encryptor = x_alg.CreateEncryptor();
 
// create the memory stream
MemoryStream x_memory_stream = new MemoryStream();
 
// create the CryptoStream that ties together the MemoryStream and the ICryptostream
CryptoStream x_cryptostream = new CryptoStream(x_memory_stream, x_encryptor, CryptoStreamMode.Write);
 
// write the plaintext out to the cryptostream
x_cryptostream.Write(x_plaintext, 0, x_plaintext.Length);
 
// close the CryptoStream
x_cryptostream.Close();
 
// get the ciphertext from the MemoryStream
byte[] x_ciphertext = x_memory_stream.ToArray();
 
// close memory stream
x_memory_stream.Close();
 
// convert from array to string
string cipher_Tx =Encoding.Default.GetString(x_ciphertext);
 
Console.WriteLine("\n{0}\n",plaintext);
// print out the plaintext
 
Console.WriteLine("\n\t\tPlaintext bytes in Hex:\n");
 
foreach (byte b in x_plaintext) {
 
Console.Write("{0:X2} ", b);
 
} // end of foreach
 
Console.WriteLine("Ciphertext:\n");
Console.WriteLine("{0}\n", cipher_Tx);
 
x_encryptor.Dispose();
 
x_alg.Clear();
 
return cipher_Tx;
 
} // end of Encrypt  
} // end of CryptoClass
 
class CryptoApp {
 
public static void Main() {
 
string ciphertext;
 
CryptoClass c1 = new CryptoClass();
c1.Initialize();
 
// string of plaintext
string ptext = "We Love Cryptography Class!";
 
ciphertext = c1.Encrypt(ptext);
 
// print out the ciphertext
// ...
 
} // end of Main
 
} // end of CryptoApp

Program Explanation

The class CryptoClass contains two methods, which are Initialize and Encrypt. The Initialize method is used to generate the values of the key and initial vector (IV). The Encrypt method receives a string of plaintext as an argument, and then converts the string into an array of bytes.

In this simple example you will set the values of the key and IV manually. Alternatively, the key and IV can be generated randomly using x_alg.GenerateKey() and x_alg.GenerateIV(), respectively. Since AES is a block cipher, you need to specify the mode of operation and block padding on the Mode and Padding members. The following CipherMode options are available: ECB, CBC, CFB, CTS, OFB PaddingMode: Zeros, PKCS7.

To create or instantiate an encryption algorithm object (i.e., x_alg), use the Create method of the SymmetricAlgorithm class with the argument Rijndael as SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael"); You can use this object to set the key, IV, and all other cipher attributes.

In the first stage of encryption, the class SymmetricAlgorithm uses the ICryptoTransform interface for the cryptographic transformation from plaintext to ciphertext or the reverse for decryption. This interface has to be used with the CryptoStream class, which defines a stream that links data streams to cryptographic transformations. The CryptoStream class requires a target data stream, the transformation to use, and the mode of the stream as the arguments. The target data stream is an instance of the MemoryStream class, which is defined under the System.IO namespace. This class defines a stream that uses memory for backing. In the final stage, the ciphertext is obtained from the memory stream.

Before terminating the program, all sensitive information such as the key, IV, or other random seed values left in the memory should be destroyed. This can be achieved by using the Clear method for the instances of the algorithm implementation class, and the Close method for the Memory Stream or CryptoStream objects. The resources used by ICryptoTransform objects can be released by the Dispose method.

Message Authentication

The .NET Framework supports five hashing algorithms, (MD5, SHA-1, SHA-256, SHA384, and SHA-512) and two keyed hashing algorithms (HMAC-SHA-1 and MAC-Triple-DES).

Hashing Algorithms

An implementation of the hashing algorithm is much simpler than the encryption demonstrated in the previous section on Symmetric Encryption. In this section, you will not have to use the ICryptoTransform, CryptoStream, and MemoryStream objects. The following table lists the hashing algorithms.

Hashing AlgorithmInput block size (bits)Hash code size (bits)
MD5512128
SHA-1512160
SHA-256512256
SHA-3841024384
SHA-5121024512

To create an instance of the hashing implementation class HashAlgorithm, you would use HashAlgorithm h_alg = HashAlgorithm.Create("SHA256"); to create the object h_alg, for the SHA-256 algorithm. You can omit the hyphen between SHA and the number 256. For example, you can use either SHA-256 or SHA256 for an argument of the Create method. To compute a hash code, you should use the ComputeHash method of the HashAlgorithm class as: byte[] h_code = h_alg.ComputeHash(byte[] message); This method takes a byte array of a message as an argument, and returns a byte array of a hash code.

Keyed Hashing Algorithms

The hashing algorithms can be made even more secure by using a secret key. The .NET Framework supports two hybrid types of keyed hashing algorithm as follows.

The Create method will take a string value, HMACSHA1 for the HMAC-SHA-1 algorithm, and MACTripleDES for the MAC-Triple-DES algorithm. Since you are dealing with keyed hashing algorithms here, how would you set up the key? You can use the same concept as described in the symmetric encryption section to set up the key. Again, both the message and key must be converted to byte arrays before hashing. After setting the key value, you can compute a hash code using the ComputeHash method, similar to what described in the Hashing Algorithms section.

Digital Signatures

The .NET Framework supports two algorithms for digital signature schemes: the RSA signature and the Digital Signature Algorithm (DSA.) The required classes are DSACryptoServiceProvider and RSACryptoServiceProvider for the DSA and RSA implementation, respectively. To create an instance of the DSA algorithm class, dsa, you should use DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(); and the object instantiation of the RSACryptoServiceProvider class is similar.

The default characteristics of a digital signature provided by the .NET framework will be different each time a message is signed, even though the message is not changed. This randomness, in the DSA case, is caused by random numbers generated by the .NET Framework. In the RSA case, the public-private key pair and other performance-enhancement parameters is randomly generated each time a message is signed, thus obtaining different signatures. Unfortunately, how to manually set the key and some random parameters is not documented in the MSDN library. However, this would not be a big problem since having keys generated randomly by a computer instead of assigning these values manually is prefered. For example, in the RSA case, the public-private key pair used in .NET Framework is a set of large numbers with 1024-bit keys.

Signing and Verifying Data

The .NET Framework provides methods for signing and verifying data, which can be seen below.

AlgorithmActionMethodReturn type
DSASignSignData(byte[ ] data);byte [ ]
VerifyVerifyData(byte[ ] data, byte[ ] sig);bool
RSASignSignData(byte[ ] data, object h_alg);byte [ ]
VerifyVerifyData(byte[ ] data, object h_alg, byte[ ] sig);bool

The value sig denotes a byte array of the signature obtained after signing the message data, which is found in the verifyData methods. In RSA scheme, an instance of the hashing algorithm class need to be created fist, and then specified in both the SignData and VerifyData methods, which is denoted by the h_alg. The return type, bool, is a Boolean value, which equals one if the signature is valid, and equals zero otherwise.

Transmitting Cryptographic Parameters Between Applications

The .NET Framework provides methods for exporting and importing public or private parameters stored in the DSAParametersand RSAParametersstructures. You more infirmation on this topic you can look in the MSDN documentation for more details, but you do not need to know about all the members of these structures. As mentioned before, a digital signature created by .NET is random. The DSA signature relies on random numbers. Unfortunately, the MSDN library does not explain a definition of each parameter, and the following notation is not conventional. The public parameters (byte array type) are P, Q, J, G, and Seed, which are of a byte array type. The private parameters are X and Y. All parameters are members of the DSAParameters structure.

For the RSA signature, the public-private key pair is randomly generated, and stored in the RSAParameters structure. The public key members are Modulus and Exponent and the private key is D. How do you import or export these parameters? For example, Alice signs a message, and then transmits her public parameters to Bob so that he can use these parameters to verify the message if it comes from Alice.

There are two ways to achieve this. The first is to use the ExportParameters and ImportParameters methods After the signature has been created, Alice exports her algorithm parameters as DSAParameters para = dsa.ExportParameters(bool); ,where bool denotes a string of Boolean value (i.e., true or false). The argument is false if you want to export only the public parameters, and is true to export both the public and private parameters. These two Boolean cases are used for both the DSA and RSA signatures. After exporting parameters, you can access some parameters, e.g., the byte array P as para.P. The other application (e.g., Bobs) can simply obtain these parameters by using dsa_Bob.ImportParameters(para);

For RSA, the Import and export procedures are the same. You will use the ToXmlString and FromXmlString methods. The .NET framework also provides an alternative, which is more convenient, to transmit algorithm parameters between applications with an XML (Extensible Markup Language) string. Analogous to the ExportParameters method, we can use the ToXmlString(bool) method to create and return an XML string representation of the algorithm parameters, where bool denotes a string of Boolean value as described above. For example, the RSA key pair parameters can be exported as string key_pair = rsa.ToXmlString(bool); ,where rsa is an instance of the RSACryptoServiceProvider class. Similar to the ImportParameters above, these parameters can be obtained by using rsa_Bob.FromXmlString(key_pair);

Exercises

rom the previous sections, you learned about encryption, hashing, and digital signatures for use with C# and the .NET Framework. In this section you will be presented with a number of exercises requiring you to use the knowledge you learned from the previous sections along with a number of questions.

If you are submitting your work, include your name in the header of each program for problem 1 - 7. Each program must be named according to its associated problem, e.g., Problem1.cs. . . Problem7.cs. Zip all the files into one file and upload it onto the class FTP server. You must include printouts of each program and answers to each question.

Problem 1

Encrypt a plaintext with the following options: -AES-CBC mode with PKCS#7 padding mode -128-bit key size and block size.

Key = { 0xFC, 0x02, 0xC6, 0x04,
0x05, 0x06, 0x07, 0x08,
0x27, 0x10, 0x83, 0x12,
0x3B, 0x14, 0x15, 0xAF }
IV = { 0x99, 0x5C, 0x8F, 0x04,
0x05, 0x06, 0x07, 0x08,
0x09, 0x8E, 0x11, 0x12,
0x13, 0x14, 0x15, 0x99 }

Plaintext: Identification and Two-factor Authentication

What is the Base64-encoded ciphertext?

Consider the Convert.ToBase64String(byte[] array) and Convert.FromBase64String(string s) methods.

Problem 2

Write a decryption program to verify your answer in Problem 1.

Hints:

Problem 3

Given ciphertext and plaintext use the information provided in Problem 1 except for the key to find the last missing three bytes of the key.

Base64-encoded ciphertext: T6+b7B9/iXa5ennZ+dpG/mmCURaBiTthLHitnmZN5vY=
Plaintext: Central Intelligence Agency
Partial key (first 13 bytes): Partial_Key = { 0xFC, 0x02, 0xC6, 0x04,

0x05, 0x06, 0x07, 0x08,
0x27, 0x10, 0x83, 0x12,
0x3B }

What are the last three bytes of the key in Hexadecimal form?

Problem 4

Given a message you must compute the hash.

Message: Programming .NET Security Part I

What is the hash code?
Comment on the results.

Change the message to: Programming .NET Security Part V

What is the hash code?
Comment on the results.

Problem 5: Keyed Hashing Algorithm

Compute the HMACSHA1 hash code using the given message.

Message: Martin Luther King, Jr.
Key: I Have a Dream

What is the output hash code?

Problem 6: DSA Digital Signature

Write a DSA digital signature program to show the following processes.

  1. Alice signs the message: Digital Signature and Electronic Authentication Law
  2. She exports her public parameters using the ExportParameters method.
  3. Bob receives the signature and imports the public parameters
  4. Bob verifies the signature.

The output printout must show both the signature and the byte arrays of the random number P and Q, which are Alice's public parameters.

Problem 7: RSA Digital Signature

Write a RSA (with SHA-1 hashing algorithm) digital signature program to show the following processes:

  1. Alice signs the message: Public-Key Cryptography Standards (PKCS)
  2. Do the same as in Problem 6, but use the XML parameter exporting/importing instead.

The output must show both the signature and its associated XML string of public keys. You will see the Modulus and Exponent values inside this XML string.

References

  1. MSDN C# Tutorials, http://msdn.microsoft.com/library/en-us/csref/html/vcoriCSharpTutorials.asp
  2. Function X C# Tutorial, http://www.functionx.com/csharp/
  3. C# Station Tutorial, http://www.whoishostingthis.com/resources/c-sharp/
  4. Softsteel C# Tutorial, http://www.softsteel.co.uk/tutorials/cSharp/contents.html
  5. Jesse Liberty, Programming C# (Third Edition), O'Reilly, 2003.
  6. Andrew Troelsen, C# and the .NET Platform (Second Edition), Apress, 2003.
  7. .NET Framework Developer Center: Getting Started, msdn.microsoft.com/netframework/gettingstarted/default.aspx
  8. Peter Thorsteinson and G. Gnana Arun Ganesh, .NET Security and Cryptography, Pearson Education, 2004.
  9. Adam Freeman and Allen Jones, Programming .NET Security, O'Reilly, 2003.