AES Encryption via iRules
Update (4/26/2011): AES::decrypt and AES::encrypt are broken in all versions and might not behave as expected. Please reference bugs 242479 and 224113.
Security is a primary concern of just about every company that passes data over some form of a network. Whether it's over the internet, internally or both, keeping your data secure is always something to be mindful of. As such, encryption has become a major part of daily life on the network. The most common form, of course, is SSL encryption, to secure entire channels for data transfer. This is both extremely effective, and wide-spread, making it a great first choice.
Sometimes, however, there are some particular cases in which you don't want to, or simply can't use SSL to encrypt the entire transaction. At this point you're looking at encrypting certain portions of the data to keep them secure. This can be not only difficult, but costly as well, by way of server resources and processing time. Never fear, though, iRules is here to help as always.
We offer multiple different data manipulation and encryption options via iRules, ranging from enabling/disabling SSL profiles, to simple b64 encoding. Probably the best bet for security, however, if SSL isn't an option, is to make use of the AES encryption commands available to you via iRules on your LTM. AES, or Advanced Encryption Standard, is a block cipher that was brought into play by the United States government when it was set as a government standard for data security in 2002. AES is a substitution permutation network, which allows it to be fast in both software and hardware, keeping it flexible across multiple platforms. You can read about the individual steps that occur when encrypting data via AES here..
So why do you care about AES or how it works? You care because you can use it, in a simple iRule, to encrypt pieces of data being sent across an otherwise open network. In those cases that SSL just won't work, or is not an option, you can choose which pieces of information you need to encrypt, and package them up tidily, so long as the receiving system knows how to decrypt them.
There are three commands available to you via iRules that allow you to deal with AES encryption. Those commands are:
AES::key [128 | 192 | 256 ]
This command creates an AES key of the specified length for use with future encrypt/decrypt operations. The default size is 128 bits.AES::encrypt
This command uses the previously generated AES key to encrypt whatever data provided, allowing the data to be securely transmitted over an open network.AES::decrypt
This command decrypts data that has been previously AES encrypted by making use of the same AES key value to decipher the data's original format.
As you can see these commands are very straight-forward, allowing you to make use of them easily and get up to speed with their functionality quickly. This practice is especially useful when the BIG-IP is going to be the system inspecting the encrypted data anyway, such as in the Cooke Encryption example below:
when RULE_INIT { set ::aes_key [AES::key 128] set ::cookie "error" set ::cookie_encryption_debug } when HTTP_RESPONSE { if {[string length [HTTP::cookie value $::cookie]] > 0}{ if {$::cookie_encryption_debug}{log local0. \ "Response from app contained our cookie: [HTTP::cookie value $::cookie]"} HTTP::cookie value $::error_cookie [URI::encode [AES::encrypt $::aes_key [HTTP::cookie value $::cookie]]] if {$::cookie_encryption_debug}{log local0. \ "Encrypted error cookie to: [URI::encode [AES::encrypt $::aes_key [HTTP::cookie value $::cookie]]]"} } } when HTTP_REQUEST { if {[string length [HTTP::cookie value $::cookie]]}{ if {$::cookie_encryption_debug}{log local0. \ "Original error cookie value: [HTTP::cookie value $::cookie]"} if {not ([catch {URI::decode [HTTP::cookie value $::cookie]} cookie_uri_decoded])}{ if {$::cookie_encryption_debug}{log local0. "\$cookie_uri_decoded was set successfully"} if {not ([catch {AES::decrypt $::aes_key $cookie_uri_decoded} cookie_decrypted])}{ if {$::cookie_encryption_debug}{log local0. "\$cookie_decrypted: $cookie_decrypted"} } else { # URI decoded value couldn't be decrypted. } } else { # Cookie value couldn't be URI decoded } } else { # Cookie wasn't present in the request } }
You can go to the codeshare page for this rule to get the fully commented version and another description of how it works. Basically what's happening here is we're looking for a cookie. We take the original cookie, encrypt it, and send it on its way. On the next requests we check for the encrypted cookie and attempt to decrypt it to read the values. This ensures that no cookie tampering can occur mid-stream, and that the client is indeed using the exact cookie we issued, since it was encrypted the entire time.
Cookies aren't the only thing you can encrypt. You could choose to pick out just about any piece of data available via the inspection engine in your LTM (and that's a LOT!) and encrypt/decrypt it at will. Whether you have a back-end system that can be configured to expect certain pieces of data in an AES encrypted format, or you're just passing information that you don't want tampered with, and letting the BIG-IP handle all of the encryption/decryption, this simple, handy method can be used to selectively encrypt chunks of data, real-time.