# Encryption Vulnerabilities

Encryption powers the modern internet, allowing secure storage of data and transmission of secrets across a network in such a way they cannot be inspected or tampered with by a third party. It is important that you use *strong encryption* algorithms when securing data in this way, or an attacker will be able to backwards engineer confidential information if they possess enough computing power.

## Encryption Algorithms

Encryption algorithms are designed to encode the contents of a string or binary object in such away that an attacker who does not possession the decryption key will not be able to decipher the contents. *Cryptography* – the study of encryption algorithms – is a complex field, and new encryption algorithms are invented by mathematicians frequently.

As computing power gets cheaper, it becomes easier for an attacker to use brute-force to decrypt the contents of encrypted data. For this reason, it’s important to use modern encryption algorithms in your code, so your secrets remain safe.

Consider the following Python function, that uses a weak encryption algorithm (MD5) to encrypt passwords. Since the algorithm does not strongly encrypt the data – it is computationally cheap to calculate the MD5 value – an attacker can quickly calculate the MD5 values of commonly used passwords, compare them to the encrypted value, and backwards engineer the passwords:

“`python
import hashlibdef encrypt_password(password):
return hashlib.md5(password.encode(‘utf-8’)).hexdigest()
“`

Here are some algorithms to avoid, since they provide weak encryption:

* `MD5`
* `SHA-1`
* `DES/CBC/PKCS5Padding`
* `DES/CBC/PKCS5PADDING`
* `DES/ECB/PKCS5Padding`
* `AES/ECB/NoPadding`

## Encoding is Not Encryption

Encodings like Base64 are a common method of transforming binary data to text before transmission. Anybody can decode Base64 text, however – do not depend on encoding methods to hide secrets from attackers!

## Don’t Invent Your Own Encryption Algorithms

Avoid the temptation to roll your own encryption algorithm. Cryptography is hard, and designing your own cryptographic schemes when well-studied encryption algorithms are freely available is asking for trouble.

## Symmetric vs Asymmetric Encryption Algorithms

An encryption algorithm that uses the same key to encrypt and decrypt data is called a *symmetric algorithm*. An *asymmetric algorithm* uses different keys to encrypt and decrypt data, and has the advantage that the encryption key can be made public, allowing anyone to securely encrypt data in a way that only the holder of the decryption key can read. For this reason, asymmetric algorithms are commonly called **public-key** algorithms. If you wish to securely retrieve data from a third party, always choose a public key algorithm.

## Weak Hashes

A *hash* is a type of encryption algorithm that produces an output of fixed length regardless of the input. Hash algorithms are often used to store passwords securely in a database, or generate digital signatures which prove data has not been tampered with. It is important that you use *strong hash* algorithms when securing data in this way – and include an element of randomness called a *salt* – or an attacker will be able to backwards engineer confidential information if they possess enough computing power. This often entails choosing a *one-way hash* algorithm that is
computationally infeasible to reverse.

Consider the following function that uses a strong, one-way hash called `BCrypt` to encodes a passwords when it is set, and repeats the calculation when a user attempts to reauthenticate:

“`python
import [email protected](‘/signup’, methods=(‘POST’,))
def do_signup():
username = request.form[‘username’]
password = request.form[‘password’]# The user is signing up – calculated their password hash and save it to the database.
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password, salt)

save_credentials(username, hashed)

return redirect(‘/login’)

@app.route(‘/login’, methods=(‘POST’,))
def do_login():
username = request.form[‘username’]
password = request.form[‘password’]

# The user is logging back in – recalculate their password hash and
# compare it with the saved value.
user = get_user(username)
hashed = user.hashed_password if user else ”

# Calculate the password hash regardless of whether the username exists,
# so the attacker cannot use timing attacks to detect which users exist
# in the database.
if bcrypt.checkpw(password, hashed):
session[‘user’] = user
return redirect(‘/timeline’)

return render_template(‘login.html’, error=’Invalid username or password’)
“`

Since the password is strongly encrypted with a one-way hash, and generated with a salt, an attacker who manages to steal the contents of your database will still not be able to backwards engineer the credentials for your users.

## Weak Randomness

Encryption algorithms rely on random number generators to avoid being predictable. If your encryption code uses a weak source of randomness – that is, if an attacker can narrow down the range of numbers the random number generator will be outputting in a given timeframe – a malicious user has a much smaller set of combinations to attempt when trying to decrypt your sensitive data.

In Python, the easiest way to generate a random number is the `random` module, which will generate random numbers on demand. However, these random numbers are **not** cryptographically secure – since they rely on the Mersenne Twister algorithm, which is completely deterministic.

Instead, you should use the `secrets` module if you require a source of randomness when encrypting data. Use the following functions:

* The `secrets.token_hex(…)` if you want a random string of a given length.
* The `secrets.randbelow(0, n)` if you want a random number in a range.
* The `secrets.token_bytes(…)` if you need bytes to to generate cryptographic keys.

## CWEs

* [CWE-326](https://cwe.mitre.org/data/definitions/326.html)
* [CWE-328](https://cwe.mitre.org/data/definitions/328.html)
* [CWE-759](https://cwe.mitre.org/data/definitions/759.html)
* [CWE-330](https://cwe.mitre.org/data/definitions/330.html)

About ShiftLeft

ShiftLeft empowers developers and AppSec teams to dramatically reduce risk by quickly finding and fixing the vulnerabilities most likely to reach their applications and ignoring reported vulnerabilities that pose little risk. Industry-leading accuracy allows developers to focus on security fixes that matter and improve code velocity while enabling AppSec engineers to shift security left.

A unified code security platform, ShiftLeft CORE scans for attack context across custom code, APIs, OSS, containers, internal microservices, and first-party business logic by combining results of the company’s and Intelligent Software Composition Analysis (SCA). Using its unique graph database that combines code attributes and analyzes actual attack paths based on real application architecture, ShiftLeft then provides detailed guidance on risk remediation within existing development workflows and tooling. Teams that use ShiftLeft ship more secure code, faster. Backed by SYN Ventures, Bain Capital Ventures, Blackstone, Mayfield, Thomvest Ventures, and SineWave Ventures, ShiftLeft is based in Santa Clara, California. For information, visit: www.shiftleft.io.

Share

See for yourself – run a scan on your code right now