OpenSSL, C++ and AES Encryption (Just scratching the surface)
Cryptography is a fascinating subject that I would like to learn more about. While I may not make any contributions in cryptology in my career, I can certainly appreciate the mathematics, mathematicians and engineers who have helped make encryption more mainstream. As I'm interested in applying cryptography in the software I create I decidd to look at how I can operate OpenSSL.
As with my previous foray into the world of Bouncy Castle (a C# Cryptographic library) I have found the documentation surrounding OpenSSL to be inadequate. While I hope what I write here can be useful to someone investigating one facet OpenSSL I hope to come back here in the future to refresh my memory when working with AES in OpenSSL in the future.
References
- OpenSSL is written by monkeys [peereboom.us]
- Reddit Commentary: OpenSSL is written by monkeys [reddit.com/r/programming]
- Comparison of TLS implementations [wikipedia.org]
- Compare SSL Libraries [curl.haxx.se]
- NaCL: Networking and Cryptographic Library [nacl.cr.yp.to]
- OpenSSL in BB10 Cascades [supportforums.blackberry.com]
- How to choose an AES encryption mode (CBC ECB CTR OCB CFB)? [stackoverflow.com]
- Block cipher mode of operation [wikipedia.org]
- AES Encryption -Key Generation with OpenSSL (Get Random Bytes for Key) [stackoverflow.com]
- How to do encryption using AES in Openssl [stackoverflow.com]
- AES CBC encrypt/decrypt only decrypts the first 16 bytes [stackoverflow.com]
- Initialization Vector [wikipedia.org]
- AES encryption/decryption demo program using OpenSSL EVP apis [saju.net.in]
- OpenSSL using EVP vs. algorithm API for symmetric crypto [stackoverflow.com]
- Some AES Ciphers are only available via EVP (like XTS) [mail-archive.com, openssl-users list]
Adventures in OpenSSL Land
I started my journey into OpenSSL with energy and optimism- I was going to learn how to work with the worlds most commonly used cryptographic library. I figured that mastering this library would help me make better, more secure software. Upon investigating the API documentation and trying out some sample code it quickly became apparent that OpenSSL has a steep learning curve. I wouldn't be getting anything productive done anytime soon.
After my initial taste of OpenSSL I decided to look at other cryptographic libraries. Was there anything else available? I found quite a few different libraries that have different levels of capability. At the end of the day I wanted to learn a crypto library that was cross platform, well used and secure so I ended up where I started with OpenSSL. That's not to say that the other libraries are 'bad', I just found that for my goals the other libraries either had too many dependencies, didn't work on all the platforms I thought I would be working on or were too limited in functionality for my needs. If you are starting a crypto project that fits into a smaller box, the other options (Like NaCL or GnuTLS) may do what you need them to do.
For BlackBerry 10 Developers
In your .pro file, add this line:
LIBS += -lcrypto
Without it you won't be able to successfully build an application that leverages OpenSSL
Important Notes for New OpenSSL Devs
- When working with the AES_* APIs (such as AES_cbc_encrypt), be sure to pass in a copy of your Initialization Vector (IV) if you plan on using it elsewhere in your program. I found during my testing that if you only have one copy of the IV and use it in multiple locations that it 'gets corrupted' (for lack of a better term). This will be most visible when setting up a test method that Encrypts a string then immediately Decrypts it (as seen below).
- Before using the AES API to encrypt, you have to run AES_set_encrypt_key(...) to setup the AES Structure required by the OpenSSL API. Likewise, you have to call AES_set_decrypt_key(...) to setup the AES Structure required to decrypt data using the OpenSSL API
OpenSSL and AES Encryption (Options)
I found a couple of different APIs that can be used to perform AES Encryption using OpenSSL. That's not to say that there may not be more, just that these are the ones I was able to find by googling:
- AES API
- This API lets you get right into encrypting or decrypting data using the AES cipher. The available functions can be found in openssl/aes.h
(At the time of this writing I was unable to find even a stub of a page on the OpenSSL Site that describes the AES API to any depth)
- EVP API
- This API lets you abstract the specific type of encryption used. It makes it easy to change out which cryptographic provider is used with less refactoring on your part. The available function list can be found in openssl/evp.h
For my purposes I decided to use the AES API directly. I made this decision based on the fact that I seemed to get further faster with the examples that used the AES API. As I gain proficiency with OpenSSL I'll be able to come back later and (hopefully) swallow the EVP API if I need to.
Get A Sample AES Encryption Function Going
In order to get the AES API to work with the ASCII data that I will be feeding it, I needed to setup:
- A random number that can be used as an Encryption Key
- A random number that can be used as an Initialization Vector
- A couple of OpenSSL AES_KEY structures for encrypting and decrypting via the API
- A function to pad my text input so it encrypts and decrypts cleanly
The result is this sample code which encrypts a string then decrypts it (minus error handling):
#include <inttypes.h>
#include <string>
#include <algorithm>
#include <openssl/aes.h>
#include <openssl/rand.h>
uint8_t Key[32];
uint8_t IV[AES_BLOCK_SIZE]; // Generate an AES Key
RAND_bytes(Key, sizeof(Key)); // and Initialization Vector
RAND_bytes(IV, sizeof(IV)); //
// Make a copy of the IV to IVd as it seems to get destroyed when used
uint8_t IVd[AES_BLOCK_SIZE];
for(int i=0; i < AES_BLOCK_SIZE; i++){
IVd[i] = IV[i];
}
/** Setup the AES Key structure required for use in the OpenSSL APIs **/
AES_KEY* AesKey = new AES_KEY();
AES_set_encrypt_key(Key, 256, AesKey);
/** take an input string and pad it so it fits into 16 bytes (AES Block Size) **/
std::string txt("this is a test");
const int UserDataSize = (const int)txt.length(); // Get the length pre-padding
int RequiredPadding = (AES_BLOCK_SIZE - (txt.length() % AES_BLOCK_SIZE)); // Calculate required padding
std::vector<unsigned char> PaddedTxt(txt.begin(), txt.end()); // Easier to Pad as a vector
for(int i=0; i < RequiredPadding; i++){
PaddedTxt.push_back(0); // Increase the size of the string by
} // how much padding is necessary
unsigned char * UserData = &PaddedTxt[0];// Get the padded text as an unsigned char array
const int UserDataSizePadded = (const int)PaddedTxt.size();// and the length (OpenSSl is a C-API)
/** Peform the encryption **/
unsigned char EncryptedData[512] = {0}; // Hard-coded Array for OpenSSL (C++ can't dynamic arrays)
AES_cbc_encrypt(UserData, EncryptedData, UserDataSizePadded, (const AES_KEY*)AesKey, IV, AES_ENCRYPT);
/** Setup an AES Key structure for the decrypt operation **/
AES_KEY* AesDecryptKey = new AES_KEY(); // AES Key to be used for Decryption
AES_set_decrypt_key(Key, 256, AesDecryptKey); // We Initialize this so we can use the OpenSSL Encryption API
/** Decrypt the data. Note that we use the same function call. Only change is the last parameter **/
unsigned char DecryptedData[512] = {0}; // Hard-coded as C++ doesn't allow for dynamic arrays and OpenSSL requires an array
AES_cbc_encrypt(EncryptedData, DecryptedData, UserDataSizePadded, (const AES_KEY*)AesDecryptKey, IVd, AES_DECRYPT);
Afterword
I look forward to getting more proficient with the OpenSSL Library. I bet I'll get the hang of it with a bit more practice.