You are on page 1of 12

OpenSSL DES APIs

OpenSSL DES APIs


Finnbarr P. Murphy
(fpm@fpmurphy.com)

Now that OpenSSL has finally reached version 1.0.0, I decided to take another look how the
various Data Encryption Standard (DES) application programming interfaces (routines) included
in OpenSSL can be used to encrypt and decrypt data. Since there is also a lack of simple examples
available on the Internet of how to actually use the OpenSSL DES routines, I have included a
number of examples in this post to encourage readers to experiment with these routines.

ly
The original author of the DES routines in OpenSSL’s libcrypto was Eric Young. Young and Tim
Hudson posted the first version of of a free cryptographic library called SSLeay (eay stands for

on
Eric A, Young) to the Internet in 1995. Amazingly Young managed to single-handedly implement
the full suite of cryptosystems used in SSLeay. Since then the SSLeay library has become part of
OpenSSL. However you will still frequently come across references to SSLeay in both man pages
and the source code. Young is still involved in cryptography and currently works for RSA, the

se
security division of EMC.

Some background information on DES is probably in order for those who have forgotten their
lu
college course on cryptography. DES has been around for quite a long time. It was developed by
IBM as enhancement to an existing key generator algorithm called Lucifer that was primarily
developed by Horst Feistel. It became a standard in 1977 when the National Bureau of Standards
a
(now called NIST) issued Federal Information Processing Standards Publication 46 (FIPS 46). That
standard specified that DES be used within the Federal Government for the cryptographic
nn

protection of sensitive, but unclassified, computer data.

DES is a member of the class of ciphers (British English: cyphers) called a block cipher. In a block
o

cipher, a block of N bits from the plaintext is replaced with a block of N bits from the ciphertext.
Ideally the relationship between the input block and the output block is completely random but
rs

invertible. This implies a one-to- one relationship with each input block being mapped to a unique
output block. Mathematically, DES maps the set of all possible 64-bit vectors onto itself. Selecting
pe

a DES cryptographic key allows a user to select one of the possible mappings

Technically speaking, DES is an iterative, block, product cipher system (encryption algorithm). A
product cipher system mixes transposition and substitution operations in an alternating manner.
r

Iterations refers to the use of the output of an operation as the input for another iteration of the
Fo

same procedure. This is known as a Feistel structure or Feistel network. A cryptographic system
based on a Feistel structure uses the same basic algorithm for both encryption and decryption. A
large proportion of block ciphers, including DES, use a Festel structure.

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 1/12


OpenSSL DES APIs

ly
on
se
a lu
nn

The algorithmic implementation of DES is known as Data Encryption Algorithm (DEA). DEA uses
o

sixteen iterations of a pair of transposition and substitution operations to encrypt or decrypt an


rs

input block. All computations are linear except for the Substitution-boxes (S-boxes) which provide
the non-linear substitution component of the algorithm. Linear algorithms can be easily broken
using a known plaintext attack. The S-boxes in DEA effectively hinder this form of attack (Claude
pe

Shannon‘s diffusion property.) The number of rounds (16) is important also. An 8-round DEA can
be broken in a few minutes on a PC using a chosen plaintext attack, i.e. differential cryptoanalysis.
When DEA was proposed, there was considerable criticism with most of it directed at the S-boxes.
It was even suggested the the S-boxes might contain a trapdoor. One useful property of DEA is
r

that it can be implemented very efficiently in software (or in hardware for that matter) using table
Fo

look-up. DES uses a 56-bit encryption key and a 64-bit block. The key itself is specified with 8
bytes (64-bits), but the last bit of each byte is used as a parity check of the other 7 bits. Round
keys are 48-bits and are generated from the 56-bit encryption key by a sequence of permutations.

Several methods of incorporating DES into a cryptographic system are possible. Generally
speaking, these can be classified into either block or stream methods. In addition a number of
modes of operation are specified by the FIPS 81 (DES Modes of Operation) standard. The modes
specify how data will be encrypted and decrypted. These are summarized below.

Electronic Codebook Mode (ECB)

● 64 bits (i.e. a block) are enciphered at a time.


● The order of the blocks can be rearranged without detection.
● A plaintext block always produces the same ciphertext block for the same key.
● An error only affects one ciphertext block.

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 2/12


OpenSSL DES APIs

● Use discouraged as vulnerable to a directory attack

Cipher Block Chaining Mode (CBC)

● Multiples of 64 bits are enciphered at a time.


● Blocks cannot be rearranged. Each ciphertext block depends on the current and all preceding
plaintext blocks.
● A plaintext block always produces the same ciphertext block for the same key and starting
variable.
● Different starting variables prevent the same plaintext enciphering to the same ciphertext.
● An error affects the current and following ciphertext blocks.

Cipher Feedback Mode (CFB)

ly
● Only blocks of j <= 64 bits are enciphered at a time.
● A small j requires more cycles through the encipherment algorithm per unit of plaintext and thus

on
greater processing overhead.
● A plaintext block always produces the same ciphertext block for the same key and starting
variable.
● Blocks cannot be rearranged. Each ciphertext block depends on the current and all preceding

se
plaintext blocks.
● Different starting variables are used to prevent the same plaintext enciphering to the same
ciphertext.
lu
● The strength of this mode depends on the size of the key k (best if j == k).
● An error will affect the current and the following ciphertext blocks.
a
Output Feedback Mode (OFB)
nn

● Only blocks of j <= 64 bits are enciphered at a time.


● A small j requires more cycles through the encipherment algorithm per unit of plaintext and thus
greater processing overhead.
o

● A plaintext block always produces the same ciphertext block for the same key and starting
variable.
rs

● Different starting variables are used to prevent the same plaintext enciphering to the same
ciphertext.
pe

● Absence of chaining makes this mode vulnerable to specific attacks.


● Different start variable values prevent the same plaintext enciphering to the same ciphertext, by
producing different key streams.
● An error bit in the ciphertext causes only one bit to be in error in the deciphered plaintext.
r

● It is not self-synchronizing.
Fo

Triple-DES ECB Mode

● Encrypt with key1, decrypt with key2 and encrypt with key3 again.
● As for ECB encryption but increases the key length to 168 bits.
● If all keys are the same it is equivalent to encrypting once with just one key.
● If the first and last key are the same, the key length is 112 bits.
● If all 3 keys are the same, this is effectively the same as normal ECB mode.

Triple-DES CBC Mode

● Encrypt with key1, decrypt with key2 and then encrypt with key3.
● As for CBC encryption but increases the key length to 168 bits with the same restrictions as the
Triple-DES ESB mode

Our first example shows how to use the basic DES encryption routine, DES_ecb_encrypt(), to

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 3/12


OpenSSL DES APIs

encrypt or decrypt a single 64-bit block of plaintext to electronic code book (ECB) mode. If the
encrypt argument is DES_ENCRYPT, the input (plaintext) is encrypted into the output (ciphertext)
using the specified key_schedule. If the encrypt argument is DES_DECRYPT, the input (ciphertext)
is decrypted into the output (plaintext). Note that input and output may overlap.

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
#include &lt;openssl/rand.h&gt;
#define BUFSIZE 64
int main(void)
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];

ly
unsigned char *e = out;
DES_cblock key;
DES_cblock seed = {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};

on
DES_key_schedule keysched;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
RAND_seed(seed, sizeof(DES_cblock));

se
DES_random_key(&amp;key);
DES_set_key((C_Block *)key, &amp;keysched);
/* 8 bytes of plaintext */
strcpy(in, "HillTown");
lu
printf("Plaintext: [%s]\n", in);
DES_ecb_encrypt((C_Block *)in,(C_Block *)out, &amp;keysched, DES_ENCRYPT);
printf("Ciphertext:");
a
while (*e) printf(" [%02x]", *e++);
printf("\n");
nn

DES_ecb_encrypt((C_Block *)out,(C_Block *)back, &amp;keysched, DES_DECRYPT);


printf("Decrypted Text: [%s]\n", back);
return(0);
}
o
rs

Note the use of C_Block. The examples in this post use C_Block because that is what I am used to
using. If you are writting new code for modern platforms, you should use DES_cblock rather than
C_Block or des_cblock. See des.h for the defintion of DES_cblock, i.e. typedef unsigned char
pe

DES_cblock[8].

Here the output when the program is compiled and executed.


r
Fo

$ gcc -o example1 example1.c -lcrypto


$ ./example1
Plaintext: [HillTown]
Ciphertext: [34] [bc] [85] [30] [14] [95] [43] [00]
Decrypted Text: [HillTown]
$

Examining the above code you will see that there are two parts to using DES encryption. The first
is the generation of a DES_key_schedule from a key, the second is the actual encryption or
decryption. A DES key is of type DES_cblock which consists of 8 bytes with odd parity. The least
significant bit in each byte is the parity bit. The key schedule is an expanded platform-dependent
form of the key which is used to speed the encryption process. The example uses a seeded PRNG (
RAND_seed()) to generate a random 64-bit DES key. Notice that I explicitly zero all storage that
the example uses; always a good idea when using OpenSSL library routines. Examining the output,
you will see that the size of the ciphertext is the same as the plaintext. This is a characteristic of a

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 4/12


OpenSSL DES APIs

block cipher. Note that if you compile and run this example, you will not get the same ciphertext
as I got due to the fact that the example uses a randomly generated key.

Our next example demonstrates the Triple-DES mode. For some reason a lot of people are
unaware that FIPS-46 actually specifies two modes for Triple-DES:

● EDE (Encrypt-Decrypt-Encrypt) where ciphertext = Ek3(Dk2(Ek1(plaintext)))


● EEE (Encrypt-Encrypt-Encrypt) where ciphertext = Ek3(Ek2(Ek1(pliantext)))

where Ek and Dk denote DES encryption and decryption respectively. In addition, ANSI X9.52
defines three key options for Triple-DES:

● k1 != k2 != k3
k1 != k2, k1 = k3, k2 != k3

ly

● k1 = k2 = k3

on
The third option makes Triple-DES backwardly compatible with DES. The recommended usage
mode, per FIPS-46, for Triple-DES is EEE or EDE with three independently generated keys, i.e.
168 key bits in total. OpenSSL uses the EDE mode.

se
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
lu
#include &lt;openssl/des.h&gt;
#include &lt;openssl/rand.h&gt;
#define BUFSIZE 1024
a
int main(void)
{
nn

unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];


unsigned char *e = out;
int i;
DES_cblock key1, key2, key3;
o

DES_cblock seed = {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
DES_key_schedule ks1, ks2, ks3;
rs

memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
pe

RAND_seed(seed, sizeof(DES_cblock));
DES_random_key(&amp;key1);
DES_random_key(&amp;key2);
DES_random_key(&amp;key3);
DES_set_key((C_Block *)key1, &amp;ks1);
r

DES_set_key((C_Block *)key2, &amp;ks2);


DES_set_key((C_Block *)key3, &amp;ks3);
Fo

/* 64 bytes of plaintext */
strcpy(in, "Now is the time for all men to stand up and be counted");
printf("Plaintext: [%s]\n", in);
for (i = 0; i &lt; 63; i += 8) {
DES_ecb3_encrypt((C_Block *)(in + i),(C_Block *)(out + i), &amp;ks1, &amp;ks2, &am
p;ks3, DES_ENCRYPT);
}
printf("Ciphertext:");
while (e++) printf(" [%02x]", *e++);
printf("\n");
for (i = 0; i &lt; 63; i += 8) {
DES_ecb3_encrypt((C_Block *)(out + i),(C_Block *)(back + i), &amp;ks1, &amp;ks2, &
amp;ks3, DES_DECRYPT);
}
printf("Decrypted Text: [%s]\n", back);
exit(0);
}

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 5/12


OpenSSL DES APIs

As you can see, this example uses three different keys (k1 != k2 != k3) which is the recommended
way of using Triple-DES. Here is the output when this example is compiled and executed:

[fpm@ultra ~]$ ./example2


Plaintext: [Now is the time for all men to stand up and be counted]
Ciphertext: [b4] [31] [40] [aa] [41] [7d] [fc] [72] [4b] [f7] [46] [b5] [24] [83] [95] [03
] [38] [1a] [50] [4e] [65] [5e] [83] [19] [b4] [0f] [74] [8b] [0c] [de] [5f] [34] [bf] [ee
] [65] [4a] [b1] [0d] [33] [b4] [db] [cd] [02] [2c] [6c] [39] [7e] [57] [0d] [99] [18] [69
] [23] [56] [fb] [00]
Decrypted Text: [Now is the time for all men to stand up and be counted]
[fpm@ultra ~]$

ly
The next example demonstrates the Cipher Block Chaining mode. In this mode each block is
XOR-ed with the previous cipherblock before encryption.

on
Because changes in the plaintext propagate forever in the ciphertext, encryption cannot be
parallelized. For the first block we start with an initiallization vector (ivec). Note that it is not
unusual to start with a zero vector as the initialization vector. Note that there is both a
DES_cbc_encrypt() and a DES_ncbc_encrypt() in libcrypto. I recommend you only use the ncbc

se
version (n stands for new). See the BUGS section of the OpenSSL DES manpage and the source
code for these functions. lu
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
a
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
nn

#include &lt;openssl/rand.h&gt;
#define BUFSIZE 512
int main(void)
{
o

unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];


unsigned char *e = out;
rs

int len;
DES_cblock key;
DES_cblock seed = {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
pe

DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
DES_key_schedule keysched;
DES_cblock ivec;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
r

memset(back, 0, sizeof(back));
RAND_seed(seed, sizeof(DES_cblock));
Fo

DES_random_key(&amp;key);
DES_set_odd_parity(&amp;key);
if (DES_set_key_checked((C_Block *)key, &amp;keysched))
{
fprintf(stderr, "ERROR: Unable to set key schedule\n");
exit(1);
}
/* 64 bytes of plaintext */
strcpy(in, "Now is the time for all men to stand up and be counted");
printf("Plaintext: [%s]\n", in);
len = strlen(in);
memcpy(ivec, ivsetup, sizeof(ivsetup));
DES_ncbc_encrypt(in, out, len, &amp;keysched, &amp;ivec, DES_ENCRYPT);
printf("Ciphertext:");
while (*e) printf(" [%02x]", *e++);
printf("\n");
memcpy(ivec, ivsetup, sizeof(ivsetup));
DES_ncbc_encrypt(out, back, len, &amp;keysched, &amp;ivec, DES_DECRYPT);

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 6/12


OpenSSL DES APIs

printf("Decrypted Text: [%s]\n", back);


exit(0);
}

Note that I reinitialize ivec before decrypting the ciphertext. If you do not reinitialize ivec your
decrypted text will be incorrect.

The next example uses DES_ede3_ncbc_encrypt() to implement outer triple CBC DES encryption
with three keys. This means that each DES operation inside the CBC mode is
C=E(ks3,D(ks2,E(ks1,M))) . This is the mode is used by SSL.

#include &lt;stdio.h&gt;

ly
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;

on
#include &lt;openssl/rand.h&gt;
#define BUFSIZE 512
int main(void)
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];

se
unsigned char *e = out;
int len;
DES_cblock key1, key2, key3;
DES_cblock seed = {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
lu
DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
DES_cblock ivec;
DES_key_schedule ks1, ks2, ks3;
memset(in, 0, sizeof(in));
a
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
nn

RAND_seed(seed, sizeof(DES_cblock));
DES_random_key(&amp;key1);
DES_random_key(&amp;key2);
DES_random_key(&amp;key3);
o

DES_set_key((C_Block *)key1, &amp;ks1);


DES_set_key((C_Block *)key2, &amp;ks2);
rs

DES_set_key((C_Block *)key3, &amp;ks3);


/* 64 bytes of plaintext */
strcpy(in, "Now is the time for all men to stand up and be counted");
pe

printf("Plaintext: [%s]\n", in);


len = strlen(in);
memcpy(ivec, ivsetup, sizeof(ivsetup));
DES_ede3_cbc_encrypt(in, out, len, &amp;ks1, &amp;ks2, &amp;ks3, &amp;ivec, DES_ENCRYP
T);
r

printf("Ciphertext:");
Fo

while (*e) printf(" [%02x]", *e++);


printf("\n");
len = strlen(out);
memcpy(ivec, ivsetup, sizeof(ivsetup));
DES_ede3_cbc_encrypt(out, back, len, &amp;ks1, &amp;ks2, &amp;ks3, &amp;ivec, DES_DECR
YPT);
printf("Decrypted Text: [%s]\n", back);
exit(0);
}

Note the need to reinitialize ivec before decrypting the ciphertext. If you do not do this, the first
64 bits of the resultant plaintext will be incorrect.

The next example shows the use of a modified form of the CBC mode called Triple DES Cipher
Block Chaining with Output Feedback Masking. This mode provides stronger protection against
dictionary attacks and matching ciphertext attacks that exploit the DES blocksize of 64 bits

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 7/12


OpenSSL DES APIs

through the introduction of secret masking values that are XOR-ed with the intermediate outputs
of each triple-DES encryption operation. Apparantly, however, Eli Biham and Lars Knudsen have
developed an attack on this mode but it requires a lot of work.

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
#include &lt;openssl/rand.h&gt;
#define BUFSIZE 512
#define CBCM_ONE
int main(void)
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];

ly
unsigned char *e = out;
int len;
DES_cblock key1, key2, key3;

on
DES_cblock seed = {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
DES_cblock ivecstr = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
DES_cblock ivec2, ivec1;
DES_key_schedule ks1, ks2, ks3;
memset(in, 0, sizeof(in));

se
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
RAND_seed(seed, sizeof(DES_cblock)); lu
DES_random_key(&amp;key1);
DES_random_key(&amp;key2);
DES_random_key(&amp;key3);
DES_set_key((C_Block *)key1, &amp;ks1);
a
DES_set_key((C_Block *)key2, &amp;ks2);
DES_set_key((C_Block *)key3, &amp;ks3);
nn

/* 64 bytes of plaintext */
strcpy(in, "Now is the time for all men to stand up and be counted");
printf("Plaintext: [%s]\n", in);
memcpy(ivec2, ivecstr, sizeof(ivecstr));
o

memset(ivec1,'&#92;&#48;',sizeof(ivec2));
len = strlen(in) + 1;
rs

#ifdef CBCM_ONE
DES_ede3_cbcm_encrypt(in, out, len, &amp;ks1, &amp;ks2, &amp;ks3, &amp;ivec2, &amp;ive
c1, DES_ENCRYPT);
pe

#else
DES_ede3_cbcm_encrypt(in, out, 16, &amp;ks1, &amp;ks2, &amp;ks3, &amp;ivec2, &amp;ivec
1, DES_ENCRYPT);
DES_ede3_cbcm_encrypt(&amp;in[16], &amp;out[16],len-16, &amp;ks1, &amp;ks2, &amp;ks3,
&amp;ivec2, &amp;ivec1, DES_ENCRYPT);
r

#endif
printf("Ciphertext:");
Fo

while (*e) printf(" [%02x]", *e+);


printf("\n");
len = strlen(out) + 1;
memcpy(ivec2, ivecstr, sizeof(ivecstr));
memset(ivec1,'&#92;&#48;',sizeof(ivec2));
DES_ede3_cbcm_encrypt(out, back, len, &amp;ks1, &amp;ks2, &amp;ks3, &amp;ivec2, &amp;i
vec1, DES_DECRYPT);
printf("Decrypted Text: [%s]\n", back);
exit(0);

The above example showns you two variations for encrypting the plaintext and vice-versa. The
two-step approach is useful in some situations.

The next example shows the use of the Cipher Feedback (CFB) mode. CFB is a close relative of
CBC but is a self-synchronizing stream cipher if the 1-bit mode is selected.

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 8/12


OpenSSL DES APIs

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
#include &lt;openssl/rand.h&gt;
#define BUFSIZE 256
#define CFBMODE 1
int main(void)
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];
unsigned char *e = out;
int len;
DES_cblock key;
DES_cblock seed = {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
DES_cblock ivecstr = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};

ly
DES_cblock ivec;
DES_key_schedule ks;
memset(in, 0, sizeof(in));

on
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
RAND_seed(seed, sizeof(DES_cblock));
DES_random_key(&amp;key);
DES_set_key((C_Block *)key, &amp;ks);

se
/* 11 bytes of plaintext */
strcpy(in, "Philippines");
printf("Plaintext: [%s]\n", in);
memcpy(ivec, ivecstr, sizeof(ivecstr));
lu
len = strlen(in);
DES_cfb_encrypt(in, out, CFBMODE, len, &amp;ks, &amp;ivec, DES_ENCRYPT);
printf("Ciphertext:");
a
while (*e) printf(" [%02x]", *e+);
printf("\n");
nn

len = strlen(out);
memcpy(ivec, ivecstr, sizeof(ivecstr));
DES_cfb_encrypt(out, back, CFBMODE, len, &amp;ks, &amp;ivec, DES_DECRYPT);
printf("Decrypted Text: [%s]\n", back);
o

exit(0);
}
rs

Here is an example which uses the CBF64 mode and also, for the first time, uses ASCII strings for
pe

the initialization vector and DES key.

#include &lt;stdio.h&gt;
r

#include &lt;string.h&gt;
Fo

#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
#define BUFSIZE 256
int main(void)
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];
unsigned char *e = out;
int len;
int n = 0;
static char *keystr = "0123456789abcdef";
static char *ivecstr = "0123456789abcdef";
DES_cblock ivec;
DES_key_schedule ks;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
strcpy(in,"Now is the time for all.");
DES_set_key((C_Block *)keystr, &amp;ks);
printf("Plaintext: [%s]\n", in);

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 9/12


OpenSSL DES APIs

memcpy(ivec, (C_Block *)ivecstr, sizeof(ivec));


len = strlen(in) + 1;
DES_cfb64_encrypt(in, out, len, &amp;ks, &amp;ivec, &amp;n, DES_ENCRYPT);
printf("Ciphertext:");
while (*e) printf(" [%02x]", *e++);
printf("\n");
memcpy(ivec, (C_Block *)ivecstr, sizeof(ivec));
DES_cfb64_encrypt(out, back, len, &amp;ks, &amp;ivec, &amp;n, DES_DECRYPT);
printf("Decrypted Text: [%s]\n", back);
exit(0);
}

Note the use of DES_string_to_key() to convert a string into a key. The inputted string should be at
least 16 characters in length.DES_string_to_key() sets odd parity so there is no need to invoke
DES_set_odd_parity().

ly
The next example demonstrates the use of 8-bit OFB mode. This mode is an additive stream cipher

on
in which errors in the ciphertext are not extended to cause additional errors in the decrypted
plaintext. Thus a single bit in error in the ciphertext causes only one bit to be in error in the
decrypted plaintext. According to the OpenSSL man page, this mode should only be used for small
sizes of plaintext. From experimenting with numbits and the BUGS section of the DES manpage, I

se
suggest you always use a value of 8 for numbits.

#include &lt;stdio.h&gt;
lu
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
a
#include &lt;openssl/rand.h&gt;
#define BUFSIZE 256
nn

int main(void)
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];
unsigned char *e = out;
o

char *keystr = "Philippines06235";


int len, n, result;
rs

DES_cblock key;
DES_cblock ivecstr = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
DES_cblock ivec;
pe

DES_key_schedule ks;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
DES_string_to_key(keystr, &amp;key);
r

if ((result = DES_set_key_checked((C_Block *)key, &amp;ks)) != 0) {


Fo

if (result == -1) {
printf("ERROR: key parity is incorrect\n");
} else {
printf("ERROR: weak or semi-weak key\n");
}
exit(1);
}
strcpy(in,"The Chocolate Hills of Bohol are wonderful.");
printf("Plaintext: [%s]\n", in);
memcpy(ivec, ivecstr, sizeof(ivecstr));
len = strlen(in);
printf("Plaintext Length: %d\n", len);
DES_ofb_encrypt(in, out, 8, len, &amp;ks, &amp;ivec);
n = 0;
printf("Ciphertext:");
while (*e) {
printf(" [%02x]", *e++);
n++;
}

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 10/12


OpenSSL DES APIs

printf("\n");
printf("Ciphertext Length: %d\n", n);
len = strlen(out);
memcpy(ivec, ivecstr, sizeof(ivecstr));
DES_ofb_encrypt(out, back, 8, len, &amp;ks, &amp;ivec);
printf("Decrypted Text: [%s]\n", back);
exit(0);
}

The final example in this post uses ede3_ofb64_encrypt() to perform the encryption and decryption.
It also reads in the plaintext from an external file. To simplify things and shorten the example, I
set k1 = k2 = k3. I will leave it up to you to modify the example to support the case where k1 !=
k2 != k3.

ly
#include &lt;stdio.h&gt;

on
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;openssl/des.h&gt;
#define BUFSIZE 1024
int main(int argc, char *argv[])

se
{
unsigned char in[BUFSIZE], out[BUFSIZE], back[BUFSIZE];
char buf[201];
char *keystr = "Victoria Harbour";
unsigned char *e = out;
lu
FILE *fin;
int i, num, len, result;
int n = 0;
a
DES_cblock key;
DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
nn

DES_key_schedule ks;
DES_cblock ivec;
if (argc != 2) {
printf("ERROR: plaintext filename required\n");
o

exit(1);
}
rs

memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(back, 0, sizeof(back));
pe

DES_string_to_key(keystr, &amp;key);
if ((result = DES_set_key_checked((C_Block *)key, &amp;ks)) != 0) {
if (result == -1) {
printf("ERROR: key parity is incorrect\n");
} else {
r

printf("ERROR: weak or semi-weak key\n");


Fo

}
exit(1);
}
fin = fopen(argv[1], "r");
if (!fin) {
printf(" ERROR: opening input file\n");
exit(1);
}
while(fgets(buf, 200, fin) != NULL) {
strcat(in, buf);
}
fclose(fin);
printf("Plaintext: [%s]\n", in);
len = strlen(in);
printf("Plaintext Length: %d\n", len);
memcpy(ivec, ivsetup, sizeof(ivsetup));
num = 0;
for (i = 0; i &lt; len; i++) {
DES_ede3_ofb64_encrypt(&amp;(in[i]), &amp;(out[i]), 1, &amp;ks, &amp;ks, &amp;ks,

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 11/12


OpenSSL DES APIs

&amp;ivec, &amp;num);
}
n = 0;
printf("Ciphertext:");
while (*e) {
printf(" [%02x]", *e++);
n++;
}
printf("\n");
printf("Ciphertext Length: %d\n", n);
memcpy(ivec, ivsetup, sizeof(ivsetup));
num = 0;
for (i = 0; i &lt; len; i++) {
DES_ede3_ofb64_encrypt(&amp;(out[i]), &amp;(back[i]), 1, &amp;ks, &amp;ks, &amp;ks,
&amp;ivec, &amp;num);
}

ly
printf("Decrypted Text: [%s]\n", back);
exit(0);
}

on
Here is sample output:

se
$ echo -n "Now is the time to finish this post" &gt; plaintext
$ ./example9 plaintext
Plaintext: [Now is the time to finish this post]
Plaintext Length: 35
lu
Ciphertext: [92] [cb] [29] [fe] [aa] [94] [d7] [ba] [07] [a5] [8f] [78] [4f] [13] [fa] [c4
] [4f] [22] [0d] [fd] [b7] [33] [81] [3e] [3a] [e4] [f5] [c6] [52] [c9] [2b] [4f] [d5] [b8
] [00]
a
Ciphertext Length: 35
Decrypted Text: [Now is the time to finish this post]
nn

Well, I think I have covered the OpenSSL v1.0 DES routines in sufficient detail for most readers.
o

There are a number of other routines but these are infrequently used or are slight variations on
the routines used in the above examples. You may come across many references to DES routines
rs

which start with des_. These are essentially the same as the DES_ routines but are from older
versions of libcrypto. The move to DES_ occurred several years ago. You should always use the
pe

DES_ version of a routine if it is available.

Armed with your new knowledge, you should now be able to go away and use DES within your
applications. Feel free to use any source code included in this post. If you want to learn more
r

about DES, Douglas Stinson does an excellent job in Chapter 3 of his book Crytography Theory
Fo

and Practice (ISBN 0-8493-8521-0). Another excellent book, with lots of C source code, is Bruce
Schneir’s Applied Cryptography (ISBN 0-471-59756-2). Unfortunately, currently the OpenSSL man
pages are poor at best and downright inaccurate at worst so you may frequently find yourself
examining the libcrypto source code. All of the relevant DES code is in the ../crypto/des
subdirectory.

Enjoy!

03-03-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 12/12