CS579A/CpE579A: Foundations of Cryptography

Lab2: Simple Shared-Key Generation Utility

[ Introduction | Software Setup | Lab Specification | Design Guidelines | Hand-in Procedure | Collaboration Policy | Useful Functions ]


Introduction

In this lab, you will build a simple utility that uses public-key cryptography to securely generate shared secret keys between two parties. You will then be able to reuse your code from Lab 1 to create encrypted files that only the other party (and you) will be able to decrypt. By doing the lab, you will familiarize yourself with the functionalities enabled by public-key cryptography, and with the some of the issues associated with key management and certification.

Software Setup

Libraries

You will be using the same libraries as in Lab 1. We have set up the appropriate libraries and header files so that you can compile against (libdcrypt) on the Linux lab machines. If you are instead working on your own machine, you should install the dcrypt library in your system. (You will also need to have the GNU MP and dmalloc libraries installed in your machine.)

Skeleton code

The files you will need for this lab are available in lab2.tar.gz. To install them in your account, download lab2.tar.gz and type the following:

% tar xzf lab2.tar.gz
% cd lab2
% ls
Makefile        pv_misc.c       skgu_cert.c    skgu_nidh.c
pv.h            skgu.h          skgu_misc.c    skgu_pki.c 
% make
gcc -g -O2 -ansi -Wall -Wsign-compare -Wchar-subscripts -Werror -I. -I/usr/local
/include/ -I/home/nicolosi/cs579/devel/include/  -c skgu_pki.c
...
gcc -g -O2 -ansi -Wall -Wsign-compare -Wchar-subscripts -Werror -o skgu_nidh skg
u_nidh.o skgu_cert.o skgu_misc.o pv_misc.o -L. -L/usr/local/lib/  -L/home/nicolo
si/cs579/devel/lib/ -ldcrypt -lgmp
% 

Toy Public-Key Infrastructure

As we will see when discussing the lab specification, the cryptographic scheme that you will implement for this lab relies on a Public-Key Infrastructure. What we mean by this is that, before starting to use the utility to generate shared secrets and exchange encrypted files, both parties, Alice and Bob, know the public key of a Certification Authority, whose job is to produce certificates—signed statements binding identities to public keys. We have already implemented for you a simple certificate generation utility to setup a toy Public-Key Infrastructure: take a look at its source files (skgu_cert.c, skgu_misc.c, skgu_pki.c). To use the skgu_pki utility to generate certificates, first run it as follows:

% ./skgu_pki init
% 

This will create a directory named .pki/ within the current directory, along with two files: .pki/ca.sk and .pki/ca.vk, holding keys needed respectively to sign and to verify certificates.

Once the Public-Key Infrastructure has been initialized using the init command for skgu_pki, you can issue certificates using the cert command:

% ./skgu_pki cert -g alice.priv alice.pub alice
% 

This will create three files: alice.priv, alice.pub and alice.cert. The first two files store a newly generated private key/public key pair for non-interactive Diffie-Hellman key generation (cf. the lab specification). The last file contains a certificate binding the public key just placed in alice.pub to the identity alice. Such certificate is signed using the signing key that was generated the last time you ran skgu_pki init.
If you don't provide the -g option, then skgu_pki cert will not generate a new private/public key pair for you. This is useful so that you can create certificates for existing public keys as well: for example, Alice might want to create a certificate (under her certification authority) for a public key that Bob got from his own certification authority.

You can choose a different name for the certificate file using the -o option:

% ./skgu_pki cert -o alice.cert.new -g alice.priv alice.pub alice  
% ls alice.cert*
alice.cert      alice.cert.new

By default, certificates generated with skgu_pki cert are valid for 30 days. You can change this behavior using the -e option; for example, the following creates a certificate set to expire in 100 days:

% ./skgu_pki cert -e 100 -g bob.priv bob.pub bob
% 

To check the validity of a certificate created using skgu_pki cert, give the check command to skgu_pki:

% ./skgu_pki check alice.cert alice.pub alice
Valid certificate

Lab Specification

Your shared key generation utility will consist of a single program, skgu_nidh, implementing a non-interactive variant of the Diffie-Hellman protocol on top of a toy Plublic-Key Infrastructure.

After completing coding of skgu_nidh, you will build the utility using make with the provided Makefile:

% make 
gcc -g -O2 -ansi -Wall -Wsign-compare -Wchar-subscripts -Werror -I. -I/usr/local
/include/ -I/home/nicolosi/cs579/devel/include/  -c skgu_nidh.c
gcc -g -O2 -ansi -Wall -Wsign-compare -Wchar-subscripts -Werror -o skgu_nidh skg
u_nidh.o skgu_cert.o skgu_misc.o pv_misc.o -L. -L/usr/local/lib/  -L/home/nicolo
si/cs579/devel/lib/ -ldcrypt  -lgmp
%

(Notice that you may have to fiddle with the Makefile if you are working on your own linux box.)

Now, initialize the PKI (if you haven't done so yet), and create certificates for Alice and Bob:

% ./skgu_pki init
% ./skgu_pki cert -g alice.priv alice.pub alice
% ./skgu_pki cert -g bob.priv bob.pub bob
% 

Next, use Alice's private key with Bob's public key:

% ./skgu_nidh alice.priv alice.cert alice bob.pub bob.cert bob example1 
% ls example1.* 
example1.b64 
% cat example1.b64 
ahPKOu+Nb5xLBhubOOVp+n7c/HS9vjAeMGuQxQu7QcU= 
% rm example1.b64
%

A brief explanation of what should happen here is the following. skgu_nidh imports the public key in bob.pub and the certificate in bob.cert, and checks that the certificate is valid for the public key with respect to the id bob. Next, the private key in alice.priv and the corresponding certificate in alice.cert are loaded, and a check is made to ensure that the certification authority that issued bob's certificate is the same as the one that issued alice's. (Note that in general this is not the only case in which alice should trust someone's certificate, but for simplicity will stick with that for this lab.)

If the certificate checks out, skgu_nidh computes the shared key (as described below), and stores it base64-encoded in example1.b64 (or skgu_key.b64, if no label is specified as last argument to skgu_nidh).

Using Bob's private key with Alice's public key should result in the same outcome:

% ./skgu_nidh bob.priv bob.cert bob alice.pub alice.cert alice example1 
% ls example1.* 
example1.b64 
% cat example1.b64 
ahPKOu+Nb5xLBhubOOVp+n7c/HS9vjAeMGuQxQu7QcU= 
%

Design Guidelines

In a non-interactive Diffie-Hellman key exchange, each party is assumed to have preliminary obtained (e.g.,, via email) the public key for the other party, certified under the signing key of a mutually trusted certification authority. After having verified the certificate and the public key for the other party, you will derive the shared key Ks according to the following equation:

Km = SHA1 (DH(Alice.pub,Bob.pub), first_id, second_id)
Ks0 = HMAC-SHA1 (Km, label, "AES-CBC")
Ks1 = HMAC-SHA1 (Km, label, "HMAC-SHA1")
Ks = < concatenation of first 16 bytes of Ks0 with first 16 bytes of Ks1 >

DH(.,.) here represents the Diffie-Hellman function: DH(ga mod p, gb mod p) = gab mod p. first_id and second_id correspond's to the id used for the two parties in the command line of skgu_nidh (in lexicographical order, to ensure that both parties will be computing the same value). The string label is a piece of side information that is specified on the command line of skgu_nidh (defaults to "skgu_key" when no label is specified). The two strings "AES-CBC" and "HMAC-SHA1" are needed to make sure that two chunks of pseudo-random bytes can be derived from the master key, as per the design guidelines of Lab 1.
Note that an eavesdropper who knows both public keys (but neither private key) can easily obtain the values ya=ga mod p and yb=gb mod p: however, it is widely believed that no efficient computation can recover DH(ya,yb)=gabmod p: this is known as the Computational Diffie-Hellman Assumption.

Hand-In Procedure

You must submit two files:

To build a software distribution, run the following commands (from the directory where your source files are located):

% cd ..
% tar cf skgu.tar lab2/
% gzip skgu.tar
%

(If the name of the directory containing your sources is not lab2, then substitute the appropriate name in the second command above.)

To create a script file, use the script command. When you run script, everything you type gets saved in a file called typescript. Press CTRL-D to finish the script. For example:

% script
Script started, output file is typescript
% ./skgu_pki init 
% ./skgu_pki cert -g alice.priv alice.pub alice 
% ./skgu_pki cert -g bob.priv bob.pub bob 
% ./skgu_nidh alice.priv alice.cert alice bob.pub bob.cert bob example1 
% ls example1.* 
example1.b64 
% cat example1.b64 
ahPKOu+Nb5xLBhubOOVp+n7c/HS9vjAeMGuQxQu7QcU= 
% rm example1.b64 
%
% ./skgu_nidh bob.priv bob.cert bob alice.pub alice.cert alice example1 
% ls example1.* 
example1.b64 
% cat example1.b64 
ahPKOu+Nb5xLBhubOOVp+n7c/HS9vjAeMGuQxQu7QcU= 
%
% ^D
% ^D Script done, output file is typescript 
% 

To turn in your distribution and script file, e-mail the files skgu.tar.gz and typescript to me at "nicolosi AT cs DOT stevens DOT edu" by 11:55pm on Thursday, May 7, 2009.

This completes the lab.

Collaboration Policy

You must write all the code you hand in for the programming assignments, except for code that we give you as part of the assigment. You are not allowed to look at anyone else's solution. You may discuss the assignments with other students, but you may not look at or copy each others' code.

Useful Functions

Below is a description of some of the functions implemented in the dcrypt library that you may find useful in completing the assignment. You will need to include the dcrypt.h header file to access these functions. You may also want to take a look at these sample programs (tst.c, tst_sha1.c) to see some of these functions in action.

Data serialization

Big Number Functions

Cryptographic Hash Functions

The SHA-1 [FIPS-180-1] hash function hashes an arbitrary-length input (up to 2^64 bytes) to a 20-byte output. SHA-1 is known as a cryptographic hash function. While nothing has been formally proven about the function, it is generally assumed that SHA-1 is one-way and collision-resistant. These properties are defined as follows:

The libraries you are using contain an implementation of SHA-1.

Sometimes the input that you want to hash is so long that it is inconvenient to store it entirely in memory before being able to hash it. This is the case for example when hashing the entire content of a file into a short digest.
For this reason, the libraries you are using allow you to process a long input "one chunk at a time." To do that, you should use a struct called sha1_ctx, which will store the "partial digest" as you keep providing new input to be hashed. You should manipulate sha1_ctx structs with the following functions:

Pseudo-Random Functions

Pseudo-Random Functions (PRFs) are a deterministic symmetric-key primitive that securely "stretches" a single (pseudo-)random "master" key into several (computationally) independent pseudo-random keys. (In fact, the amount of derivable pseudo-random keys is exponential in the bitlength of the master key, something not possible with Pseudo-Random Number Generators).

You use PRFs as follows. Let's say that you want to derive a key k_s for a specific purpose from a master key k_m. You cook up a string, or label, to represent the task at hand. Any convention would do, as long as the labels correspond uniquely to the tasks. One possible convention is the following: Say that the key that you are deriving will be used to encrypt files from Alice to Bob. Then you would use a label like: "MY-APP:task=encryption,opt=(sndr=alice,rcvr=bob)".
(In fact, it would be a good idea to also include some timestamp information in the label. That complicates slightly the process of reconstructing the label at a later time, so we omit that from this toy example.) Then, you use the master key k_m to key the PRF, and give the label as input to the PRF. The resulting output can be safely used as a key, and it will have the property of looking random to any (efficient) attackers who knows the label, and possibly even the keys derived from other labels, as long as the attacker has never seen the master key.

As it turns out, the Keyed-Hash Message Authentication Code (HMAC) [FIPS-198a] is a not just a secure Message Authentication Code, but also a secure pseudo-random function, based on the use of any cryptographic hash function, like SHA-1. The libraries you are using contain an implementation of HMAC, instantiated with the SHA-1 cryptographic hash function.

Similarly to what discussed for the case of SHA-1, the libraries you are using allow you to process a long input "one chunk at a time."

Public-Key Encryption Functions

If you only used symmetric-key cryptography, you would need to exchange a secret key with all the friends with whom you want to have confidential communication. With Public-Key Cryptography, instead, you can give all your friend the same public key, and they will be able to send you encrypted content that only you can recover. Similarly, you only need to know your friend's public key to create a ciphertext that only he/she will be able to decrypt. The libraries you are going to use contain an implementation of two very well-known Public-Key Encryption schemes: Rabin [Wil80] and ElGamal [ElG86]. Although you won't need them to complete the assignment, below we describe the interface provided by libdcrypt:

References

[ElG85] T. ElGamal, A public key cryptosystem and a signature scheme based on discrete logarithms.
IEEE Transactions on Information Theory, Vol. IT-31, No. 4, pp. 469--472, July 1985.
[FIPS-180-1] FIPS-180-1, Secure Hash Standard.
U.S. Department of Commerce/N.I.S.T., 1994
[FIPS-197] FIPS-197, Announcing the Advanced Encryption Standard.
U.S. Department of Commerce/N.I.S.T., 2001
[FIPS-198a] FIPS-198a, The Keyed-Hash Message Authentication Code (HMAC).
U.S. Department of Commerce/N.I.S.T., 2002
[Wil80] H. C. Williams, A Modification of the RSA Public-Key Encryption Procedure.
IEEE Transactions on Information Theory, Vol. IT-26, No. 6, November 1980.

Credits: David Mazières, Antonio Nicolosi, and Nelly Fazio
Versions of this Lab also assigned in classes taught at NYU and CUNY/City College.