Cryptographic Libraries
Overview
Microsoft .NET Framework is a development and execution environment that allows interoperability between programming languages, programming libraries, and the Windows platforms. The .NET Framework also provides a variety of tools to support major encryption algorithms, hashing algorithms, and digital signatures. Two programming languages, C# and Visual Basic, can be used to implement these algorithms through the .NET Cryptography classes. In this lab you will lean how to implement some basic cryptographic algorithms provided by the .NET class using C# programming.
This lab is divided into six sections. The first section is an introduction to the lab, which covers two basic C# program. The second section covers encryption under the .NET Framework. The third and fourth section covers authentication, hash algorithms, and digital signatures. The remaining two sections is the lab exercises and resources. This lab is used in Cryptography TELECOM 2820/INFSCI 2170.
Requirements
To complete this tutorial you will need a PC with Microsoft Visual C# .NET installed. Visual C# .NET is included in the Microsoft Visual Studio .NET package, which can found on the computers in the SIS lab. All examples in this lab manual were tested with Microsoft Development Environment 2003/.NET Framework version 1.1. You should also have basic knowledge of Object-Oriented Programming (OOP).
C# .NET Programming
C# is an OOP language; thus, the fundamental concepts of a class and object are similar to those of C++ or Java. The following examples should give you enough information on how to write basic C# programs. However, if you require additional resources you should read the MSDN C# Tutorial, and spend some time reading some of the other online tutorials [2]-[4] found in the references section. You can also refer to [5] and [6] for further studies if you are very serious. To understand how the .NET Framework works, you should skim through reference [7]. Furthermore, if you are looking for anything related to .NET or C# programming, the online MSDN library http://msdn2.microsoft.com/en-us/library/aa288436.aspx is very useful.
Sample Program 1
This section will introduce you to simple Microsoft Visual Studio .NET commands and instructions pertaining to programming in C#. You will also be given a simple C# program, which will be an informal introduction to the language if you are not familiar.
To launch Microsoft Visual Studio .NET open the program menu and select it. After starting Visual Studio to create a new program open the File Menu from the menu toolbar. Once inside the File Menu select New Project, which will invoke the New Project window. From the New Project window you can choose the type of project you wish to create. Select the Visual C# Project option and click Console Application for the template. Enter HelloWorld as the project name, which will also be th ename o your executable file in the HelloWorld/bin/Debug directory. Visual C# .NET will create a file Class1.cs by default. This file should be opened automatically. If you do not see the file, double-click on the file name shown in the Solution Explorer window to open it.
In the Solution Explorer window, right-click on Class1.cs and rename it to HelloClass.cs. Replace the content created by default in HelloClass.cs with the following code:
using System;
using System.Text;
class HelloClass {
Console.WriteLine("Hello World!\n");
string message_str = "Hello World!";
Console.WriteLine("String printout: {0}\n", message_str);
byte[] message_byte = Encoding.Default.GetBytes(message_str);
Console.WriteLine("Byte printout (in hex):\n");
int count = 0;
foreach (byte b in message_byte) {
count++;
Console.WriteLine("\n\nThe number of bytes in {0} is{1}\n", message_str, count);
return 0;
Note:
- Main(), with a capital "M", is the entry point for the program.
- In this program, you are using two Namespaces, System and System.Text.
- The System namespace is the required namespace that must be included in every C# program. The namespace restricts a name's scope, making it meaningful only within the defined namespace. The other namespace, System.Text is included here because you are using the Encoding class to convert a string into an array of bytes.
Compile the program by choosing Build or click the Build button. Check for any error messages and if there are none run the program by choosing Debug and select Start Without Debugging. Examine the source code and output line by line to ensure complete understanding of its workings. Basically, the program prints out the classic word Hello World in different ways.
When working on this lab exercise, you may have several test programs (*.cs) contained within your project. Make sure that the program you want to compile is "included" in the project space. This can be done by right-clicking on the file name in the Solution Explorer to set the property to include In project. Similarly, the program or class that will not be compiled must be set to Exclude From Project.
Sample Program 2
To create another program, in the Solution Explorer window, right-click on the project name, which is HelloWorld, and select Add. Once inside the Add menu select Add Class, and then enter HelloClass2.cs. Replace all the content created by default in HelloClass2.cs with the following code:
using System;
class HelloClass2 {
public byte[] Key;
public void InitializeKey() {
0x09, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0xAA };
public void SayHi() {
public string strY = "AES";
public int intX = 128;
//Program entry point.
class HelloApp {
public static int Main() {
c1.SayHi();
c1.InitializeKey();
int num_byte = 0;
foreach (byte b in c1.Key) {
num_byte++;
Console.WriteLine("\n" + "The number of bytes:\t" + num_byte);
Console.WriteLine("\nWe're using {0} with {1}-bit key.\n", c1.strY, c1.intX);
return 0;
Since the file HelloClass.cs in the previous example is still included in your project you have to set that file to Exclude From Project before compiling HelloClass2.cs. (see step 11). If you do not remember how to do this refer to the previous example.
Compile and run the program by selecting Debug and then Start Without Debugging. Examine the source code and the output line by line. Make sure that you understand everything in the program. This example shows how to access members of another class. Here the Main method is put inside the class HelloApp, which is used for program entry point. The InitializeKey method will be used later in an encryption example in the next section.
Now you have completed the basic C# programs. The next section will describe how to use classes provided by the .NET Security Framework for cryptography algorithm implementations.
Java Cryptography Extension
Java Cryptography has long been used by many programmers, however, it is used as an external package and requires extensive integrity checks on any piece of code. Recently, Sun Microsystem, the creator of Java, has released a new cryptographic packages that are included with Java 2 Standard Edition version 1.4 (J2SE v1.4). The packages are called Java Cryptography Extension (JCE). It has been widely used from small Java applications such as an Applet to large applications such as Web-based Automating Toolkit. In the current release, JCE has decent APIs that are easy to use. Also in this release, many new ciphers such as AES have been integrated. For more information about JCE. You can visit Sun's website for more information on JCE at http://java.sun.com/products/jce/.
Overview of JCE
JCE is composed of many classes, which you can review when you want to use them. However, there are a few core classes you should know.
The Cipher class
This is the core class that is required in every cryptographic program. The Cipher object defines what cipher will be used, the mode that will be used, and what padding method will be used when one is required. You have to include an initiation, which is used to specify whether the cipher is for encryption or decryption and what parameters are required. For example, it is required to specify the Initial Vector (IV) when you want to use it in Cipher Block Chaining (CBC) mode. If you use RC5 cipher, you also need to specify the key size, the input block size, and the operational rounds for encryption. The parameters are encapsulated in the AlgorithmParameters class. In some special cases, you will need to pass the parameters required for decryption so that the ciphertext can be correctly decrypted.
To do any cipher operation, you need to perform three. First, you need to initialize the cipher as described above. Then, you need to use update() to run the cipher. Finally, you need to use doFinal() to complete the cipher process. However, in JCE, you can use doFinal(plaintext) in most cases, which does not require the use of update().
The Cipher Stream classes
The cipher stream classes are CipherInputStream and CipherOutputStream. These classes are filter classes that are used in conjunction with FileInputStream and FileOutputStream classes. They encrypt the data stream providing confidentiality. This class can be used with file encryption or socket applications.
The KeyGenerator and KeyFactory Classes
The KeyGenerator class is used to generate a set of keys from a specific random number. However, to generate a random number that is secure, you ought to use SecureRandom class to generate a secure random number and use it to generate a key. The KeyFactory Class is used to store secret keys. It provides an abstract level for key storage.
The KeyAgreement Class
This class provides methods for key agreement protocol such as the Diffie-Hellman protocol. The agreement is composed of exchanging phases. Then, a shared secret or key can be generated after the exchanging phrases.
The Mac Class
This class is the core class for Message Authentication Code (MAC). Similar to Cipher class, the Mac class is initialized to specify what MAC algorithm and key that should be used. Then, it computes the MAC based on operations such as update(), doFinal() similar to Cipher class methods.
JCE Programming
This section will introduce you to some JCE APIs through the use of an example, which will be encrypting a "Hello World" program. You will be given sample code that will demonstrate how the JCE works, which can be found below.
First you will load some Java packages including Java security and Java crypto packages, which is done in line 1 - 4.
1 import java.security.*;
2 import javax.crypto.*;
3 import javax.crypto.spec.*;
4 import java.io.*;
On line 7, you need to specify the exception that will be thrown. On line 8-10 parameters are defined.
5 public class hello {
6
7 public static void main(String[] args) throws Exception {
8 String plaintext = "Hello World!";
9 String mykey = "1122334455667788"; // needed to be exactly 16 bytes
10
On line 13 a key is being defined using the SecretKeySpec class along with the algorithm that the key will be used for. Line 15 the IV is being definede since AES is being used in CBC mode. The JCE requires the IV to be exactly 16 bytes long.
12 // define a key
13 SecretKeySpec keyspec = new SecretKeySpec(mykey.getBytes(), "AES");
14 // define the IV
15 IvParameterSpec ivspec = new IvParameterSpec(myiv.getBytes());
Next the cipher will be instantiated, where you have to specify the cipher type, cipher mode, and the padding mode used. This is done on line 17. The backslash (/) is being used to specify these arguments in one string. This example uses AES in CBC mode with a PKCS#5 padding mode. There are a number of ciphers that are available to be used along with modes and padding methods that can be reviewed at the end of this section.
16 // set the cipher to desired operations
17 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
The init() method is used to set the mode for encryption or decryption, key, and the IV, which can be seen in line 19.
18 // initiate the cipher
19 cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
In line 21 the plaintext is being encrypted using the doFinal() method. If you want to handle multiple encryptions you should use the update() method to encrypt one block of data, and then use the doFinal() method to encrypt the remaining data. The doFinal() method will pad the data it is is less than the specified block size. The encryption process requires input and output to be in the form of a byte.
20 // Encrypt
21 byte [] encrypted = cipher.doFinal(plaintext.getBytes());
22
To make encrypted text readable, you will use Base64 encoding, which is done in line 24. This process is done by using the Base64Encoder class to encode the encrypted bytes. In line 25 the encoded bytes are being printed out to the screen.
23 // Encode
24 String encoded = new sun.misc.BASE64Encoder().encode(encrypted);
25 System.out.println(encoded);
26
After encrypting and encoding the data it must be decoded and decrypted. Line 28 decodes the data, where the Base64Decoder class is being used and returns the bytes it decodes.
27 // Decode
28 byte [] decoded = new sun.misc.BASE64Decoder().decodeBuffer(encoded);
29
Now you can decrypt the data, which requires you to have the same algorithm parameters that were used for the encryption. You can use the getParameters() method to retrieve the parameters from the AlgorithmParameters class that holds them. This is done in line 31. Line 32 the parameters are printed out to verify their correctness. In this example CBC is being used so the only parameter that is used is the IV
30 // get algorithm parameters for decryption
31 AlgorithmParameters aparam = cipher.getParameters();
32 System.out.println("Params " + aparam.toString());
33
After you have gotten the parameters the cipher can be instantiated, which is done in line 35. The ciphertext can now be decrypted using the doFinal() method as you can see in line 36. Line 37 the plaintext is being printed out.
34 // Decrypt using the same key
35 cipher.init(Cipher.DECRYPT_MODE, keyspec, aparam);
36 byte [] decrypted = cipher.doFinal(decoded);
37 System.out.println(new String(decrypted));
38 } // end of main
39 } // end of class
Available Ciphers and their Defaults
The following is a list of available ciphers and their default key size and block size.
Cipher | Default Key Size | Default Block Size |
---|---|---|
AES | 128 bits | 128 bits |
Blowfish | 56 bits | 64 bits |
DES | 56 bits | 64 bits |
DESede | 112 bits | 64 bits |
PBEWith <digest> and <encryption> | Variable due to encryption type | Variable due to encryption type |
RC2, RC4, and RC5 | 128 bits | 64 bits |
RSA | 1024 bits | Variable |
Available Modes
The following is a list of available modes that are available.
Mode | Description |
---|---|
NONE | No mode is used |
CBC | Cipher block chaining mode |
ECB | Electronic code book mode |
CFB | Cipher feedback mode |
OFB | Output feedback mode |
PCBC | Propagating CBC mode defined by Kerberos v4 |
Available Padding Methods
The following is a list of available padding methods.
Pad Method | Description |
---|---|
NoPadding | No padding is used, requiring the data's length to be the size of multiple blocks |
OAEPWith <digest> and <mgf> Padding | Use RSA OAEP padding |
PKCS5 Padding | PKCS # 5 standard padding |
SSL3 Padding | Use SSL v 3 padding (not available with J2SE v1.4) |
For more Java programming libraries, there are plenty of on-line resources and books. Please see the Resources section at the end of the document.
Exercises
From the previous sections, you have learned to write a cryptographic program using the OpenSSL library, and how to compile your program. In this section, you will be presented with a series of exercises requiring you to write programs using the knowledge you have learned from previous sections. You need to solve each problem using both Java and C.
If you are submitting your work include your name in the header of each program. You also need to include a printout of your program's result as seen on the screen. Use the "script" program on Unix to capture your screen typing. Zip all source code into a single folder where your file name is lab1-<your name>.zip. It is not necessary to submit the Worksheet Solutions document as long as you include a printout of the following answers.
Problem 1
Given a Base64 encoded ciphertext, key and IV that has been encrypted using AES in CBC mode, find the plaintext.
Based64-encoded ciphertext:
hTpVHO39rnpFyThzbcI+gg0rdBcbHL+5OqWFFY8QDF6T/nX4+O1lXFgJnDbRFaC1lL5hFY3uVsbQ8mP14yeSDNnD2dFnhBZLbkjqriE8IwJfcA3yL1Q3LhKQVUWPgPrZVvL98RtKl9ZEYCW/Sb7egw==
Key: Have you failed?
IV: This is your IV!
Hints:
- The encoded ciphertext, the key, and the IV are string-type
- Ciphertext should be on one line or one string to avoid the newline character (\n) in the string.
- For encoding in OpenSSL, use EVP_
- int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
- elen = EVP_EncodeBlock(encoded, ciphertext, clen);
- This function encodes a ciphertext string into encoded string, and encodes it for clen bytes, which is the total length of the ciphertext string. This function returns the amount of encoded string in bytes.
- int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);
- dlen = EVP_DecodeBlock(decoded, encoded, elen);
- In contrast, this function decodes the encoded string for elen bytes to decoded string, and returns the amount of decoded string in bytes.
- You key and IV must be 16 bytes long, which is used for AES cipher.
- int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
Problem 2
Given a partial secret key (the first 13 bytes) and the IV, try breaking an AES encryption in CBC mode by searching for the last 3 bytes of the key to find the associated plaintext.
Partial key (the first 13 bytes): {0x01,0x23,0x45,0x67,0x89,0x1a,0xbc,0xde,0xf0,0x01,0x23,0x45,0x67}
IV: {0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0x00}
Known beginning text: "The unknown message is:"
Base64-encoded ciphertext:
A8K+2+60yXYmEBQHOW4BN/2f/ubS5JMHy/B4hpGiaHDbR4qGLBL0AiwvUKi/th+lHt2meNQ82Zmfmnk2+rqd6dBERgBe82v7Smvri2T3VNuhu00h42l6CWHfPguguX5Ya1MNvmBxvMWygk21q+t0nA==
Hints:
- The partial key and the IV are in hexadecimal form, but the ciphertext are encoded using Base64
- Ciphertext should be on one line or one string to avoid the newline character (\n) in the string.
- You need to append three bytes at the end of the given partial key, and change them to find the right key.
- You will need to search within 224 output spaces and find the meaningful output, which is the original plaintext.
- The plaintext has known beginning. Thus, you will know you find the right key when the beginning of decrypted plaintext matches the known beginning.
- You can reuse your previous program to crack this problem.
- It may be easier if you start your program to search from smaller space size such as 256 (28) key spaces, and assume the second last byte. After you are confident in your program, you can increase the key search space to one or more bytes.
Problem 3
Implement AES encryption using the Counter Mode Encryption (CTR) or AES-CTR, and use your own key, IV, and message. Submit your key, IV, plaintext, and the Base64 encoded ciphertext for grading. Do not forget to encode your ciphertext using Base64 encoding so it can be readable for grading.
Problem 4
Use the AES-CTR mode to decrypt the given ciphertext using a given key and IV. Find and submit the associated plaintext. You will use a CTR cipher, a stream mode cipher, to encrypt a counter to produce a stream of pseudorandom numbers that are used to encrypt plaintext, which is simply an XOR encryption operation.
Key: What do you see?
IV: Who would ya be?
Ciphertext: (Encoded by Base64):
dIR1uyU0YhU9s3+jLwgzLhXQbbt2I2IeMqlo9jAZL35cyiW7ICJ5AXSve/MzHyIqW81xp21nahZ0r3v3NQA/K0GEdrszNCsMPKUr7CwdOStB0Wu3Ij4rETrgbvU5Hy96Uc1juD8kfhQguSWjcU0FMkeEUrc4NH8XOuBI6ykfNTxcyGn+fnYzT2DtOrpqWH8=
You MUST use AES in CFB mode to encrypt the counter, which starts from zero.
Ciphertext should be on one line or one string to avoid the newline character (\n) in the string.
Here is the pseudocode for the CTR program.
1 encrypted_counter = AES_Encrypt(counter);
2 for (the number of plaintext bytes)
3 if (we don't have enough encrypted counter bytes) {
4 increase the counter;
5 encrypt the counter;
6 }
7 ciphertext = pseudorandom plaintext;
On line 1, the first block of random bytes are generated by encrypting a counter number. Using AES you will have 16 random bytes from one encryption. This means you will need 6 AES encryptions for plaintext with a length between 81 - 96 bytes. Lines 3 -6 will check whether there are enough encrypted bytes for a XOR operation. If not the counter should be increased. Line 7 a XOR operation is performed on the plaintext using the random bytes.
CTR's decryption mode is similar to the process of encrypting the counter in the previous step. To find the associated plaintext use XOR operations on the ciphertext using the random bytes generated by the counter. For more information about the CTR mode visit http://csrc.nist.gov/CryptoToolkit/modes/workshop1/papers/lipmaa-ctr.pdf.
Hints:
- Define a counter as a 16-byte string for simplicity.
- To encrypt a block of 16 bytes of the counter using AES in CFB mode.
- For each 16 bytes of plaintext, you need to do the counter encryption, and need to increase the counter by one to encrypt other 16 bytes for next encryption
- Make sure your counter start from zero.
Worksheet Solutions
The following questions you are required to submit.
Problem 1. Plaintext ____________________________________________________________________
Problem 2. The last three bytes of the key are ______________________________________________
Plaintext ____________________________________________________________________
Problem 3: Message ____________________________________________________________________
Key ________________________________________________________________________
IV __________________________________________________________________________
Ciphertext ___________________________________________________________________
Problem 4: The plaintext is _______________________________________________________________