AES: running with (cryptographic) scissors
Developers can misuse cryptography when they don't fully understand the options. Let's look at how this applies to AES.
The confidentiality of data at rest and in transit is typically protected by encryption. The Advanced Encryption Standard (AES) is a very widely used encryption algorithm; it is one of the current standards approved by NIST (the other, Triple DES, is being deprecated).
Elliptic curve cryptographic algorithms such as Curve25519, Salsa20 and Poly1305 have gained a lot of ground recently, but AES still retains numerous advantages – in addition to its NIST standard status, it has significant software and hardware support.
Furthermore, even though it has been in use since 2001, no practical attacks against the algorithm have been identified – the only successful attacks to date (side channel attacks) are against flawed implementations. So it should be safe to use, right?
However, the security of the algorithm is only half of the story. In order to encrypt with AES, like all block ciphers, the developer must use an API that selects between multiple key sizes, modes of operation and padding modes, as well as an initialization vector (IV) which is a required random value added during the encryption process. For example, take a look at the following VULNERABLE code fragments:
// C# (System.Security.Cryptography) var a = new AesManaged(); a.Mode = CipherMode.CBC; a.Padding = PaddingMode.Zeros; a.IV = iv; // Java (javax.crypto.Cipher) var cipher = Cipher.getInstance("AES"); // C (OpenSSL) EVP_CipherInit_ex(&ctx, EVP_AES_128_cbc(), NULL, key, iv, 1) ;
These all fall prey to one (or more) of three stumbling blocks:
- Using the wrong parameters for AES: Some of the modes of operation are either inherently insecure or introduce potential vulnerabilities. For instance, the Java code can default to the insecure ECB mode.
- Choosing the wrong IV (initialization vector): It may be tempting to use an all-zero IV, reuse an IV, or use user-provided input as the IV – but all of these enable cryptographic attacks.
- Improper use of padding: The developer can choose the wrong type of padding or skip the verification of padding.
Let’s look at the modes of operation first. Choosing ECB makes the encryption inherently weak, choosing CTR makes the encryption malleable (meaning the attacker can modify certain bits in the plaintext by manipulating the ciphertext), OFB and CFB can weaken the algorithm if the implementation feeds back less than a full block for each iteration, and using CBC opens the door for several weaknesses. Some developers may not be aware of the meaning behind these abbreviations at all!
As for initialization vectors and padding: reusing IVs (or allowing the attacker to control the IV) can severely weaken the security of all modes, especially OFB and CFB. If CBC is used, padding abuse also enables attacks such as BEAST or padding oracle attacks like POODLE. Note that the latter single-handedly caused all major implementations to stop supporting the SSLv3 protocol!
Symmetric encryption with AES
Many developers may not be aware of these pitfalls, but – especially for DevOps – dealing with cryptographic tools and solutions is an absolute necessity. And the worst part about all this? Making any of the mistakes above will not be apparent at all when implementing and testing the functionality – the program will work completely fine. But it may contain a cryptographic vulnerability, ready for exploitation…
Of course, there are secure ways of using these APIs; in particular, the use of authenticated encryption with associated data (AEAD) that adds integrity protection to the process, thus eliminating these attack possibilities. For AES, using AES-GCM-SIV is a good solution against the typical issues mentioned above. Thankfully, APIs are getting better at not making developers make mistakes, for example, in C#, AesManaged doesn’t allow the selection of CFB or OFB modes.
No blockbusters on the AES horizon
Nowadays crypto experts tend to recommend use of ‘foolproof’ elliptic curve-based crypto APIs based on NaCl such as libsodium. These always use secure parameters internally, and the algorithms do not allow the possibility of a developer making the mistakes listed above. While it is a perfectly fine solution to switch over to such APIs in theory, in practice many systems will have to interoperate with existing components using AES or may have operational reasons for not switching.
Finally, it should be noted that quantum computing – held up as a bogeyman for much of modern cryptography, though it is unlikely to become a practical threat in the near future – is expected to be very effective against many elliptic-curve algorithms. On the other hand, AES-256 in particular will remain resilient, though of course, ‘quantum-resistant’ variants of elliptic curve algorithms are already being developed as well.
All in all, AES may not be the ‘best’ cryptographic algorithm – and definitely not the most foolproof – but it is a solid choice both for performance and backward compatibility. It even has ‘quantum resistance’, just in case!
The key to using AES securely is understanding its options and using them correctly. Use AES-GCM-SIV with a 256-bit key (canonical name: AEAD_AES_256_GCM_SIV) if available, AES-GCM if not – and in the latter case, make sure to check your program is not possibly reusing IVs! If AES-GCM is not available, AES-CTR combined with HMAC after the encryption (to protect against malleability) can be an acceptable compromise.
We cover the secure use of AES and other cryptography for developers in depth in many of our courses, such as Desktop application security in Java. This information is indispensable for any developers who have to use cryptographic functions in their work – or even just to understand how to securely use a cryptographic API.