Cryptographic functionality is essential to a massive number of applications. As data protection regulations mandate how certain types of data should be protected, developers are increasingly required to build cryptography into their code. Java is currently one of the most popular programming languages used across a wide range of applications including Minecraft and Hadoop, so it’s important that developers know what to consider when implementing cryptography correctly.
However, cryptography can be complicated, and most developers are not secretly cryptographers on the side. Requiring developers to jump through hoops and blindly make crucial decisions is not a good or safe way to implement core security functionality.
Why it's so Difficult to Correctly Implement Cryptography
Cryptography can go wrong in a number of different ways. By making mistakes or trying to take shortcuts, a developer can easily undermine the security of the application they are writing and the data that it uses.
But let us assume a developer is not trying to work around the rules or develop a custom protocol. How hard is it to implement cryptographic functionality and what can go wrong? Implementing a “simple” function using cryptography requires working through the following process.
1. Identify the Relevant Library to Use
“Rolling your own crypto” is never a good idea due to the large number of ways in which it can go wrong. It is always better to select an existing library rather than attempting to write the cryptographic code yourself.
However, selecting a library can be a challenge for a developer with limited knowledge of cryptography. Important considerations include:
- Applicability: Does the library have the required functionality?
- Code Quality: Is the code well-designed and implemented or do exploitable issues exist?
- Level of Support: Is the library actively supported or may unpatched vulnerabilities exist?
- Documentation Clarity: Does the documentation provide the detail required to use the library correctly?
- Optimization: Has the code been optimized to run as quickly and efficiently as possible?
Many programming languages have built-in cryptography libraries, and a number of third-party libraries exist as well. Without in-depth knowledge of cryptography and these libraries, it may be difficult to determine if the selected library is the best choice for a developer’s use case.
Solving this challenge can be especially difficult in Java due to how Java’s cryptographic providers work. Unless a developer specifies the implementation of a particular function that they want to use, Java will automatically select the first provider that offers that functionality. This means that a developer may not know the implementation used by their code or how secure or optimized it is.
2. Correctly Set Up the Identified Library
After selecting a library, it may be necessary to configure it. Some libraries may be designed to be standalone or to automatically install any required dependencies. Other options may have functionality enabled or disabled based upon whether or not the required dependencies are installed.
Depending on the quality of the documentation and the installer used, it may be difficult to determine whether or not a cryptographic library is correctly installed and configured. This has the potential to impact the security and usability of the code relying upon the library.
3. Select an Appropriate Encryption Algorithm
Encryption algorithms can be classified in a number of different ways, and each category has its advantages and disadvantages. For example, asymmetric encryption is ideal for setting up a key exchange but is inefficient for bulk encryption, while symmetric encryption is much more efficient but requires a pre-shared key.
Selecting which encryption cipher is best suited for a particular use case can be confusing. There are several ciphers other than Advanced Encryption Standard (AES), including Salsa20, 3DES and Blowfish but AES is the NIST standard, so it’s commonly chosen.
4. Properly Configure the Selected Algorithm
Once an algorithm has been selected, the next step is to properly configure it. Many encryption algorithms and use cases have certain requirements and additional choices, such as:
- Initialization Vectors: An initialization vector should be either a random or at least unique - but publicly known - value included in the encryption operation.
- Block Cipher Modes of Operation: AES provides several different cipher modes, including ECB, CBC, CFG, OFB, and CTR. Some of the modes have different weaknesses and are susceptible to different attacks. Making a wrong choice could be the difference between being on the front pages of the news or not.
- Key Size: Along with the cipher, the IV, and the mode, the developer usually needs to select the encryption key size. AES commonly supports keys of 128, 256 and even 192 bit keys. Choosing the largest key is not always the best choice depending upon use case.
- Salts: Salting is an essential part of password security. Implementing salting improperly can result in password hashes which are vulnerable to dictionary attacks. This can mean the difference between a catastrophic data breach and a non-event.
These are only some of the decisions that a developer may need to make when implementing cryptography for a particular application. Whether or not the right decisions are made can depend heavily on the developer’s knowledge and the quality of the library’s documentation; however, research has determined that poor documentation is a common complaint and leading challenge faced by Java developers.
5. Correctly Interact with the Cryptography API
When working with cryptography, many developers take an “error driven” approach to working with the API. With this approach, whether or not the code is “right” or “wrong” depends solely on if it compiles without errors.
Java cryptography libraries are known to have unclear error messages that do not help developers to solve issues in their code. Without a usable system and clear documentation, the security of a developer’s code may depend on luck and which page they reference on StackOverflow. Implementing cryptography correctly requires an interface that makes it easy for the developer to do the right thing.
Simplifying Cryptography for Developers
Cryptography can be complicated, and even little mistakes can have significant impacts. For many of the applications built in a language such as Java, where cryptography is used, these little mistakes can be the difference between a secure system and an embarrassing data breach.
Ubiq is designed to make using cryptography simple for developers by eliminating many of the decisions and challenges that they face when implementing cryptographic functionality. By handling the complex functionality behind the scenes and only exposing a simple API, Ubiq eliminates the opportunity to make these costly mistakes. To find out more about how to quickly build data encryption into any application, watch our short demo video.