...making Linux just a little more fun! |
By Vinayak Hegde |
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.
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.
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 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 :-
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 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; } |
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 |
Consider an instant messenger software (IM) which wants to communicate with another IM securely. The following approach could be followed.
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).