Chapter 8
Cryptography in Linux

 8.1 Prerequisites
  8.1.1 Assumed Knowledge
  8.1.2 Linux and Network Setup
 8.2 OpenSSL
  8.2.1 Overview of OpenSSL
  8.2.2 Example Scenario
  8.2.3 Random Numbers
  8.2.4 Symmetric Key Encryption Basics
  8.2.5 Hash and MAC Functions
  8.2.6 Symmetric Key Encryption Padding and Modes of Operation
  8.2.7 RSA and Digital Signatures
  8.2.8 Diffie-Hellman Secret Key Exchange
  8.2.9 Performance Benchmarking
 8.3 Using Classical Ciphers with pycipher
  8.3.1 Install pycipher (Recommended Method)
  8.3.2 Install pycipher (Alternative Method)
  8.3.3 Using pycipher

File: nsl/crypto.tex, r1670

This chapter demonstrates how to perform common cryptographic operations in Linux. Upon completion of this chapter you should be able to encrypt files with recommended ciphers such as Advanced Encryption Standard (AES), generate and distribute Rivest Shamir Adleman cipher (RSA) public keys, and apply digital signatures to messages. OpenSSL, a library used by many free and commercial applications, is used for the modern cryptography operations in this book. If you are studying how ciphers work (as opposed to just applying them), Section 8.3 briefly shows how to use PyCipher, a Python library, to encrypt with classical ciphers such as Caesar, Playfair and Vigenere.

8.1 Prerequisites

8.1.1 Assumed Knowledge

This chapter assumes you have knowledge of:

Basic Linux command line skills, as covered in Chapter 4, are assumed. You will need to be able to:

8.1.2 Linux and Network Setup

All of the practical tasks in this chapter can be completed on a single Linux computer. While some of the demonstrations may used two Linux computers (e.g. for sender and receiver), the same operations could be performed on a single computer.

Although virtnet (Chapter 3) is not required, if you do use it, as only a single computer is necessary, topology 1 is appropriate (or in fact any topology—just use a single node).

8.2 OpenSSL

8.2.1 Overview of OpenSSL

https://www.openssl.org/ is a program and library that supports many different cryptographic operations, including:

While the primary purpose of OpenSSL is as a library, i.e. you write software that calls OpenSSL to perform cryptographic operations for your software, it also is a standalone program with a command-line interface. While we only use the standalone program, once you are familiar with it, you should be able to use the library.

OpenSSL supports different operations or commands, with the name of the command following openssl. For example, to perform symmetric key encryption the command is enc and on the command line you run:

$ openssl enc

Each of the operations supported by OpenSSL have a variety of options, such as input/output files, algorithms, algorithm parameters and formats. This article aims to give a demonstration of some simple and common operations.

To start learning the details of OpenSSL, read the man page, i.e. man openssl. You’ll soon learn that each of the operations (or commands) have their own man pages. For example, the operation of symmetric key encryption is enc, which is described in man enc. Although it is good to read the man pages, in my (and others) experience, the man pages of OpenSSL can be very detailed, hard to follow, confusing and out of date. So hopefully this article will make life easier for those getting started.

There are other websites that give an overview of OpenSSL operations, as well as programming with the API. Check them out for more details.

8.2.2 Example Scenario

As input plaintext I will copy some files on Ubuntu Linux into my home directory. You don’t need to do this if you already have some files to encrypt. It doesn’t matter what files you use. I have chosen the following three, and will rename them simply to plaintext1.in, plaintext2.in, plaintext3.in:

  1. /usr/share/dict/words: a large text file containing a list of words, i.e. a dictionary
  2. /usr/bin/openssl: the binary for the program OpenSSL
  3. /etc/legal: a short text file containing the Ubuntu legal notice
$ cp /usr/share/dict/words plaintext1.in

$ cp /usr/bin/openssl plaintext2.in $ cp /etc/legal plaintext3.in $ ls -l plaintext* -rw-r--r-- 1 sgordon sgordon 938848 Jul 31 13:32 plaintext1.in -rwxr-xr-x 1 sgordon sgordon 513208 Jul 31 13:32 plaintext2.in -rw-r--r-- 1 sgordon sgordon 267 Jul 31 13:32 plaintext3.in

The file extension of .in is just to remember that these are the original plaintext inputs. After encrypting and decrypting, we may obtain outputs, for which we will use the extension .out. Remember, file extensions in Linux often do not matter (Section 4.3).

8.2.3 Random Numbers

Before we perform any encryption, we will first see how to create random numbers. Random numbers are important for creating shared secret keys (as well as other use in other cryptographic operations). There are different ways to generate a random value in Linux. Three are demonstrated below.

Generating Random Numbers with Bash

The Bash shell has a built-in random number generator, which is accessed from the shell variable $RANDOM. It uses a Linear Congruential Generator (LCG) to return a value between 0 and 32,767. This is not a cryptographically strong Pseudo Random Number Generator (PRNG) and should not be used to create keys. I include it here only as an example; I do not use the output.

$ echo $RANDOM
4086
$ echo $RANDOM
11809
$ echo $RANDOM
6018

To see the details of the LCG algorithm used, look in the Bash source code; after downloading and unpackaging the source, look in the file variables.c, search for the function brand. You can also see that the seed is based on the current time and process ID.

Generating Random Numbers with /dev/urandom

The Linux kernel has a pseudo-device /dev/urandom which is considered cryptographically strong PRNG for most applications. The device produces a continuous stream of random bytes, so while it is possible to view the stream in real-time using cat, it is common to pipe the output to select a specific number of bytes in an easy to read format. We can use xxd to do this.

First grab 8 Bytes, output in binary:

$ cat /dev/urandom | xxd -l 8 -b
0000000: 10000111 11110111 01001101 10011100 01111110 10110110  ..M.~.
0000006: 01010110 11010001

If we want 16 Bytes of hex output:

$ cat /dev/urandom | xxd -l 16 -g 16
00000000: 75619f0688497b213c5db43d49210c4d  ua...I{!<].=I!.M

A little bit of text processing will return just the random value (omitting the other output produced by xxd). Let’s use cut to grab the 2nd field, considering the output as space separated/delimited:

$ cat /dev/urandom | xxd -l 16 -g 16 | cut -d " " -f 2
313be197c436bebf074a2da3599a0ce0

Read the man pages for an explanation of the Linux kernel random number source device /dev/urandom and the related /dev/random. The section 7 man page gives an overview, while the section 4 man page gives more technical details on the two devices.

$ man -S7 random
$ man -S4 urandom
                                                                                      
                                                                                      

Generating Random Numbers with OpenSSL

OpenSSL has its own PRNG which is also considered cryptographically strong. This is accessed using the rand command and specifying the number of bytes to generate. To get hex output, use the -hex option:

$ openssl rand -hex 8
89978d4960720a750f35d569bcf28494

You can also output to a file and view the file with xxd:

$ openssl rand -out rand1.bin 8
$ ls -l rand1.bin 
-rw-rw-r-- 1 sgordon sgordon 8 Jul 31 15:14 rand1.bin
$ xxd rand1.bin
0000000: 7d12 162f 1a18 c331                      }../...1
$ xxd -b -g 8 -c 8 rand1.bin  | cut -d " " -f 2
0111110100010010000101100010111100011010000110001100001100110001

On Linux, the OpenSSL rand command normally uses output from /dev/urandom to seed (initialise) it’s PRNG. Read the man page for more information.

8.2.4 Symmetric Key Encryption Basics

The most common cryptographic operation is encryption. Lets encrypt some files using selected symmetric key (conventional) ciphers such as Data Encryption Standard (DES), 3DES and AES.

Symmetric key encryption is performed using the enc operation of OpenSSL. To encrypt we need to choose a cipher. A list of supported ciphers can be found using:

$ openssl list-cipher-algorithms
AES-128-CBC
AES-128-CBC-HMAC-SHA1
AES-128-CFB
AES-128-CFB1
AES-128-CFB8
...
seed => SEED-CBC
SEED-CBC
                                                                                      
                                                                                      
SEED-CFB
SEED-ECB
SEED-OFB

The lowercase seed is an alias for the actual cipher SEED-CBC, i.e. SEED using Cipher Block Chaining (CBC) mode of operation. You can use the cipher names in either lowercase or uppercase.

Now lets encrypt using DES and Electronic Code Book (ECB), creating an output file ciphertext1.bin. Enter a password when prompted—OpenSSL will automatically convert it to a key appropriate for DES:

$ openssl enc -des-ecb -in plaintext1.in -out ciphertext1.bin
enter des-ecb encryption password: password
Verifying - enter des-ecb encryption password: password
$ ls -l plaintext1.in ciphertext1.bin
-rw-rw-r-- 1 sgordon sgordon 938872 Jul 31 14:15 ciphertext1.bin
-rw-r--r-- 1 sgordon sgordon 938848 Jul 31 13:32 plaintext1.in

To decrypt, include the -d option:

$ openssl enc -d -des-ecb -in ciphertext1.bin -out plaintext1.out
enter des-ecb decryption password: password
$ ls -l plaintext1.in plaintext1.out
-rw-r--r-- 1 sgordon sgordon 938848 Jul 31 13:32 plaintext1.in
-rw-rw-r-- 1 sgordon sgordon 938848 Jul 31 14:18 plaintext1.out
$ diff plaintext1.in plaintext1.out
$ xxd -l 96 ciphertext1.bin 
0000000: 5361 6c74 6564 5f5f f253 8361 b87d 1a3e  Salted__.S.a.}.>
0000010: 30ed be95 5b38 ebf9 a013 ca64 bbf4 03ea  0...[8.....d....
0000020: 3ebb cdf8 483d 5a12 acd8 bc75 140c 920b  >...H=Z....u....
0000030: da41 7376 edc3 b9bd 59c4 a5ce 0a67 408a  .Asv....Y....g@.
0000040: d23e 10ee 7ac3 f5b6 4f09 4aaf 88e4 1f96  .>..z...O.J.....
0000050: 3171 7277 91a7 100c ac04 7871 dd39 cf4c  1qrw......xq.9.L

The lack of output from the diff command indicates the files plaintext1.in and plaintext1.out are identical. We’ve retrieved the original plaintext.

xxd was used to view the first 96 bytes, in hexadecimal, of the ciphertext. The first 8 bytes contain the special string Salted__ meaning the DES key was generated using a password and a salt. The salt is stored in the next 8 bytes of ciphertext, i.e. the value f2538361b87d1a3e in hexadecimal. So when decrypting, the user supplies the password and OpenSSL combines with the salt to determine the DES 64 bit key.

Let’s try an example where we select a key. I will use AES with a 128 bit key and Counter mode (CTR) mode of operation. In addition to the key, an Initialisation Vector/Value (IV) is needed.

$ openssl enc -aes-128-ctr -in plaintext2.in -out ciphertext2.bin -K 0123456789abcdef0123456789abcdef -iv 00000000000000000000000000000000
                                                                                      
                                                                                      
$ openssl enc -d -aes-128-ctr -in ciphertext2.bin -out plaintext2.out -K 0123456789abcdef0123456789abcdef -iv 00000000000000000000000000000000
$ ls -l *2*
-rw-rw-r-- 1 sgordon sgordon 513208 Jul 31 14:29 ciphertext2.bin
-rwxr-xr-x 1 sgordon sgordon 513208 Jul 31 13:32 plaintext2.in
-rw-rw-r-- 1 sgordon sgordon 513208 Jul 31 14:30 plaintext2.out
$ diff plaintext2.in plaintext2.out
$ xxd -l 96 ciphertext2.bin 
0000000: 06ee 8984 3a69 ac84 d388 ce61 110a 6274  ....:i.....a..bt
0000010: c1ed f9ed f193 f2d2 bf8d 29e2 1577 5d32  ..........)..w]2
0000020: 1e25 cc36 bb37 baa7 eb65 402b a8ef 421b  .%.6.7...e@+..B.
0000030: a6f7 073c a08a e698 747d 5153 8df1 ed88  ...<....t}QS....
0000040: 1131 f4e0 2014 1392 ee36 2b54 27eb ca72  .1.. ....6+T'..r
0000050: 4b88 e623 ed28 2da7 87cd 0c1a 5441 5d7c  K..#.(-.....TA]|

Both the Key (note uppercase -K) and IV were specified on the command line as a hexadecimal string. With AES-128, they must be 32 hex digits (128 bits). You may choose any value you wish.

8.2.5 Hash and MAC Functions

Hash functions, like MD5 and Secure Hash Algorithm (SHA), as well as Message Authentication Code (MAC) functions (e.g. using Hash-based MAC (HMAC)) are available via the message digest (dgst) operating of OpenSSL. To list the available algorithms:

$ openssl list-message-digest-algorithms
DSA
DSA-SHA
DSA-SHA1 => DSA
DSA-SHA1-old => DSA-SHA1
DSS1 => DSA-SHA1
MD4
MD5
...
ssl3-md5 => MD5
ssl3-sha1 => SHA1
whirlpool

Calculate the MD5 hash of a file:

$ openssl dgst -md5 plaintext3.in 
MD5(plaintext3.in)= 0110925f6e068836ef2e09356e3651d9

Now create a new file, slightly different from the previous and see that the MD5 hash is significantly different:

$ cat plaintext3.in 

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

$ sed 's/U/X/g' plaintext3.in > plaintext4.in
$ cat plaintext4.in 

The programs included with the Xbuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Xbuntu comes with ABSOLXTELY NO WARRANTY, to the extent permitted by
applicable law.

$ openssl dgst -md5 plaintext4.in 
MD5(plaintext4.in)= 0b4974e95714c429e40cfad510286827

Use SHA-256, first outputing to the terminal and then in binary to a file:

$ openssl dgst -sha256 plaintext3.in
SHA256(plaintext3.in)= 9fa4ad4d7c2a346540c64c4c3619e389db894116f99a0fbbcc75a58bf2851262
$ openssl dgst -sha256 -binary -out dgst3.bin plaintext3.in
$ xxd dgst3.bin 
0000000: 9fa4 ad4d 7c2a 3465 40c6 4c4c 3619 e389  ...M|*4e@.LL6...
0000010: db89 4116 f99a 0fbb cc75 a58b f285 1262  ..A......u.....b

Create a MAC using HMAC and MD5. First generate a random 128 bit key, then pass the key as an option when using HMAC:

$ openssl rand 32 -hex
36463a4eb02b5ab9776aa8ed51f4e8a34f4bd785597fd74d4277652fd9f743d5
$ openssl dgst -md5 -mac hmac -macopt hexkey:36463a4eb02b5ab9776aa8ed51f4e8a34f4bd785597fd74d4277652fd9f743d5 plaintext3.in
HMAC-MD5(plaintext3.in)= 85e0bbf0a14559699c4b8e04bd1c1665

A much simpler alternative to calculate hash values is to use the Linux programs md5sum and sha1sum (and its variants sha224sum, sha256sum and so on). For example:

$ sha256sum plaintext3.in 
9fa4ad4d7c2a346540c64c4c3619e389db894116f99a0fbbcc75a58bf2851262  plaintext3.in
                                                                                      
                                                                                      

8.2.6 Symmetric Key Encryption Padding and Modes of Operation

Section 8.2.4 showed a simple method for performing symmetric key encryption with OpenSSL. Now we are going to consider some more details, in particular the role of padding and modes of operation.

Recall that block ciphers, like DES and AES, operate on fixed size blocks. For example, DES encrypts a 64 bit (or 8 Byte) block of plaintext. But commonly the plaintext we want to encrypt is larger than a single block. Modes of operation, such as ECB, CBC and CTR, are used to apply the block cipher across multiple blocks. That is, encrypt the first 8 Bytes of plaintext with DES, then encrypt the next 8 Bytes of plaintext (or related data) with DES, and combine them together according to some algorithm. Wikipedia has a nice summary of several block cipher modes of operation.

A related issue is that often the full plaintext will not be an integer multiple of blocks. For example, a 50 Byte file consists of 6 by 8 Byte blocks with 2 Bytes in the 7th block. Padding is needed to fill out that 7th block. By default, OpenSSL performs padding for you. However if you are sure you have a correct length plaintext (integer multiple of blocks), you can omit padding. This is useful to perform simple exploration of the output.

The following shows an example of using OpenSSL without padding, and demonstrates the weakness of the ECB mode of operation.

To get started, we need a plaintext message to encrypt. The first command below generates a message (saving to a file), and the subsequent commands show us some information about the message/file.

$ echo -n "Hello. This is our super secret message. Keep it secret please. Goodbye." > plaintext.txt
$ cat plaintext.txt 
Hello. This is our super secret message. Keep it secret please. Goodbye.
$ wc -m plaintext.txt 
72 plaintext.txt
$ ls -l
total 4
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:39 plaintext.txt
$ xxd -c 8 plaintext.txt 
0000000: 4865 6c6c 6f2e 2054  Hello. T
0000008: 6869 7320 6973 206f  his is o
0000010: 7572 2073 7570 6572  ur super
0000018: 2073 6563 7265 7420   secret
0000020: 6d65 7373 6167 652e  message.
0000028: 204b 6565 7020 6974   Keep it
0000030: 2073 6563 7265 7420   secret
0000038: 706c 6561 7365 2e20  please.
0000040: 476f 6f64 6279 652e  Goodbye.
                                                                                      
                                                                                      
$ xxd -b -c 8 plaintext.txt 
0000000: 01001000 01100101 01101100 01101100 01101111 00101110 00100000 01010100  Hello. T
0000008: 01101000 01101001 01110011 00100000 01101001 01110011 00100000 01101111  his is o
0000010: 01110101 01110010 00100000 01110011 01110101 01110000 01100101 01110010  ur super
0000018: 00100000 01110011 01100101 01100011 01110010 01100101 01110100 00100000   secret
0000020: 01101101 01100101 01110011 01110011 01100001 01100111 01100101 00101110  message.
0000028: 00100000 01001011 01100101 01100101 01110000 00100000 01101001 01110100   Keep it
0000030: 00100000 01110011 01100101 01100011 01110010 01100101 01110100 00100000   secret
0000038: 01110000 01101100 01100101 01100001 01110011 01100101 00101110 00100000  please.
0000040: 01000111 01101111 01101111 01100100 01100010 01111001 01100101 00101110  Goodbye.

The meaning of the preceeding output is:

  1. Create a short text message with echo. The -n option is used to ensure no newline is added to the end. There are two things about this message that will be important later: the length is a multiple of 8 characters (9 by 8 characters) and the word secret appears twice (in particular positions).
  2. Display the message on the screen with cat.
  3. Count the number of characters with wc.
  4. View the file size with ls.
  5. Show the message in hexadecimal and binary using xxd. From now on, I’ll only look at the hexadecimal values (not binary).

To encrypt with DES-ECB we need a secret key (as well as IV). You can choose your own values. For security, they should be randomly chosen. We saw in Section 8.2.3 different ways to generate random values. Let’s use rand twice: the first will be for the secret key and the second for the IV.

$ openssl rand -hex 8
001e53e887ee55f1
$ openssl rand -hex 8
a499056833bb3ac1

Now encrypt the plaintext using DES-ECB. The IV and Key are taken from the outputs OpenSSL PRNG above. Importantly, we use the -nopad option at the end:

$ openssl enc -des-ecb -e -in plaintext.txt -out ciphertext.bin -iv a499056833bb3ac1 -K 001e53e887ee55f1 -nopad
                                                                                      
                                                                                      

Now look at the output ciphertext. First note it is the same length as the plaintext (as expected, when no padding is used). And on initial view, the ciphertext looks random (as expected). But closer inspection you see there is some structure: the 4th and 7th lines of the xxd output are the same. This is because it corresponds to the encryption of the same original plaintext ” secure ” (recall that word was repeated in the plaintext, in the positions such that it is in a 64-bit block). Since ECB is used, repetitions in input plaintext blocks will result in repetitions in output ciphertext blocks. This is insecure (especially for long plaintext). Another mode of operation, like CBC, should be used.

$ ls -l
total 8
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:42 ciphertext.bin
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:39 plaintext.txt
$ xxd -c 8 ciphertext.bin
0000000: 56dc b368 d9ef 0793  V..h....
0000008: 7be4 a87d e26d c2f1  {..}.m..
0000010: e042 bbe6 9e00 6d37  .B....m7
0000018: f1e9 7163 cb4a 38d8  ..qc.J8.
0000020: 5394 a92f 8cf2 ac72  S../...r
0000028: 5064 be07 f67c d807  Pd...|..
0000030: f1e9 7163 cb4a 38d8  ..qc.J8.
0000038: a31c 0efd cd0b dd03  ........
0000040: 0486 7e2d 00ad 762d  ..~-..v-

Now lets decrypt:

$ openssl enc -des-ecb -d -in ciphertext.bin -out received.txt -iv a499056833bb3ac1 -K 001e53e887ee55f1 -nopad

And look at the decrypted value. Of course, it matches the original plaintext message.

$ ls -l
total 12
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:42 ciphertext.bin
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:39 plaintext.txt
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:43 received.txt
$ cat received.txt 
Hello. This is our super secret message. Keep it secret please. Goodbye.
$ xxd -c 8 received.txt 
0000000: 4865 6c6c 6f2e 2054  Hello. T
0000008: 6869 7320 6973 206f  his is o
0000010: 7572 2073 7570 6572  ur super
0000018: 2073 6563 7265 7420   secret
0000020: 6d65 7373 6167 652e  message.
0000028: 204b 6565 7020 6974   Keep it
                                                                                      
                                                                                      
0000030: 2073 6563 7265 7420   secret
0000038: 706c 6561 7365 2e20  please.
0000040: 476f 6f64 6279 652e  Goodbye.

Now lets try and decrypt again, but this time using the wrong key. I’ve changed the last hexadecimal digit of the key from “1” to “2”.

$ openssl enc -des-ecb -d -in ciphertext.bin -out received2.txt -iv a499056833bb3ac1 -K 001e53e887ee55f2 -nopad

Looking at the decrypted message, it is random. We didn’t obtain the original plaintext. Normally, when padding is used, OpenSSL adds a checksum when encrypting which allows, after decrypting, incorrect deciphered messages to be automatically detected.

$ ls -l
total 16
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:42 ciphertext.bin
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:39 plaintext.txt
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:46 received2.txt
-rw-r--r-- 1 sgordon sgordon 72 Nov 11 16:43 received.txt
$ xxd -c 8 received2.txt
0000000: 0346 e59e c22d 403f  .F...-@?
0000008: 63ff 28fd eb6b 387d  c.(..k8}
0000010: b52f d595 06c0 342f  ./....4/
0000018: f419 3569 e383 c857  ..5i...W
0000020: 0a77 0b49 6f62 cb64  .w.Iob.d
0000028: 8265 d419 51f3 ea12  .e..Q...
0000030: f419 3569 e383 c857  ..5i...W
0000038: f296 33f3 5cf4 d359  ..3.\..Y
0000040: e205 4018 0ce0 34f5  ..@...4.

8.2.7 RSA and Digital Signatures

OpenSSL can be used to perform various operations with public key cryptography. Here we demonstrate basic usage of RSA. Section 8.2.8 demonstrates Diffie-Hellman Key Exchange (DHKE), while an example of using digital certificates, including creating a Certificate Authority with OpenSSL, is included in Chapter 12.

To demonstrate RSA we use the scenario of user Alice on node1 wishing to send a confidential and signed message to user Bob on node2.

Then I decrypted the ciphertext and verified the signature. Of course I also had to create my own key pair and make the public key available to the sender.

The steps are shown below, first in a screencast where I provide some explanation of the options and steps, and second in text form (with little explanation) that you can view and copy and paste if needed. Note that although the steps used in both outputs are the same, the actual values differ (i.e. the output listed below is from a different set of keys than used in the screencast).

Steps Performed by Alice

Any user can generate their RSA key pair using the genpkey command. Note that in public key cryptography a key pair consists of a private key and public key. A user can distribute their public key to anyone, but keeps their private key to themselves. But they also need to store their own public key. So in practice, a user will have two files: a private key file, which contains their private key information and their public key information; and a public key file, which contains only their public key information. So in OpenSSL, when a private key is generated with genpkey, the public key information is also created.

To generate the private (and public key):

alice@node1:~$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:3 -out privkey-alice.pem
alice@node1:~$ cat privkey-alice.pem
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCoXEAmbAuh9Nks
xtjIqgW8+MjaoRLWIKOpr54E7XcpzMSlNZggPBp0sLjfgvNFBPP7BrQms3qigwow
krML/fdwSFybigmuTCyJS/UIn3J5s70vUSpQ9M8oAU+6lvRdiByqR0zBnnWdR9B8
wW2/jM2Ng3yq51S6qR6LUs92jEzYATz1df8z+qcUL+navmOSLdA110qQpbKjEjI1
esJIkqrKlQiu1N0TQbexC9dNwtI79G79UR+YOR8CWJyYy/ZPeUrsr1mcSGL7facW
/aG2hh85/XdICm2PWgRySUu0M2rHdxL+AMukauYnlw4gddTO0cmUNyxKrVr5aQBP
hZxKtFV5AgEDAoIBAHA9gBmdXRajO3MvOzBxWSil2zxrYeQVwnEfvq3zpMaIgxjO
ZWrSvE3LJepXTNit9/yvIsR3pxcCBssMd11T+kra6GexW8mIHbDdTgW/oaZ303Tg
xuCjNMVWNScPTZOwExwviIEUTmjaiv3WSSpd3l5XqHHvjdHGFFzh36RdiI//vcSX
VHC76AkhkJ13aDEIUSQPMfE0OmI4dgK2sxH8BXAmAgc7YOksLF4t+tjaEoeUFQWP
SwFiGgVaU3wtmv1DoSwbAKSWs/9hDg3vgN8AFku3HCdBkpmpp2CYqoBWFDfUNW2q
TtB7IU2fwUOtoqiW8CegqVNf+X+KWT85mb1NnqMCgYEA3z2IhWyENYsHRrfbpISR
                                                                                      
                                                                                      
q3y5l5sgFM1ofRbPA5AZbZANY48jFPSeuKWJ1HhhZpwai+dcKf5R2w5V/4vpKqec
wFFGkXiOshkzty/67A75Uww/iewff0nj8ZwG7oLYl2PHu7iyyHiwbTj7N21Rapq+
iUHpd4RBpiOPoad4lD+CDWcCgYEAwREKex5clXt2SjavosQPqwMG6Au3RkJVBBqZ
sh1/NRJOohTYtsDgvH49CpAaT9R7w42eBRfUHOv7H9KeYyv3GNlARyzXouM4WtIb
dFkMqrwrQyEIkl73l8VdXXDZtQ/xByDOjPMBxvosNM2f9jcw2BbctslbvpaJ2Mk2
oW892h8CgYEAlNOwWPMCzlyvhHqSba22clMmZRIVYzOa/g80rQq7nmAI7QoXY02/
JcOxOFBA7xK8XUToG/7hPLQ5VQfwxxpogDYvC6W0drt3z3VR8rSmN11/sUgU/4aX
9mgEnwHlukKFJ9B3MFB1niX8z542RxHUW4FGT62BGW0Ka8T7DX+sCO8CgYEAgLYG
/L7oY6ekMXnKbIK1HKyvRV0k2YGOArxmdr5Uzgw0bA3lzytAfal+Bwq8NThSgl5p
WLqNaJ1SFTcUQh1PZeYq2h3lF0IlkeFnouYIcdLHghYFtun6ZS4+Pks7zgqgr2s0
XfdWhKbIIzO/+XogkA89zzDn1GRb5dt5wPTT5r8CgYEA29235n/Hw7wzOJyao6nO
3rjCZon4/V2G800VJF5hhAqCX5KDLd0KIMbaHaxsjW+n79CqZSUz3kZtpSXBXRJ7
SIXoCYljaoxdJ6SkVED6uFmcZ+3iwioxXzpIFIW0ZZj5S/WgBkPsioAJ6Cp5S8zh
BFB15UA+JWFH2SRabjXf0+4=
-----END PRIVATE KEY-----

The genpkey command takes an algorithm (RSA) as an option, and that algorithm may have further specific options. In this example we set the RSA key length to 2048 bits and used a public exponent of 3. Omitting these -pkeyopt options will revert to the default values. The private key (and public key information) is output to a file.

The private key file is encoded with Base64. To view the values:

alice@node1:~$ openssl pkey -in privkey-alice.pem -text
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCoXEAmbAuh9Nks
xtjIqgW8+MjaoRLWIKOpr54E7XcpzMSlNZggPBp0sLjfgvNFBPP7BrQms3qigwow
krML/fdwSFybigmuTCyJS/UIn3J5s70vUSpQ9M8oAU+6lvRdiByqR0zBnnWdR9B8
wW2/jM2Ng3yq51S6qR6LUs92jEzYATz1df8z+qcUL+navmOSLdA110qQpbKjEjI1
esJIkqrKlQiu1N0TQbexC9dNwtI79G79UR+YOR8CWJyYy/ZPeUrsr1mcSGL7facW
/aG2hh85/XdICm2PWgRySUu0M2rHdxL+AMukauYnlw4gddTO0cmUNyxKrVr5aQBP
hZxKtFV5AgEDAoIBAHA9gBmdXRajO3MvOzBxWSil2zxrYeQVwnEfvq3zpMaIgxjO
ZWrSvE3LJepXTNit9/yvIsR3pxcCBssMd11T+kra6GexW8mIHbDdTgW/oaZ303Tg
xuCjNMVWNScPTZOwExwviIEUTmjaiv3WSSpd3l5XqHHvjdHGFFzh36RdiI//vcSX
VHC76AkhkJ13aDEIUSQPMfE0OmI4dgK2sxH8BXAmAgc7YOksLF4t+tjaEoeUFQWP
SwFiGgVaU3wtmv1DoSwbAKSWs/9hDg3vgN8AFku3HCdBkpmpp2CYqoBWFDfUNW2q
TtB7IU2fwUOtoqiW8CegqVNf+X+KWT85mb1NnqMCgYEA3z2IhWyENYsHRrfbpISR
q3y5l5sgFM1ofRbPA5AZbZANY48jFPSeuKWJ1HhhZpwai+dcKf5R2w5V/4vpKqec
wFFGkXiOshkzty/67A75Uww/iewff0nj8ZwG7oLYl2PHu7iyyHiwbTj7N21Rapq+
iUHpd4RBpiOPoad4lD+CDWcCgYEAwREKex5clXt2SjavosQPqwMG6Au3RkJVBBqZ
sh1/NRJOohTYtsDgvH49CpAaT9R7w42eBRfUHOv7H9KeYyv3GNlARyzXouM4WtIb
dFkMqrwrQyEIkl73l8VdXXDZtQ/xByDOjPMBxvosNM2f9jcw2BbctslbvpaJ2Mk2
oW892h8CgYEAlNOwWPMCzlyvhHqSba22clMmZRIVYzOa/g80rQq7nmAI7QoXY02/
JcOxOFBA7xK8XUToG/7hPLQ5VQfwxxpogDYvC6W0drt3z3VR8rSmN11/sUgU/4aX
9mgEnwHlukKFJ9B3MFB1niX8z542RxHUW4FGT62BGW0Ka8T7DX+sCO8CgYEAgLYG
/L7oY6ekMXnKbIK1HKyvRV0k2YGOArxmdr5Uzgw0bA3lzytAfal+Bwq8NThSgl5p
WLqNaJ1SFTcUQh1PZeYq2h3lF0IlkeFnouYIcdLHghYFtun6ZS4+Pks7zgqgr2s0
                                                                                      
                                                                                      
XfdWhKbIIzO/+XogkA89zzDn1GRb5dt5wPTT5r8CgYEA29235n/Hw7wzOJyao6nO
3rjCZon4/V2G800VJF5hhAqCX5KDLd0KIMbaHaxsjW+n79CqZSUz3kZtpSXBXRJ7
SIXoCYljaoxdJ6SkVED6uFmcZ+3iwioxXzpIFIW0ZZj5S/WgBkPsioAJ6Cp5S8zh
BFB15UA+JWFH2SRabjXf0+4=
-----END PRIVATE KEY-----
Private-Key: (2048 bit)
modulus:
     00:a8:5c:40:26:6c:0b:a1:f4:d9:2c:c6:d8:c8:aa:
     05:bc:f8:c8:da:a1:12:d6:20:a3:a9:af:9e:04:ed:
     77:29:cc:c4:a5:35:98:20:3c:1a:74:b0:b8:df:82:
     f3:45:04:f3:fb:06:b4:26:b3:7a:a2:83:0a:30:92:
     b3:0b:fd:f7:70:48:5c:9b:8a:09:ae:4c:2c:89:4b:
     f5:08:9f:72:79:b3:bd:2f:51:2a:50:f4:cf:28:01:
     4f:ba:96:f4:5d:88:1c:aa:47:4c:c1:9e:75:9d:47:
     d0:7c:c1:6d:bf:8c:cd:8d:83:7c:aa:e7:54:ba:a9:
     1e:8b:52:cf:76:8c:4c:d8:01:3c:f5:75:ff:33:fa:
     a7:14:2f:e9:da:be:63:92:2d:d0:35:d7:4a:90:a5:
     b2:a3:12:32:35:7a:c2:48:92:aa:ca:95:08:ae:d4:
     dd:13:41:b7:b1:0b:d7:4d:c2:d2:3b:f4:6e:fd:51:
     1f:98:39:1f:02:58:9c:98:cb:f6:4f:79:4a:ec:af:
     59:9c:48:62:fb:7d:a7:16:fd:a1:b6:86:1f:39:fd:
     77:48:0a:6d:8f:5a:04:72:49:4b:b4:33:6a:c7:77:
     12:fe:00:cb:a4:6a:e6:27:97:0e:20:75:d4:ce:d1:
     c9:94:37:2c:4a:ad:5a:f9:69:00:4f:85:9c:4a:b4:
     55:79
publicExponent: 3 (0x3)
privateExponent:
     70:3d:80:19:9d:5d:16:a3:3b:73:2f:3b:30:71:59:
     28:a5:db:3c:6b:61:e4:15:c2:71:1f:be:ad:f3:a4:
     c6:88:83:18:ce:65:6a:d2:bc:4d:cb:25:ea:57:4c:
     d8:ad:f7:fc:af:22:c4:77:a7:17:02:06:cb:0c:77:
     5d:53:fa:4a:da:e8:67:b1:5b:c9:88:1d:b0:dd:4e:
     05:bf:a1:a6:77:d3:74:e0:c6:e0:a3:34:c5:56:35:
     27:0f:4d:93:b0:13:1c:2f:88:81:14:4e:68:da:8a:
     fd:d6:49:2a:5d:de:5e:57:a8:71:ef:8d:d1:c6:14:
     5c:e1:df:a4:5d:88:8f:ff:bd:c4:97:54:70:bb:e8:
     09:21:90:9d:77:68:31:08:51:24:0f:31:f1:34:3a:
     62:38:76:02:b6:b3:11:fc:05:70:26:02:07:3b:60:
     e9:2c:2c:5e:2d:fa:d8:da:12:87:94:15:05:8f:4b:
     01:62:1a:05:5a:53:7c:2d:9a:fd:43:a1:2c:1b:00:
     a4:96:b3:ff:61:0e:0d:ef:80:df:00:16:4b:b7:1c:
     27:41:92:99:a9:a7:60:98:aa:80:56:14:37:d4:35:
     6d:aa:4e:d0:7b:21:4d:9f:c1:43:ad:a2:a8:96:f0:
     27:a0:a9:53:5f:f9:7f:8a:59:3f:39:99:bd:4d:9e:
     a3
prime1:
     00:df:3d:88:85:6c:84:35:8b:07:46:b7:db:a4:84:
                                                                                      
                                                                                      
     91:ab:7c:b9:97:9b:20:14:cd:68:7d:16:cf:03:90:
     19:6d:90:0d:63:8f:23:14:f4:9e:b8:a5:89:d4:78:
     61:66:9c:1a:8b:e7:5c:29:fe:51:db:0e:55:ff:8b:
     e9:2a:a7:9c:c0:51:46:91:78:8e:b2:19:33:b7:2f:
     fa:ec:0e:f9:53:0c:3f:89:ec:1f:7f:49:e3:f1:9c:
     06:ee:82:d8:97:63:c7:bb:b8:b2:c8:78:b0:6d:38:
     fb:37:6d:51:6a:9a:be:89:41:e9:77:84:41:a6:23:
     8f:a1:a7:78:94:3f:82:0d:67
prime2:
     00:c1:11:0a:7b:1e:5c:95:7b:76:4a:36:af:a2:c4:
     0f:ab:03:06:e8:0b:b7:46:42:55:04:1a:99:b2:1d:
     7f:35:12:4e:a2:14:d8:b6:c0:e0:bc:7e:3d:0a:90:
     1a:4f:d4:7b:c3:8d:9e:05:17:d4:1c:eb:fb:1f:d2:
     9e:63:2b:f7:18:d9:40:47:2c:d7:a2:e3:38:5a:d2:
     1b:74:59:0c:aa:bc:2b:43:21:08:92:5e:f7:97:c5:
     5d:5d:70:d9:b5:0f:f1:07:20:ce:8c:f3:01:c6:fa:
     2c:34:cd:9f:f6:37:30:d8:16:dc:b6:c9:5b:be:96:
     89:d8:c9:36:a1:6f:3d:da:1f
exponent1:
     00:94:d3:b0:58:f3:02:ce:5c:af:84:7a:92:6d:ad:
     b6:72:53:26:65:12:15:63:33:9a:fe:0f:34:ad:0a:
     bb:9e:60:08:ed:0a:17:63:4d:bf:25:c3:b1:38:50:
     40:ef:12:bc:5d:44:e8:1b:fe:e1:3c:b4:39:55:07:
     f0:c7:1a:68:80:36:2f:0b:a5:b4:76:bb:77:cf:75:
     51:f2:b4:a6:37:5d:7f:b1:48:14:ff:86:97:f6:68:
     04:9f:01:e5:ba:42:85:27:d0:77:30:50:75:9e:25:
     fc:cf:9e:36:47:11:d4:5b:81:46:4f:ad:81:19:6d:
     0a:6b:c4:fb:0d:7f:ac:08:ef
exponent2:
     00:80:b6:06:fc:be:e8:63:a7:a4:31:79:ca:6c:82:
     b5:1c:ac:af:45:5d:24:d9:81:8e:02:bc:66:76:be:
     54:ce:0c:34:6c:0d:e5:cf:2b:40:7d:a9:7e:07:0a:
     bc:35:38:52:82:5e:69:58:ba:8d:68:9d:52:15:37:
     14:42:1d:4f:65:e6:2a:da:1d:e5:17:42:25:91:e1:
     67:a2:e6:08:71:d2:c7:82:16:05:b6:e9:fa:65:2e:
     3e:3e:4b:3b:ce:0a:a0:af:6b:34:5d:f7:56:84:a6:
     c8:23:33:bf:f9:7a:20:90:0f:3d:cf:30:e7:d4:64:
     5b:e5:db:79:c0:f4:d3:e6:bf
coefficient:
     00:db:dd:b7:e6:7f:c7:c3:bc:33:38:9c:9a:a3:a9:
     ce:de:b8:c2:66:89:f8:fd:5d:86:f3:4d:15:24:5e:
     61:84:0a:82:5f:92:83:2d:dd:0a:20:c6:da:1d:ac:
     6c:8d:6f:a7:ef:d0:aa:65:25:33:de:46:6d:a5:25:
     c1:5d:12:7b:48:85:e8:09:89:63:6a:8c:5d:27:a4:
     a4:54:40:fa:b8:59:9c:67:ed:e2:c2:2a:31:5f:3a:
     48:14:85:b4:65:98:f9:4b:f5:a0:06:43:ec:8a:80:
     09:e8:2a:79:4b:cc:e1:04:50:75:e5:40:3e:25:61:
                                                                                      
                                                                                      
     47:d9:24:5a:6e:35:df:d3:ee

An explanation of these values can be found in a lecture on Public Key Cryptography, specifically on slide 18.

To output just the public key to a file:

alice@node1:~$ openssl pkey -in privkey-alice.pem -out pubkey-alice.pem -pubout
alice@node1:~$ cat pubkey-alice.pem
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAqFxAJmwLofTZLMbYyKoF
vPjI2qES1iCjqa+eBO13KczEpTWYIDwadLC434LzRQTz+wa0JrN6ooMKMJKzC/33
cEhcm4oJrkwsiUv1CJ9yebO9L1EqUPTPKAFPupb0XYgcqkdMwZ51nUfQfMFtv4zN
jYN8qudUuqkei1LPdoxM2AE89XX/M/qnFC/p2r5jki3QNddKkKWyoxIyNXrCSJKq
ypUIrtTdE0G3sQvXTcLSO/Ru/VEfmDkfAlicmMv2T3lK7K9ZnEhi+32nFv2htoYf
Of13SAptj1oEcklLtDNqx3cS/gDLpGrmJ5cOIHXUztHJlDcsSq1a+WkAT4WcSrRV
eQIBAw==
-----END PUBLIC KEY-----

Check by looking at the individual values. Only the public key values are included:

alice@node1:~$ openssl pkey -in pubkey-alice.pem -pubin -text
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAqFxAJmwLofTZLMbYyKoF
vPjI2qES1iCjqa+eBO13KczEpTWYIDwadLC434LzRQTz+wa0JrN6ooMKMJKzC/33
cEhcm4oJrkwsiUv1CJ9yebO9L1EqUPTPKAFPupb0XYgcqkdMwZ51nUfQfMFtv4zN
jYN8qudUuqkei1LPdoxM2AE89XX/M/qnFC/p2r5jki3QNddKkKWyoxIyNXrCSJKq
ypUIrtTdE0G3sQvXTcLSO/Ru/VEfmDkfAlicmMv2T3lK7K9ZnEhi+32nFv2htoYf
Of13SAptj1oEcklLtDNqx3cS/gDLpGrmJ5cOIHXUztHJlDcsSq1a+WkAT4WcSrRV
eQIBAw==
-----END PUBLIC KEY-----
Public-Key: (2048 bit)
Modulus:
     00:a8:5c:40:26:6c:0b:a1:f4:d9:2c:c6:d8:c8:aa:
     05:bc:f8:c8:da:a1:12:d6:20:a3:a9:af:9e:04:ed:
     77:29:cc:c4:a5:35:98:20:3c:1a:74:b0:b8:df:82:
     f3:45:04:f3:fb:06:b4:26:b3:7a:a2:83:0a:30:92:
     b3:0b:fd:f7:70:48:5c:9b:8a:09:ae:4c:2c:89:4b:
     f5:08:9f:72:79:b3:bd:2f:51:2a:50:f4:cf:28:01:
     4f:ba:96:f4:5d:88:1c:aa:47:4c:c1:9e:75:9d:47:
     d0:7c:c1:6d:bf:8c:cd:8d:83:7c:aa:e7:54:ba:a9:
     1e:8b:52:cf:76:8c:4c:d8:01:3c:f5:75:ff:33:fa:
     a7:14:2f:e9:da:be:63:92:2d:d0:35:d7:4a:90:a5:
     b2:a3:12:32:35:7a:c2:48:92:aa:ca:95:08:ae:d4:
     dd:13:41:b7:b1:0b:d7:4d:c2:d2:3b:f4:6e:fd:51:
     1f:98:39:1f:02:58:9c:98:cb:f6:4f:79:4a:ec:af:
     59:9c:48:62:fb:7d:a7:16:fd:a1:b6:86:1f:39:fd:
     77:48:0a:6d:8f:5a:04:72:49:4b:b4:33:6a:c7:77:
                                                                                      
                                                                                      
     12:fe:00:cb:a4:6a:e6:27:97:0e:20:75:d4:ce:d1:
     c9:94:37:2c:4a:ad:5a:f9:69:00:4f:85:9c:4a:b4:
     55:79
Exponent: 3 (0x3)

Now that Alice has her private and public key files, let’s create a text file containing the message to send to Bob:

alice@node1:~$ echo "This is my example message." > message-alice.txt
alice@node1:~$ cat message-alice.txt
This is my example message.

To sign the message you need to calculate its hash and then encrypt that hash using your private key. To create a hash of a message (without encrypting):

alice@node1:~$ openssl dgst -sha1 message-alice.txt
SHA1(message-alice.txt)= 064774b2fb550d8c1d7d39fa5ac5685e2f8b1ca6

OpenSSL has an option to calculate the hash and then sign it using a selected private key. The output will be a file containing the signature.

alice@node1:~$ openssl dgst -sha1 -sign privkey-alice.pem -out sign-alice.bin message-alice.txt
alice@node1:~$ ls -l
total 16
-rw-r--r-- 1 sgordon users   28 2012-03-04 15:14 message-alice.txt
-rw-r--r-- 1 sgordon users 1704 2012-03-04 14:58 privkey-alice.pem
-rw-r--r-- 1 sgordon users  451 2012-03-04 15:08 pubkey-alice.pem
-rw-r--r-- 1 sgordon users  256 2012-03-04 15:20 sign-alice.bin

To encrypt the message using RSA, use the recipients public key (this assumes the recipient, Bob, has already created and distributed their public key, using the same steps as above):

alice@node1:~$ openssl pkeyutl -encrypt -in message-alice.txt -pubin -inkey pubkey-bob.pem -out ciphertext-alice.bin

Note that direct RSA encryption should only be used on small files, with length less than the length of the key. If you want to encrypt large files then use symmetric key encryption. Two approaches to do this with OpenSSL: (1) generate a random key to be used with a symmetric cipher to encrypt the message and then encrypt the key with RSA; (2) use the smime operation, which combines RSA and a symmetric cipher to automate approach 1.

Now Alice sends the following to Bob:

Steps Performed by Bob

When Bob receive’s the two files from Alice, he needs to decrypt the ciphertext and verify the signature. Bob will need to use his RSA private/public key files, which were generated in the same way as for Alice, i.e. using genpkey.

To decrypt the received ciphertext:

bob@node2:~$ openssl pkeyutl -decrypt -in ciphertext-alice.bin -inkey privkey-bob.pem -out received-alice.txt
bob@node2:~$ cat received-alice.txt
This is my example message.

To verify the signature of a message:

bob@node2:~$ openssl dgst -sha1 -verify pubkey-alice.pem -signature sign-alice.bin received-alice.txt 
Verified OK

The output messages shows the verification was successful.

8.2.8 Diffie-Hellman Secret Key Exchange

Now we give an example of using OpenSSL operations to perform a Diffie-Hellman Key Exchange (DHKE). The goal in DHKE is for two users to obtain a shared secret key, without any other users knowing that key. The exchange is performed over a public network, i.e. all messages sent between the two users can be intercepted and read by any other user. The protocol makes use of modular arithmetic and especially exponentials. The security of the protocol relies on the fact that solving a discrete logarithm (the inverse of an exponential) is practically impossible when large enough values are used.

Wikipedia has a description and example of DHKE. There is also a lecture on public key cryptography and accompanying videos and examples, with Diffie-Hellman starting from slide 23 also include a description.

DHKE is performed by two users, on two different computers. To demonstrate RSA we use the scenario of user Alice on node1 wishing to send a confidential and signed message to user Bob on node2. For this demo, we use the scenario of user Alice on node1 and Bob on node2. Take note of the prompt to see who is performing each command.

The first step is to generate the Diffie-Hellman (DH) global public parameters, saving them in the file dhp.pem. We use the OpenSSL genpkey command, similar to RSA in Section 8.2.7, but specified the algorithm as DH and use the -genparam option:

alice@node1:~$ openssl genpkey -genparam -algorithm DH -out dhparam.pem
...+.......................................................................
.............................................................+.............
...............................................+...........................
...........................+........+......................................
.....................................+.....................................
...........................+..................................+........+...
...............+..........+...............+................................
........................................................................+..
..................................................................+........
..............................................+........................+...
.....++*++*++*

Now let’s display the generated global public parameters, first in the encoded form, then in the text form:

alice@node1:~$ cat dhparam.pem
-----BEGIN DH PARAMETERS-----
MIGHAoGBAOZVzJ4E8766527Mp3FD71xEUYdmFan4tPcSuPO99H7n9xfAm7WytmRQ
gxNn2dz4X58FKLzVMY+x2rLyPOd8SLa3OB7tE+gKFMymswteN//lPbFeLWtyei78
7lGJNnjVDpqJFmo1nldMTDyl5Z+ueZJP5vGGs2ouvem/Cf5N5QRTAgEC
-----END DH PARAMETERS-----
alice@node1:~$ openssl pkeyparam -in dhparam.pem -text
-----BEGIN DH PARAMETERS-----
MIGHAoGBAOZVzJ4E8766527Mp3FD71xEUYdmFan4tPcSuPO99H7n9xfAm7WytmRQ
gxNn2dz4X58FKLzVMY+x2rLyPOd8SLa3OB7tE+gKFMymswteN//lPbFeLWtyei78
7lGJNnjVDpqJFmo1nldMTDyl5Z+ueZJP5vGGs2ouvem/Cf5N5QRTAgEC
-----END DH PARAMETERS-----
PKCS#3 DH Parameters: (1024 bit)
     prime:
         00:e6:55:cc:9e:04:f3:be:ba:e7:6e:cc:a7:71:43:
         ef:5c:44:51:87:66:15:a9:f8:b4:f7:12:b8:f3:bd:
         f4:7e:e7:f7:17:c0:9b:b5:b2:b6:64:50:83:13:67:
         d9:dc:f8:5f:9f:05:28:bc:d5:31:8f:b1:da:b2:f2:
         3c:e7:7c:48:b6:b7:38:1e:ed:13:e8:0a:14:cc:a6:
         b3:0b:5e:37:ff:e5:3d:b1:5e:2d:6b:72:7a:2e:fc:
         ee:51:89:36:78:d5:0e:9a:89:16:6a:35:9e:57:4c:
         4c:3c:a5:e5:9f:ae:79:92:4f:e6:f1:86:b3:6a:2e:
         bd:e9:bf:09:fe:4d:e5:04:53
     generator: 2 (0x2)
                                                                                      
                                                                                      

Each user can use the public parameters to generate their own private and public key, saving them in their respective files. Similar to RSA, the DH private key file also stores the public key information.

alice@node1:~$ openssl genpkey -paramfile dhparam.pem -out dhprivkey-alice.pem
alice@node1:~$ openssl pkey -in dhprivkey-alice.pem -text -noout
PKCS#3 DH Private-Key: (1024 bit)
     private-key:
         48:88:7d:fd:09:0d:17:5e:33:be:ea:29:e7:b3:83:
         34:29:92:89:06:9f:9a:b4:92:b6:78:07:90:5f:aa:
         98:d9:6d:22:d7:92:05:be:f0:3f:14:af:09:3f:17:
         97:b9:04:73:41:32:c3:4a:38:8f:dc:79:e2:04:97:
         bf:a1:46:5f:ec:2a:ac:4f:ab:df:3b:b0:c9:be:86:
         85:d2:0f:7b:fe:03:46:a9:ab:df:7f:a8:98:38:c3:
         fa:9c:a6:ab:db:70:be:a6:67:95:ab:66:99:cc:15:
         4d:b5:94:90:e4:15:9f:14:2f:7b:dd:ff:60:3c:1d:
         3d:6c:4f:ff:81:77:e1:1d
     public-key:
         00:d9:ab:d7:8c:93:df:dd:eb:92:0d:57:d6:51:31:
         26:d8:f1:11:8c:92:37:a4:51:01:40:8d:bf:fe:6c:
         fd:95:b0:11:a0:16:e4:e0:ab:8a:ef:06:01:e8:36:
         a4:52:b8:bb:88:be:7c:a7:1e:4f:22:f9:7a:a6:5f:
         83:58:ee:69:34:8d:12:27:d6:5d:b6:e5:36:41:d1:
         a6:54:2a:a4:be:4b:4a:dc:75:fa:c8:16:af:79:a8:
         e3:f5:09:7f:83:13:e7:b7:25:df:37:ea:dc:8c:77:
         4e:20:33:df:a9:9c:95:cc:ef:33:3b:f4:02:b0:66:
         19:8c:30:48:1e:2a:83:87:5c
     prime:
         00:e6:55:cc:9e:04:f3:be:ba:e7:6e:cc:a7:71:43:
         ef:5c:44:51:87:66:15:a9:f8:b4:f7:12:b8:f3:bd:
         f4:7e:e7:f7:17:c0:9b:b5:b2:b6:64:50:83:13:67:
         d9:dc:f8:5f:9f:05:28:bc:d5:31:8f:b1:da:b2:f2:
         3c:e7:7c:48:b6:b7:38:1e:ed:13:e8:0a:14:cc:a6:
         b3:0b:5e:37:ff:e5:3d:b1:5e:2d:6b:72:7a:2e:fc:
         ee:51:89:36:78:d5:0e:9a:89:16:6a:35:9e:57:4c:
         4c:3c:a5:e5:9f:ae:79:92:4f:e6:f1:86:b3:6a:2e:
         bd:e9:bf:09:fe:4d:e5:04:53
     generator: 2 (0x2)

The other user uses the same public parameters, dhparam.pem, to generate their private/public key:

bob@node2:~$ openssl genpkey -paramfile dhparam.pem -out dhprivkey-bob.pem
                                                                                      
                                                                                      
bob@node2:~$ openssl pkey -in dhprivkey-bob.pem -text -noout
PKCS#3 DH Private-Key: (1024 bit)
     private-key:
         5d:70:9b:3e:a7:c9:b1:3b:df:17:d3:76:dd:45:f0:
         38:6d:be:35:f6:79:5d:05:bf:e2:63:b0:ea:25:00:
         61:0a:4c:e2:e4:e7:8e:97:6e:cb:9e:f0:f9:4b:d9:
         1c:2e:d6:b1:71:cb:ec:56:a7:2f:b0:af:ff:67:df:
         37:e0:d8:8c:ab:5d:ef:3d:27:c5:5a:a6:8d:49:30:
         6b:4e:d4:1f:5c:40:da:35:d0:bc:c7:3d:16:a3:13:
         2e:86:af:13:8b:65:c4:19:f2:75:43:e7:11:b6:5a:
         81:d1:e0:ff:5d:f3:c2:f4:6f:d2:f0:72:97:66:b9:
         93:3d:17:b0:06:ef:8a:3b
     public-key:
         00:d9:9a:00:1b:98:f5:0b:e2:d6:57:f7:4d:e3:4b:
         aa:43:ad:e2:f2:93:31:a1:e7:4b:a7:06:dc:ab:22:
         09:5a:0d:41:1a:c1:37:c0:6d:88:f4:7c:0a:22:27:
         1e:d3:84:39:51:92:62:d5:14:9e:68:ee:2f:69:27:
         ae:dd:d1:e6:a2:5f:3c:d2:7b:a7:7c:8e:61:28:fb:
         8b:1c:d7:a0:0b:d3:7b:37:af:78:b2:7e:eb:62:a7:
         85:b6:0f:90:10:b7:9c:ce:ec:84:a9:28:e3:7f:22:
         8f:76:cd:68:58:56:45:fd:3e:36:37:a1:99:aa:ca:
         4a:65:65:af:a8:21:ee:1f:b6
     prime:
         00:e6:55:cc:9e:04:f3:be:ba:e7:6e:cc:a7:71:43:
         ef:5c:44:51:87:66:15:a9:f8:b4:f7:12:b8:f3:bd:
         f4:7e:e7:f7:17:c0:9b:b5:b2:b6:64:50:83:13:67:
         d9:dc:f8:5f:9f:05:28:bc:d5:31:8f:b1:da:b2:f2:
         3c:e7:7c:48:b6:b7:38:1e:ed:13:e8:0a:14:cc:a6:
         b3:0b:5e:37:ff:e5:3d:b1:5e:2d:6b:72:7a:2e:fc:
         ee:51:89:36:78:d5:0e:9a:89:16:6a:35:9e:57:4c:
         4c:3c:a5:e5:9f:ae:79:92:4f:e6:f1:86:b3:6a:2e:
         bd:e9:bf:09:fe:4d:e5:04:53
     generator: 2 (0x2)

The users must exchange their public keys. To do so, they must first extract their public keys into separate files using the pkey command

alice@node1:~$ openssl pkey -in dhprivkey-alice.pem -pubout -out dhpub-alice.pem

Bob would perform a similar command as above with his keys (not shown).

We can view the public keys:

alice@node1:~$ openssl pkey -pubin -in dhpub-alice.pem -text
-----BEGIN PUBLIC KEY-----
MIIBIDCBlQYJKoZIhvcNAQMBMIGHAoGBAOZVzJ4E8766527Mp3FD71xEUYdmFan4
                                                                                      
                                                                                      
tPcSuPO99H7n9xfAm7WytmRQgxNn2dz4X58FKLzVMY+x2rLyPOd8SLa3OB7tE+gK
FMymswteN//lPbFeLWtyei787lGJNnjVDpqJFmo1nldMTDyl5Z+ueZJP5vGGs2ou
vem/Cf5N5QRTAgECA4GFAAKBgQDZq9eMk9/d65INV9ZRMSbY8RGMkjekUQFAjb/+
bP2VsBGgFuTgq4rvBgHoNqRSuLuIvnynHk8i+XqmX4NY7mk0jRIn1l225TZB0aZU
KqS+S0rcdfrIFq95qOP1CX+DE+e3Jd836tyMd04gM9+pnJXM7zM79AKwZhmMMEge
KoOHXA==
-----END PUBLIC KEY-----
PKCS#3 DH Public-Key: (1024 bit)
     public-key:
         00:d9:ab:d7:8c:93:df:dd:eb:92:0d:57:d6:51:31:
         26:d8:f1:11:8c:92:37:a4:51:01:40:8d:bf:fe:6c:
         fd:95:b0:11:a0:16:e4:e0:ab:8a:ef:06:01:e8:36:
         a4:52:b8:bb:88:be:7c:a7:1e:4f:22:f9:7a:a6:5f:
         83:58:ee:69:34:8d:12:27:d6:5d:b6:e5:36:41:d1:
         a6:54:2a:a4:be:4b:4a:dc:75:fa:c8:16:af:79:a8:
         e3:f5:09:7f:83:13:e7:b7:25:df:37:ea:dc:8c:77:
         4e:20:33:df:a9:9c:95:cc:ef:33:3b:f4:02:b0:66:
         19:8c:30:48:1e:2a:83:87:5c
     prime:
         00:e6:55:cc:9e:04:f3:be:ba:e7:6e:cc:a7:71:43:
         ef:5c:44:51:87:66:15:a9:f8:b4:f7:12:b8:f3:bd:
         f4:7e:e7:f7:17:c0:9b:b5:b2:b6:64:50:83:13:67:
         d9:dc:f8:5f:9f:05:28:bc:d5:31:8f:b1:da:b2:f2:
         3c:e7:7c:48:b6:b7:38:1e:ed:13:e8:0a:14:cc:a6:
         b3:0b:5e:37:ff:e5:3d:b1:5e:2d:6b:72:7a:2e:fc:
         ee:51:89:36:78:d5:0e:9a:89:16:6a:35:9e:57:4c:
         4c:3c:a5:e5:9f:ae:79:92:4f:e6:f1:86:b3:6a:2e:
         bd:e9:bf:09:fe:4d:e5:04:53
     generator: 2 (0x2)

After exchanging public keys, i.e. the files dhpub-alice.pem and dhpub-bob.pem, each user can derive the shared secret. Alice uses her private key and Bob’s public key to derive a secret, in this case a 128 Byte binary value written into the file secret-alice.bin:

alice@node1:~$ openssl pkeyutl -derive -inkey dhprivkey-alice.pem -peerkey dhpubkey-bob.pem -out secret-alice.bin

Bob does the same using his private key and Alice’s public key to produce his secret in the file secret-bob.bin:

bob@node2:~$ openssl pkeyutl -derive -inkey dhprivkey-bob.pem -peerkey dhpub-alice.pem -out secret-bob.bin

The secrets should be the same. Although there is no need for Bob to send his secret file to Alice, if he did, then Alice can use cmp to compare the files, or even xxd to manually inspect the binary values:

alice@node1:~$ cmp secret-alice.bin secret-bob.bin
alice@node1:~$ xxd secret-alice.bin
                                                                                      
                                                                                      
0000000: b7cb b892 b541 7810 d8ec d089 6c89 3c19  .....Ax.....l.<.
0000010: e8e1 27d8 66ee dac8 684a f0bd 0a7f e7d3  ..'.f...hJ......
0000020: 3643 8654 fddf 4399 e58e 2c7c 3d33 9532  6C.T..C...,|=3.2
0000030: f693 edf2 c9a0 40e8 58b8 38de 74a5 c0b0  ......@.X.8.t...
0000040: 64ab 4006 a3cd d795 2cef d0fc 2b0f d1ab  d.@.....,...+...
0000050: d1e5 1a2a 3431 e3fa ba63 f7cf 1c61 ff65  ...*41...c...a.e
0000060: d9cd c85d c5fe 5c50 c543 aaeb de49 8501  ...]..\P.C...I..
0000070: 6cf1 66a6 87b6 ddec 835c b4b1 3d9d e2fe  l.f......\..=...
alice@node1:~$ xxd secret-bob.bin
0000000: b7cb b892 b541 7810 d8ec d089 6c89 3c19  .....Ax.....l.<.
0000010: e8e1 27d8 66ee dac8 684a f0bd 0a7f e7d3  ..'.f...hJ......
0000020: 3643 8654 fddf 4399 e58e 2c7c 3d33 9532  6C.T..C...,|=3.2
0000030: f693 edf2 c9a0 40e8 58b8 38de 74a5 c0b0  ......@.X.8.t...
0000040: 64ab 4006 a3cd d795 2cef d0fc 2b0f d1ab  d.@.....,...+...
0000050: d1e5 1a2a 3431 e3fa ba63 f7cf 1c61 ff65  ...*41...c...a.e
0000060: d9cd c85d c5fe 5c50 c543 aaeb de49 8501  ...]..\P.C...I..
0000070: 6cf1 66a6 87b6 ddec 835c b4b1 3d9d e2fe  l.f......\..=...

Now both Alice and Bob have a shared secret, securely exchanged across a public network using Diffie-Hellman.

8.2.9 Performance Benchmarking

OpenSSL has a built-in operation for performance testing. It encrypts random data over short period, measuring how many bytes can be encrypted per second. It can be used to compare the performance of different algorithms, and compare the performance of different computers.

To run performance tests across a large set of algorithms, simple use the speed operation. Note that it may take a few minutes:

$ openssl speed
...

You can select the algorithms to test, e.g. AES, DES and MD5:

$ openssl speed aes-128-cbc des md5
...
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
md5              68101.86k   199387.83k   444829.62k   639419.85k   734323.76k
des cbc          76810.00k    78472.53k    78442.77k    79241.85k    78440.45k
des ede3         28883.98k    29585.17k    29640.69k    29499.08k    29740.52k
aes-128 cbc     138894.09k   150561.30k   154512.15k   155203.81k   155590.46k

The output shows the progress, the versions and options used for OpenSSL and then a summary table at the end. Focus on the summary table, and the last line (for aes-128-cbc) in the example above. The speed test encrypts as many b Byte input plaintexts as possible in a period of 3 seconds. Different size inputs are used, i.e. b = 16, 64, 256, 1024 and 8192 Bytes. The summary table reports the encryption speed in Bytes per second. So if 25955833 16-Byte plaintext values are encrypted in 3 seconds, then the speed reported in the summary table is 25955833 ÃŮ 16 Ãů 3 âĽĹ 138 million Bytes per second. You can see that value (138,894.09kB/s) in the table above. So AES using 128 bit key and CBC can encrypt about 138 MB/sec when small plaintext values are used and 155 MB/sec when plaintext values are 8192 Bytes.

Normally OpenSSL implements all algorithms in software. However recent Intel CPUs include instructions specifically for AES encryption, a feature referred to as AES-NI. If an application such as OpenSSL uses this special instruction, then part of the AES encryption is performed directly by the CPU. This is usually must faster (compared to using general instructions). To run a speed test that uses the Intel AES-NI, use the evp option:

$ openssl speed -evp aes-128-cbc
...
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-128-cbc     689927.75k   729841.81k   745383.38k   747226.84k   747784.87k

Compare the values to the original results. In the original test we achieved 138 MB/sec. Using the Intel AES hardware encryption we get a speed of 689 MB/sec, about 5 times faster.

8.3 Using Classical Ciphers with pycipher

To learn some of the concepts and approaches used by current encryption algorithms (ciphers), it can be useful to first study how some of the original, simpler ciphers work (e.g. Caesar cipher, Playfair, Vigenere). With these simpler ciphers, often referred to as classical ciphers, it is quite easy to understand the algorithm and even perform encryption/decryption by hand. Athlough most are trivial to break with computers today, the concepts they use are often applied in current day ciphers.

Often classical ciphers are studied in my security subjects. Although it is valuable to initially perform the encryption steps by hand, sometimes its useful to use software to speed things up. pycipher is a Python package that implements many classical ciphers. It has good documentation on how to use it, including installation instructions. Below I give two alternatives to install pycipher in a virtnet node. The first is the default and easiest that uses git. The second is an alternative if git is not available and you want a specific version of pycipher.

8.3.1 Install pycipher (Recommended Method)

In a terminal on the virtual node run:

$ sudo apt-get update
$ sudo apt-get install git python-pip
$ sudo pip install git+git://github.com/jameslyons/pycipher

8.3.2 Install pycipher (Alternative Method)

If the recommended method above does not work (e.g. you don’t have or want to use git or pip), then you could try the following:

$ sudo apt-get install unzip python-setuptools
$ wget https://github.com/jameslyons/pycipher/archive/master.zip
$ unzip master.zip
$ cd pycipher-master/
$ sudo python setup.py install
$ python setup.py test

This installs and tests the latest version. Depending on the version, some tests my fail. In my case it ran 41 tests, but 2 tests failed (using the Porta algorithm). Do not use the algorithms that failed the tests.

8.3.3 Using pycipher

A quick example of encrypting and decrypting with pycipher is below. Other ciphers include: Beaufort, Foursquare, Enigma, Polybius, Bifid, ADFGVX, Coltrans, Playfair, and Vigenere. Details on the ciphers supported and how to use them are in the latest documentation.

$ python
Python 2.7.3 (default, Feb 27 2014, 20:00:17)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pycipher
>>> pycipher.Caesar(3).encipher("hello")
'KHOOR'
>>> pycipher.Caesar(3).decipher("khoor")
'HELLO'
>>> quit()