Cryptography in Python
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. Python is currently one of the most popular programming languages used across a wide range of applications including Instagram and Spotify, so it’s important that developers understand 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.
The Challenges of Correctly Implementing 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.
In Python, multiple different cryptography libraries exist, and the one that a developer selects can impact the functionality and security of their code. A 2017 study of Python developers found that code using Keyczar was the most likely to be secure but least likely to be functional. In contrast, 80% of code implementing symmetric encryption with PyCrypto was functional, but only 10% of implementations were secure.
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.
Python’s dynamic typing and ability to reassign variable names to variables of different types can make correctly implementing cryptography more complex. Without the need to explicitly initialize a variable as a certain type, it is easier to get code to “work” even when it is incorrect.
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 the code is “right” or “wrong” depends solely on if it compiles without errors.
Without a usable system and clear documentation, the security of a developer’s code may depend on luck and which page they referenced on Stack Overflow. 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 Python, where cryptography is used, these little mistakes can be the difference between a secure system and a damaging 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, check out this demo.