Skip to main content

Insecure Use of Cryptography

Why is this important?โ€‹

Cryptography is hard. And when it is used in an application, it's usually to make sure user data is secure in transit and at rest. Cryptographic libraries are not always easy to use and can even contain insecurities. They often require the Developer to have a good understanding of the primitives available and expect the Developer to make the right choices. A great cryptographic library has minimal knobs and dials and uses the best cryptographic primitives by default thus freeing the Developer from having to understand the primitives and make the right decisions.

Check out this video for a high-level explanation:

Insecure Cryptographic Storage

Fixing Insecure Use of Cryptographyโ€‹

Option A: Use a strong hashing functionโ€‹

The algorithms SHA-1, MD2, MD4 and MD5 are not a recommended MessageDigest. The security of the MD5 hash function is severely compromised. A collision attack exists that can find collisions within seconds on a computer with a 2.6 GHz Pentium 4 processor. Further, there is also a chosen-prefix collision attack that can produce a collision for two inputs with specified prefixes within hours, using off-the-shelf computing hardware.

PBKDF2 with SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, or SHA-512/256 are acceptable for all hash function use-cases.

Detailed Instructionsโ€‹

  1. Go through the issues that GuardRails identified in the PR.

  2. Identify the code like:

    MessageDigest md5Digest = MessageDigest.getInstance("MD5");
    md5Digest.update(password.getBytes());
    byte[] hashValue = md5Digest.digest();
  3. And replace it with:

    // Java 8 or higher
    public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 4096, 256 * 8);
    SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    return f.generateSecret(spec).getEncoded();
    }
  4. Test it

  5. Ship it ๐Ÿšข and relax ๐ŸŒด

Referencesโ€‹

Option B: Use Strong Ciphersโ€‹

Cryptography is a complex topic and there are many ways it can be used insecurely.

The following issues are identified by GuardRails and can be easily avoided.

ECB Mode

An authentication cipher mode which provides better confidentiality of the encrypted data should be used instead of Electronic Code Book (ECB) mode, which does not provide good confidentiality. Specifically, ECB mode produces the same output for the same input each time. So, for example, if a user is sending a password, the encrypted value is the same each time. This allows an attacker to intercept and replay the data.

Padding Oracle

This specific mode of CBC with PKCS5Padding is susceptible to padding oracle attacks. An adversary could potentially decrypt the message if the system exposed the difference between plaintext with invalid padding or valid padding. The distinction between valid and invalid padding is usually revealed through distinct error messages being returned for each condition.

Cipher Integrity

The ciphertext produced is susceptible to alteration by an adversary. This means that the cipher provides no way to detect that the data has been tampered with. If the ciphertext can be controlled by an attacker, it could be altered without detection.

Detailed Instructionsโ€‹

  1. Go through the issues that GuardRails identified in the PR.

  2. Identify the code like this:

    // ECB Mode
    Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
    c.init(Cipher.ENCRYPT_MODE, k, iv);
    byte[] cipherText = c.doFinal(plainText);

    or:

    Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
    c.init(Cipher.ENCRYPT_MODE, k, iv);
    byte[] cipherText = c.doFinal(plainText);

    or:

    Cipher c = Cipher.getInstance("AES");
    c.init(Cipher.ENCRYPT_MODE, k, iv);
    byte[] cipherText = c.doFinal(plainText);
  3. And replace it with a proper cryptographic operation.

    Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
    c.init(Cipher.ENCRYPT_MODE, k, iv);
    byte[] cipherText = c.doFinal(plainText);
  4. Test it

  5. Ship it ๐Ÿšข and relax ๐ŸŒด

Referencesโ€‹

Option C: Use RSA with proper paddingโ€‹

Using the RSA algorithm without Optimal Asymmetric Encryption Padding (OAEP) weakens the encryption.

Detailed Instructionsโ€‹

  1. Go through the issues that GuardRails identified in the PR.

  2. Identify the code like this:

    Cipher.getInstance("RSA/NONE/NoPadding");
  3. And replace it with:

    Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding")
  4. Test it

  5. Ship it ๐Ÿšข and relax ๐ŸŒด

Referencesโ€‹

Option D: Use Strong Key Sizesโ€‹

Key Sizes based on algorithm:

  • The Blowfish cipher supports key sizes from 32 bits to 448 bits. A small key size makes the ciphertext vulnerable to brute force attacks. At least 128 bits of entropy should be used when generating the key if use of Blowfish is required.
  • For the RSA algorithm the use of 2048 bits and higher is recommended.
  • For the AES algorithm the use of 256 bits and higher is recommended.
  • For EllipticCurves (EC) the use of 256 bits and higher is recommended.

Detailed Instructionsโ€‹

  1. Go through the issues that GuardRails identified in the PR.

  2. Identify the code like this:

    // Vulnerable Blowfish example
    KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
    keyGen.init(64);

    and ensure the minimum acceptable key size of 128 is used:

    //  Blowfish example
    KeyGenerator keyGen = KeyGenerator.getInstance("Blowfish");
    keyGen.init(128);

    or alternatively, for RSA, identify code like this:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(512);

    and ensure the minimum acceptable key size of 2048 is used:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(2048);

    or alternatively, for AES, identify code like this:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("AES");
    keyGen.init(64);

    and ensure the minimum acceptable key size of 256 is used:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.init(256);

    or alternatively, for EC, identify code like this:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
    ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp224r1");
    keyGen.initialize(ecGenParameterSpec);

    and ensure the minimum acceptable key size of 256 is used:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
    ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1");
    keyGen.initialize(ecGenParameterSpec);
  3. Test it

  4. Ship it ๐Ÿšข and relax ๐ŸŒด

Referencesโ€‹

More information:โ€‹