diff --git a/Document/0x04g-Testing-Cryptography.md b/Document/0x04g-Testing-Cryptography.md index 713cab9401..29f99b5986 100644 --- a/Document/0x04g-Testing-Cryptography.md +++ b/Document/0x04g-Testing-Cryptography.md @@ -118,20 +118,38 @@ 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: +Different Key Derivation Functions (KDFs) are suitable for various tasks, most commonly known for the following two: -- 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. +- Key Derivation: the generation of keys from secret passwords or passphrases. +- Password storage: To prevent attackers from reading stolen passwords after a data breach, passwords should be stored as hashes generated by a resource-intensive Key Derivation Function (KDF). -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"). +KDFs derive bytes suitable for cryptographic operations from passwords or other data sources using a pseudorandom function (PRF). When discussing KDFs in the context of mobile applications, we are usually referring to cryptographic key derivation rather than password hashing and storage. Therefore, this chapter focuses primarily on KDFs in the context of cryptographic key derivation, not 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). +In short, we recommend: + +- When using a KDF for cryptographic operations, always select **a recommended and approved KDF** and implement it according to the latest standards and the software provider's documentation. +- Only use KDFs based on **secure hash functions** - that is, hashes for which no practical pre-image or length-extension attacks are known, and where directly attacking the KDF is computationally infeasible. +- Avoid combining **user-supplied input** (such as passwords) directly with HMAC Key Derivation Function (HKDF), as this can make **pre-image attacks by password crackers** significantly easier. + +Choose a KDF that uses 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 of brute-force attacks, including rainbow-table attacks. Finally, with computing power becoming faster and cheaper, the technique can be reconfigured to increase the workload without requiring a complete 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 over which is most effective, both are stronger than using salts with hash functions and incur very little computational overhead. Note that using these functions can affect performance, so they require special consideration. However, their configurability provides finer control over CPU and memory usage, allowing them to be adjusted to suit the environment's needs. When CPU and memory performance are a challenge, consider increasing the desired bit length of the derived key rather than increasing the iteration count (e.g., using HMAC-SHA512 instead of HMAC-SHA256). This might make the KDF more susceptible to brute-force attacks, but it should be acceptable as long as you stay within the recommended guidelines. +Unfortunately, "brute-force" attacks are quite likely to succeed when users select passwords and pins with little or no entropy, which is required for cryptographic keys. Therefore, ensure that passwords and pins aren't passed directly to an HKDF. The input key 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 KDF 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")). When the input is user-controlled, a password hashing algorithm like Argon2, scrypt, bcrypt, or PBKDF2 should be used as a KDF 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 you choose an appropriate iteration count that provides sufficient computational effort, making 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 implement algorithms recognized by the [Password Hashing Competition (PHC)](https://password-hashing.net/ "PHC"), such as [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 recommendations on iteration count when using KDFs using Argon2, scrypt, bcrypt, or PBKDF2. + +Further read: + +- [NIST SP 800-132: Recommendation for Password-Based Key Derivation](https://csrc.nist.gov/pubs/sp/800/132/final) +- [Wikipedia, 2025.02.21](https://en.wikipedia.org/wiki/Key_derivation_function "Key derivation function") +- [KDF1](https://en.wikipedia.org/wiki/IEEE_P1363) +- [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) +- [HKDF](https://en.wikipedia.org/wiki/HKDF) ### 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 (PRNGs) 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 depending on the algorithm used. Cryptographically secure PRNGs (CSPRNGs) 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 them 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