In a previous post we went over how to use the OpenSSL API in C to decrypt AndroidPay data. There was something I didn’t realize in my implementation. I was using version 1.1.0 over the OpenSSL API and there are a lot of folks still running versions earlier than that.

Unfortunately there are some API differences between 1.1.0 and earlier versions and even more unfortunately, we do hit a couple of them.

One of the biggest differences is in creating a new EVP_MD_CTX which we do when generating the symmetric encryption key and the mac key. In OpenSSL versions >= 1.1.0 the function to create a new EVP_MD_CTX is EVP_MD_CTX_new() this lines up with many of the other new instance creation functions in OpenSSL. However prior to 1.1.0 the way to get a new EVP_MD_CTX instance is with a call to EVP_MD_CTX_create().

We need to reconcile this and ideally we need a solution that works in both instances. This is where we can use a preprocessor conditional.

1
2
3
4
5
6
7
EVP_MD_CTX *hmac;

#if OPENSSL_VERSION_NUMBER >= 0x10100000L 
    hmac = EVP_MD_CTX_new();
#else
    hmac = EVP_MD_CTX_create();
#endif

This code snippet will only surface the method call that corresponds to the correct OpenSSL API. Now since there are different EVP_MD_CTX creation functions of course that means there are different functions to clean up EVP_MD_CTX instances so we need to use the same preprocessor conditionals.

1
2
3
4
5
#if OPENSSL_VERSION_NUMBER >= 0x10100000L 
    EVP_MD_CTX_free(hmac);
#else
    EVP_MD_CTX_destroy(hmac);
#endif

The next incompatibility deals with how the HMAC() function works. In versions >= 1.1.0 we could use NULL and 0 if we didn’t want to specify a salt for the HKDF algorithm.

1
2
3
4
5
6
7
const EVP_MD *sha256 = EVP_sha256();
unsigned char *prc;
unsigned int prc_len = EVP_MD_size(sha256);

if (HMAC(sha256, NULL, 0, input_keying_material, input_keying_material_len, prc, &prc_len) == NULL) {
    ERROR;
}

In prior version that call results in an error because a key (what we call a salt in HKDF) has to be specified and the length has to be greater than zero. Luckily the AndroidPay documentation covers this by telling us that not providing a salt is equivalent to 32 zeroed bytes. So we’ll create a key that’s 32 zeroed bytes and make the length of our key 32.

1
2
3
4
5
6
7
8
9
const EVP_MD *sha256 = EVP_sha256();
unsigned char *prc;
unsigned int prc_len = EVP_MD_size(sha256);
const unsigned char salt[33] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
const int salt_len = 32;

if (HMAC(sha256, salt, salt_len, input_keying_material, input_keying_material_len, prc, &prc_len) == NULL) {
    ERROR;
}

Remember that 0 is different from \0 we basically want to use NULL values and 0 isn’t a NULL value. Doing this will work in all versions of OpenSSL so we don’t need any preprocessor conditionals.

Those two changes are really all that’s needed to update the code from the previous post so that it works with older versions of OpenSSL. I should note that the lowest version I tested with is 1.0.1. I can’t guarantee that anything older than that will work.