Skip to content
Open
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions Document/0x04g-Testing-Cryptography.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,42 @@ Secret keys must be stored in secure device storage whenever symmetric cryptogra

### Improper Key Derivation Functions

Cryptographic algorithms (such as symmetric encryption or some MACs) expect a secret input of a given size. For example, AES uses a key of exactly 16 bytes. A native implementation might use the user-supplied password directly as an input key. Using a user-supplied password as an input key has the following problems:
When discussing key derivation functions (KDFs) in the context of mobile applications, we are usually referring to cryptographic key derivation rather than password storage. This chapter focuses primarily on KDF in the context of cryptographic key derivation, rather than password storage. For general advice on password storage, please refer to the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).
KDFs derive bytes suitable for cryptographic operations from passwords or other data sources using a pseudorandom function (PRF).

- If the password is smaller than the key, the full key space isn't used. The remaining space is padded (spaces are sometimes used for padding).
- A user-supplied password will realistically consist mostly of displayable and pronounceable characters. Therefore, only some of the possible 256 ASCII characters are used and entropy is decreased by approximately a factor of four.
Different KDFs are suitable for different tasks such as:

Ensure that passwords aren't directly passed into an encryption function. Instead, the user-supplied password should be passed into a KDF to create a cryptographic key. Choose an appropriate iteration count when using password derivation functions. For example, [NIST recommends an iteration count of at least 10,000 for PBKDF2](https://pages.nist.gov/800-63-3/sp800-63b.html#sec5 "NIST Special Publication 800-63B") and [for critical keys where user-perceived performance is not critical at least 10,000,000](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf "NIST Special Publication 800-132"). For critical keys, it is recommended to consider implementation of algorithms recognized by [Password Hashing Competition (PHC)](https://password-hashing.net/ "PHC") like [Argon2](https://github.com/p-h-c/phc-winner-argon2 "Argon2").
- Cryptographic key derivation:
- Together with a non-secret parameter to derive one or more keys from a common secret value. Also known as "key diversification"
- As components of multiparty key-agreement protocols (e.g: [KDF1](https://en.wikipedia.org/wiki/IEEE_P1363)).
- To derive keys from secret passwords or passphrases.
- To derive keys of different length from the ones provided (e.g: [PBKDF2HMAC](https://en.wikipedia.org/wiki/PBKDF2) or [HKDF](https://en.wikipedia.org/wiki/HKDF)).
- [Key stretching](https://en.wikipedia.org/wiki/Key_stretching) and [key strengthening](https://en.wikipedia.org/wiki/Key_derivation_function#Key_stretching_and_key_strengthening).

- Password storage:
- In order to ensure attacker's can't use a stolen password even in the event of a data breach, passwords are stored as hashes computed through a computationally intensive KDF. The ideal password storage's KDF should be demanding on both computational and memory resources.

Source: ([Wikipedia, 2025.02.21](https://en.wikipedia.org/wiki/Key_derivation_function "Key derivation function"))

When using a KDF for cryptographic operations always ensure to use a recommended and approved KDF properly according to the latest recommendations and the software provider's documentation. E.g Only using a key derivation functions that is constructed from hashes against which no non-trivial pre-image or length-extension attacks are known and where attacking the key derivation function directly is infeasible. Using user-supplied input together with HKDF will make it easy for password crackers to execute a preimage attack.

Choose a KDF that use an adaptive hash function that can be configured to change the amount of computational effort needed to compute the hash, such as the number of iterations ("stretching") or the amount of memory required. Some hash functions perform salting automatically. These functions can significantly increase the overhead for a brute force attack compared to intentionally-fast functions. For example, rainbow table attacks can become infeasible due to the high computing overhead. Finally, since computing power gets faster and cheaper over time, the technique can be reconfigured to increase the workload without forcing an entire replacement of the algorithm in use.

Some hash functions that have one or more of these desired properties include [scrypt](https://www.tarsnap.com/scrypt.html), and [PBKDF2](https://www.rfc-editor.org/rfc/rfc2898). While there is active debate about which of these is the most effective, they are all stronger than using salts with hash functions with very little computing overhead.

Note that using these functions can have an impact on performance, so they require special consideration to avoid denial-of-service attacks. However, their configurability provides finer control over how much CPU and memory is used, so it could be adjusted to suit the environment's needs. In the case where CPU and memory performance is a challenge try adjusting desired bit-length of the derived key instead of increasing the iteration account (e.g using HMAC-SHA512 instead of HMAC-SHA256). This might make the KDF more susceptible by brute-force attacks, but should be acceptable as long as you keep yourself within recommended guidelines.

Unfortunately, "brute-force" attacks are quite liable to succeed where users selects passwords and pins with none or with too little entropy than what is required for cryptographic keys. Therefore, ensure that passwords and pins aren't directly passed into a HKDF. The key that is input to a key-derivation function is called a key-derivation key (KDK). A KDK **shall** be a cryptographic key, but the KDK used as an input to a recommended key-derivation functions can, for example, be generated by an approved cryptographic random bit generator, e.g. by a deterministic random bit generator (see: [NIST 800-108, rev 1](https://csrc.nist.gov/pubs/sp/800/108/r1/upd1/final "NIST: Recommendation for Key Derivation Using Pseudorandom Functions")) ([NIST, 2022](https://csrc.nist.gov/pubs/sp/800/108/r1/upd1/final "NIST: Recommendation for Key Derivation Using Pseudorandom Functions")).
If the input is user-controlled, a password hashing algorithm like Argon2, scrypt, bcrypt, or PBKDF2 is used as a key derivation function to provide sufficient computational effort. Do not use an HKDF or any other integrity-based hashing algorithm like MD5, SHA-1, SHA-2, or SHA-3 for this purpose. HKDFs, like SHA-3, aren't designed for low-entropy inputs. In the context of key derivation, these should only be used for key stretching or key diversification of randomly generated keys.
When using a password hashing algorithm as a KDF, also ensure to choose an appropriate iteration count that can provide sufficient computational efforts. Meaning that they make password or secret cracking attacks infeasible or expensive. For example, [NIST recommends an iteration count of at least 10,000 for PBKDF2](https://pages.nist.gov/800-63-3/sp800-63b.html#sec5 "NIST Special Publication 800-63B") and [for critical keys where user-perceived performance is not critical at least 10,000,000](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf "NIST Special Publication 800-132"). For critical keys, it is recommended to implementation algorithms recognized by [Password Hashing Competition (PHC)](https://password-hashing.net/ "PHC") like [Argon2](https://github.com/p-h-c/phc-winner-argon2 "Argon2"). Also see ["OWASP Password Storage Cheat Sheet"](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#introduction "OWASP Cheat Sheet Series: Password Storage Cheat Sheet") for recommendation on iteration count when using key derivation functions using Argon2, scrypt, bcrypt or PBKDF2.

### Improper Random Number Generation

A common weakness in mobile apps is the improper use of random number generators. Regular Pseudo-Random Number Generators (PRNGs), while sufficient for general use, are not designed for cryptographic purposes. When used to generate keys, tokens, or other security-critical values, they can make systems vulnerable to prediction and attack.

The root issue is that deterministic devices cannot produce true randomness. PRNGs simulate randomness using algorithms, but without sufficient entropy and algorithmic strength, the output can be predictable. For example, UUIDs may appear random but do not provide enough entropy for secure use.
It is fundamentally impossible to produce truly random numbers on any deterministic device. Pseudo-random number generators (PRNG) compensate for this by producing a stream of pseudo-random numbers - a stream of numbers that appear as if they were randomly generated. The quality of the generated numbers varies with the type of algorithm used. Cryptographically secure PRNGs (CSPRNG) generate random numbers that pass statistical randomness tests, and are resilient against prediction attacks (e.g. it is statistically infeasible to predict the next number produced).

The correct approach is to use a [**Cryptographically Secure Pseudo-Random Number Generator (CSPRNG)**](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator). CSPRNGs are designed to resist statistical analysis and prediction, making them suitable for generating non-guessable values. All security-sensitive values must be generated using a CSPRNG with at least 128 bits of entropy.
PRNGs can be vulnerable when developers use a regular PRNG for cryptographic purposes, instead of a cryptographically secure PRNG (["Cryptographically secure pseudorandom number generator", 2025.01.31](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator "Wikipedia: Cryptographically secure pseudorandom number generator")). All random numbers and strings which are intended to be non-guessable must be generated using a cryptographically secure pseudo-random number generator (CSPRNG) and have at least 128 bits of entropy. Note that UUIDs do not meet this condition.

### Improper Hashing

Expand Down