Friday, May 12, 2023

Why You Don't Want To Use CFMX_COMPAT Encryption

This is the first of what may be a couple of posts about my presentation from ColdFusion Summit East 2023, which was held in April in Washington, DC.

Let's talk about ColdFusion and encryption.  Specifically -- about the CFMX_COMPAT algorithm.  The encrypt() function was introduction in ColdFusion 4 (ca. November 1998), and CFMX_COMPAT was the only algorithm available.  The release of ColdFusion 7 (ca. February 2005) added native support for AES, 3DES, DES, and Blowfish.  But CFMX_COMPAT remains the default algorithm used by the encrypt() function.   

Most ColdFusion developers probably know that they shouldn't use CFMX_COMPAT.  Or at least have an understanding that it's not a secure choice, even if they're not fully aware about why it's insecure.  The Adobe encrypt() documentation says as much, stating "This algorithm is the least secure option (default)[...]The default algorithm, which is the same one used in ColdFusion 5 and ColdFusion MX, uses an XOR-based algorithm that uses a pseudo-random 32-bit key, based on a seed passed by the user as a function parameter. This algorithm is less secure than the other available algorithms."

But as the default algorithm, it's what you'll get if you don't explicitly specify an algorithm.  And it's very insecure, especially if the encrypted data is ever exposed to the user.  

The team at Synactiv has an excellent blog post walking through the cryptographic weaknesses and means of attack against CFMX_COMAT, and you can look at the actual implementation of the algorithm in the Lucee source code.  

But let's break it down even more simply.  CFMX_COMPAT uses a 32-bit key, which is generated from the "key" (seed)  provided by the user.  32 bits = Four Characters.  But where do these four characters come from?  They come from the user-provided seed!  And for seeds that are 8 or more characters, it uses characters 5 through 8, regardless of the total length of the seed.  So - the following three encrypt() calls - 


encrypt('MySecretData', 'ABCDy123','CFMX_COMPAT','hex')


all result in the same ciphertext! - 5AAEA4A990809B8AB37FA88E

And what does 32 bits (or 4 characters) really mean in terms of total number of possibilities and the overall size of the key space?

A key space of 4 billion isn't awful, but is still reasonable to crack easily with sufficient hardware.  But if you're using CFMX_COMPAT, it's likely that (at best), you're only using ASCII printable characters in your seed.   So if you expose data that is encrypted with CFMX_COMPAT to the user, he will need to make a maximum of around 81 million guesses to obtain a valid 32-bit  (4 character) seed that can then be used to encrypt and decrypt any values.  And these guesses will be made offline, with no interaction with your application, nothing to detect, and nothing to log.  Going from 4 billion to 81 million is a pretty significant decrease.  Plus there are probable ways to make the brute-force guesses more efficient, cut down on total character set size, and recover a valid seed even faster.  And if you're using a smaller character set, you're left with a significantly smaller total key space.  

So if you shouldn't use CFMX_COMPAT, what should you use?  AES in CBC Mode (with added ciphertext integrity checking) is the best choice for a native, symmetric-key algorithm in ColdFusion.  But even that can have security pitfalls to watch out for.  Which will be a topic for a future blog post!

No comments:

Post a Comment