[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]
LINUX GAZETTE
...making Linux just a little more fun!
Encryption using OpenSSL's crypto libraries
By Vinayak Hegde

Motivation for the article

Linux has already made quite a few inroads into the corporate world. One of the persistent demands of the corporate world has been a need for better data security. This is where encryption comes in, to hide sensitive data from a third party intruder. Open-source software has a reputation for secure programming. This article is another step in that direction.

OpenSSL's libcrypto is a really good library if you want to use encryption without bothering with the details of underlying implementation of the algorithm. The problem is that the documentation is really minimal. You can obviously read the source and figure out what going on. Also the fact that function names are intuitive helps to some extent. Another way of getting help is joining the various mailing lists from the OpenSSL website. However the command line tools of OpenSSL are pretty well documented and easy to use. I shall explain in this article how to use the blowfish algorithm for encryption using OpenSSL's crypto libraries.

Some Background Information

During the early days of cryptography, algorithms as well as keys were secret. However now that trend has changed. Now algorithms are publicly known and keys are kept secret. The best example of this is the RSA algorithm which is widely known and implemented. The public key are known to the world but the private keys are kept secret. RSA is an asymmetric algorithm as it does not use the same key for encryption and decryption. Also it is generally not advisable to use RSA for encrypting large amounts of data as the it is computationally intensive.

For encrypting large amounts of data, generally less computationally intensive algorithms are prefered. In this article we use the blowfish algorithm for encrypting and decrypting data. Blowfish is a symmetric algorithm which means it uses the same key for encryption and decryption. Blowfish was designed by the famous cryptographer Bruce Schneier. Blowfish is a fast algorithm for encryption/decryption.

Generating the key

For the purposes of demonstration we shall use a 128-bit key. This is stored as an character array in the program. We also generate an 64 bit initialization vector(IV). For our program we will use Cipher Block Chaining (CBC) mode. Also we will not use the blowfish functions directly but use then through a the higher level interface.

An initialization vector is a bit of random information that is used as an input in chained encryption algorithms, that is, when each stage of encrypting a block of input data provides some input to the encryption of the next block. (blowfish uses 64-bit blocks for encryption). The IV provides the first bit of input for encrypting the 1st block of data, which then provides input for the 2nd block and so on. The bit left over at the end is discarded.

The random bits are generated from the character special file /dev/random which provides a good source for random numbers. See the manpage for more information.


int
generate_key ()
{
	int i, j, fd;
	if ((fd = open ("/dev/random", O_RDONLY)) == -1)
		perror ("open error");

	if ((read (fd, key, 16)) == -1)
		perror ("read key error");

	if ((read (fd, iv, 8)) == -1)
		perror ("read iv error");
	
	printf("128 bit key:\n");
	for (i = 0; i < 16; i++)
		printf ("%d \t", key[i]);
	printf ("\n ------ \n");

	printf("Initialization vector\n");
	for (i = 0; i < 8; i++)
		printf ("%d \t", iv[i]);

	printf ("\n ------ \n");
	close (fd);
	return 0;
}

The Encryption routine

The encryption routine takes two parameters - the file descriptors of input file and the output file to which the encrypted data is to be saved. It is always a good idea to zero-fill your buffers using the memset or bzero commands before using the buffers with data. This is especially important if you plan to reuse the buffers. In the program below, the input data is being encrypted in blocks of 1K each.

The steps for encryption are as follows :-

  1. Create a cipher context
  2. Initialize the cipher context with the values of Key and IV
  3. Call EVP_EncryptUpdate to encrypt successive blocks of 1k eack
  4. Call EVP_EncryptFinal to encrypt "leftover" data
  5. Finally call EVP_CIPHER_CTX_cleanup to discard all the sensitive information from memory

You may be wondering what "leftover" data is? As mentioned earlier, Blowfish encrypts information in blocks of 64-bit each. Sometimes we may not have 64 bits to make up a block. This may happen if the buffer size in the program below or the file/input data size is not a integral multiple of 8 bytes(64-bits).So accordingly the data is padded and then the partial block is encrypted using EVP_EncryptFinal. The length of the encoded data block is stored in the variable tlen and added to the final length.


int
encrypt (int infd, int outfd)
{
	unsigned char outbuf[OP_SIZE];
	int olen, tlen, n;
	char inbuff[IP_SIZE];
	EVP_CIPHER_CTX ctx;
	EVP_CIPHER_CTX_init (& ctx);
	EVP_EncryptInit (& ctx, EVP_bf_cbc (), key, iv);

	for (;;)
	  {
		  bzero (& inbuff, IP_SIZE);

		  if ((n = read (infd, inbuff, IP_SIZE)) == -1)
		    {
			    perror ("read error");
			    break;
		    }
		  else if (n == 0)
			  break;

		  if (EVP_EncryptUpdate (& ctx, outbuf, & olen, inbuff, n) != 1)
		    {
			    printf ("error in encrypt update\n");
			    return 0;
		    }

		  if (EVP_EncryptFinal (& ctx, outbuf + olen, & tlen) != 1)
		    {
			    printf ("error in encrypt final\n");
			    return 0;
		    }
		  olen += tlen;
		  if ((n = write (outfd, outbuf, olen)) == -1)
			  perror ("write error");
	  }
	EVP_CIPHER_CTX_cleanup (& ctx);
	return 1;
}

The Decryption routine

The decryption routine basically follows the same steps as the encryption routine. The following code show how the decryption is done.
 

int
decrypt (int infd, int outfd)
{
	unsigned char outbuf[IP_SIZE];
	int olen, tlen, n;
	char inbuff[OP_SIZE];
	EVP_CIPHER_CTX ctx;
	EVP_CIPHER_CTX_init (& ctx);
	EVP_DecryptInit (& ctx, EVP_bf_cbc (), key, iv);

	for (;;)
	  {
		  bzero (& inbuff, OP_SIZE);
		  if ((n = read (infd, inbuff, OP_SIZE)) == -1)
		    {
			    perror ("read error");
			    break;
		    }
		  else if (n == 0)
			  break;

		  bzero (& outbuf, IP_SIZE);

		  if (EVP_DecryptUpdate (& ctx, outbuf, & olen, inbuff, n) != 1)
		    {
			    printf ("error in decrypt update\n");
			    return 0;
		    }

		  if (EVP_DecryptFinal (& ctx, outbuf + olen, & tlen) != 1)
		    {
			    printf ("error in decrypt final\n");
			    return 0;
		    }
		  olen += tlen;
		  if ((n = write (outfd, outbuf, olen)) == -1)
			  perror ("write error");
	  }

	EVP_CIPHER_CTX_cleanup (& ctx);
	return 1;
}

The complete code

A minimal interactive program implementing the above routines can be downloaded from here . The command for compiling the program is
# gcc -o blowfish sym_funcs.c -lcrypto
The program takes three files from the command line

  1. File to be encrypted
  2. File is which the encrypted data is to be stored
  3. File in which decrypted data is to be stored
Don't forget to generate a key before encrypting ;).

An Example Application - A Secure Instant Messenger

Consider an instant messenger software (IM) which wants to communicate with another IM securely. The following approach could be followed.

  1. Each IM client has it's own public and private key.
  2. The IM client has the public keys of all the IMs it wants to communicate with. (say friends' IMs).
  3. The session key is generated by the client which initiates the connection. This session key is used for encrypting the messages between the two clients.
  4. The session key is encrypted and exchanged between two/multiple clients using public-Key encryption.(eg. RSA algorithm). Thus Authentication is also taken care of.
  5. The exchange of encrypted data (using Blowfish symmetric encryption) thereafter takes place between the different clients after this "security handshake".

Resources

  1. OpenSSL Homepage
  2. The Blowfish Algorithm
  3. Handbook of Applied Cryptography

 

[BIO] My life changed since I discovered Linux. Suddenly Computers became interesting as i could try out lots of stuff on my Linux box due to the easy availabily of source code. My interests are predominantly in the fields of networking, embedded systems and programming languages. I currently work for Aparna Web services where we make Linux accessible for academia/corporations by configuring remote boot stations (Thin Clients).


Copyright © 2003, Vinayak Hegde. Copying license http://www.linuxgazette.net/copying.html
Published in Issue 87 of Linux Gazette, February 2003

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]