Filter BIOs Abstract InputOutput

79 b = BIO_newBIO_s_bio; BIO_set_write_buf_sizeb, 4096; BIO_make_bio_paira, b; BIO_new_bio_paira, 8192, b, 8192; c = BIO_newBIO_s_bio; BIO_set_write_buf_sizec, 1024; BIO_destroy_bio_paira; disconnect a from b BIO_make_bio_paira, c;

4.3.2 Filter BIOs

A filter BIO by itself provides no utility. It must be chained with a sourcesink BIO and possibly other filter BIOs to be useful. The ability to chain filters with other BIOs is perhaps the most powerful feature of OpenSSLs BIO package, and it provides a great deal of flexibility. A filter BIO often performs some kind of translation of data before writing to or after reading from a concrete medium, such as a file or socket. Creating BIO chains is reasonably simple and straightforward; however, care must be taken to keep track of the BIO that is at the end of the chain so that the chain can be manipulated and destroyed safely. If you destroy a BIO that is in the middle of a chain without first removing it from the chain, its a safe bet that your program will crash shortly thereafter. As we mentioned earlier, the BIO package is one of OpenSSLs lower-level packages, and as such, little error checking is done. This places the burden on the programmer to be sure that any operations performed on a BIO chain are both legal and error-free. When creating a chain, you must also ensure that you create the chain in the proper order. For example, if you use filters that perform base64 conversion and encryption, you would probably want to perform base64 encoding after encryption, not before. Its also important to ensure that your sourcesink BIO is at the end of the chain. If its not, none of the filters in the chain will be used. The interface for creating a filter BIO is similar to creating sourcesink BIO. BIO_new is used to create a new BIO with the appropriate BIO_METHOD object. Filter BIOs are provided by OpenSSL for performing encryption and decryption, base64 encoding and decoding, computing message digests, and buffering. There are a handful of others as well, but they are of limited use, since they are either platform-specific or meant for testing the BIO package. The function shown in Example 4-8 can be used to write data to a file using the BIO package. Whats interesting about the function is that it creates a chain of four BIOs. The result is that the data written to the file is encrypted and base64 encoded with the base64 encoding performed after the data is encrypted. The data is first encrypted using outer triple CBC DES and the specified key. The encrypted data is then base64-encoded before it is written to the file through an in-memory buffer. The in-memory buffer is used because triple CBC DES is a block cipher, and the two filters cooperate to ensure that the ciphers blocks are filled and padded properly. Chapter 6 discusses symmetric ciphers in detail. Example 4-8. Assembling and using a BIO chain int write_dataconst char filename, char out, int len, unsigned char key { int total, written; BIO cipher, b64, buffer, file; Create a buffered file BIO for writing file = BIO_new_filefilename, w; if file TE AM FL Y Team-Fly ® 80 return 0; Create a buffering filter BIO to buffer writes to the file buffer = BIO_newBIO_f_buffer; Create a base64 encoding filter BIO b64 = BIO_newBIO_f_base64; Create the cipher filter BIO and set the key. The last parameter of BIO_set_cipher is 1 for encryption and 0 for decryption cipher = BIO_newBIO_f_cipher; BIO_set_ciphercipher, EVP_des_ede3_cbc, key, NULL, 1; Assemble the BIO chain to be in the order cipher-b64-buffer-file BIO_pushcipher, b64; BIO_pushb64, buffer; BIO_pushbuffer, file; This loop writes the data to the file. It checks for errors as if the underlying file were non-blocking for total = 0; total len; total += written { if written = BIO_writecipher, out + total, len - total = 0 { if BIO_should_retrycipher { written = 0; continue; } break; } } Ensure all of our data is pushed all the way to the file BIO_flushcipher; We now need to free the BIO chain. A call to BIO_free_allcipher would accomplish this, but well first remove b64 from the chain for demonstration purposes. BIO_popb64; At this point the b64 BIO is isolated and the chain is cipher-buffer- file. The following frees all of that memory BIO_freeb64; BIO_free_allcipher; }

4.4 Random Number Generation

Many functions throughout the OpenSSL library require the availability of random numbers. For example, creating session keys and generating publicprivate key pairs both require random numbers. To meet this requirement, the RAND package provides a cryptographically strong pseudorandom number generator PRNG. This means that the random data it produces isnt truly random, but it is computationally difficult to predict. Cryptographically secure PRNGs, including those of the RAND package, require a seed. A seed is essentially a secret, unpredictable piece of data that we use to set the initial state of the PRNG. The security of this seed is the basis for the unpredictability of the output. Using the seed value, the generator can use mathematical and cryptographic transforms to ensure that its output cannot be determined. Ideally, the seed should be high in entropy. Entropy is a measurement of how random data is. To illustrate, lets consider generating a bit of data by flipping a fair coin. The