How to avoid Cryptography errors
In the previous articles of the series on Cryptography errors in applications, we discussed how the use of Crypto in applications can go wrong and what type of attacks are possible against these errors. We have also discussed the case study of Linux.Encoder ransomware to better understand how crypto errors can be exploited. This article primarily focuses on some of the best practices to follow when using Cryptography in applications.
Avoid using outdated algorithms
The use of outdated algorithms such as MD5 and SHA1 for hashing secrets such as passwords is commonly seen. MD5 and SHA1 are considered broken and developers should avoid the use of these algorithms. If developers need to hash passwords, it is recommended to use a more secure algorithm such as bcrypt. This one-way function can prevent brute-force attacks because it is computationally slow, and it needs a lot of time to generate all the values to crack hashes using brute forcing. An important feature of this algorithm is the support for the work factor. As an example, the JBCrypt library for Java comes with gensalt() method, which takes an optional parameter (log_rounds) that determines the computational complexity of the hashing. If we pass 12 as an argument to it, 12 is the work factor. Using a work factor of 12, is fast enough to not be noticed and will still be strong in a few years. Using a high work factor makes it incredibly difficult to execute a brute-force attack, but can put unnecessary load on the system.
Do not roll your own crypto
Crypto algorithms need extensive testing to ensure that they are safe enough to use in production grade applications. When developers need to use a crypto algorithm to solve a specific security problem, it is always recommended to use standard cryptographic algorithms. This is because re-inventing the wheel by writing your own cryptographic algorithms requires intensive testing and can result in bugs. For instance, if you need to secure communications over the network, use TLS, which is a widely accepted scheme.
Avoid the use of ECB cipher mode
As discussed in the previous articles of this series, choosing ECB cipher mode with AES leads to insecure data encryption as data encrypted using ECB mode leaks information about the plain text. Instead, it is recommended to use a secure mode of operation, such as CBC mode or CTR mode. It should be noted that even the use of CBC mode can lead to security issues especially when the IV is predictable (even though IV is not a secret).
Make sure the random number are random enough
We have seen in the case of Linux.Encoder ransomware, seeding the pseudorandom number generators with predictable seed material like current time is insecure. Developers must ensure that non-predictable seed material is used to seed the pseudorandom generators. In addition to it, when encryption keys, IVs and nonces are generated using pseudorandom generators, avoid using functions like rand() and random(). For example, when writing Java code avoid using java.util.Random class, instead use java.security.SecureRandom class as the latter provides a cryptographically strong random number generator. The classes defined in Random are not cryptographically strong.
Avoid hardcoded crypto keys
Hardcoding of encryption keys used with symmetric key encryption algorithms such as AES is commonly seen in applications. Some choose to place them in environment variables or config files. Developers should keep in mind that these keys can be compromised if the application or the source code is compromised. While it is easy to say that it is an insecure practice to keep encryption keys in places like config files, this is a hard to avoid problem for developers and requires a better design solution. More thinking should be put in place on how to store the encryption keys during the design phase of the application. Android key store system is one example, where cryptographic keys can be stored if it is an Android Application. According to the documentation, “The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable. Moreover, it offers facilities to restrict when and how keys can be used, such as requiring user authentication for key use or restricting keys to be used only in certain cryptographic modes. See Security Features section for more information”. Similarly, appropriate storage vaults should be considered for securely storing encryption keys.
Cryptography for both application developers as well as security professionals is a hard to master subject. When dealing with Cryptography in applications, it is recommended to follow the industry standards and widely accepted best practices to avoid unforeseen errors in applications with respect to the use of Cryptography. This article has attempted to outline some of the best practices that can be followed in applications, but do not treat this as a checklist of what to do or what not to do.