This rule is deprecated; use {rule:php:S4426}, {rule:php:S5542}, {rule:php:S5547} instead.

Encrypting data is security-sensitive. It has led in the past to the following vulnerabilities:

- CVE-2017-7902
- CVE-2006-1378
- CVE-2003-1376

Proper encryption requires both the encryption algorithm and the key to be strong. Obviously the private key needs to remain secret and be renewed regularly. However these are not the only means to defeat or weaken an encryption.

This rule flags function calls that initiate encryption/decryption.

## Ask Yourself Whether

- the private key might not be random, strong enough or the same key is reused for a long long time.
- the private key might be compromised. It can happen when it is stored in an unsafe place or when it was transferred in an unsafe manner.
- the key exchange is made without properly authenticating the receiver.
- the encryption algorithm is not strong enough for the level of protection required. Note that encryption algorithms strength decreases as time passes.
- the chosen encryption library is deemed unsafe.
- a nonce is used, and the same value is reused multiple times, or the nonce is not random.
- the RSA algorithm is used, and it does not incorporate an Optimal Asymmetric Encryption Padding (OAEP), which might weaken the encryption.
- the CBC (Cypher Block Chaining) algorithm is used for encryption, and it’s IV (Initialization Vector) is not generated using a secure random algorithm, or it is reused.
- the Advanced Encryption Standard (AES) encryption algorithm is used with an unsecure mode. See the recommended practices for more information.

You are at risk if you answered yes to any of those questions.

## Recommended Secure Coding Practices

- Generate encryption keys using secure random algorithms.
- When generating cryptographic keys (or key pairs), it is important to use a key length that provides enough entropy against brute-force attacks. For the Blowfish algorithm the key should be at least 128 bits long, while for the RSA algorithm it should be at least 2048 bits long.
- Regenerate the keys regularly.
- Always store the keys in a safe location and transfer them only over safe channels.
- If there is an exchange of cryptographic keys, check first the identity of the receiver.
- Only use strong encryption algorithms. Check regularly that the algorithm is still deemed secure. It is also imperative that they are implemented correctly. Use only encryption libraries which are deemed secure. Do not define your own encryption algorithms as they will most probably have flaws.
- When a nonce is used, generate it randomly every time.
- When using the RSA algorithm, incorporate an Optimal Asymmetric Encryption Padding (OAEP).
- When CBC is used for encryption, the IV must be random and unpredictable. Otherwise it exposes the encrypted value to crypto-analysis attacks like "Chosen-Plaintext Attacks". Thus a secure random algorithm should be used. An IV value should be associated to one and only one encryption cycle, because the IV’s purpose is to ensure that the same plaintext encrypted twice will yield two different ciphertexts.
- The Advanced Encryption Standard (AES) encryption algorithm can be used with various modes. Galois/Counter Mode (GCM) with no padding should be preferred to the following combinations which are not secured:
  - Electronic Codebook (ECB) mode: Under a given key, any given plaintext block always gets encrypted to the same ciphertext block. Thus, it does not hide data patterns well. In some senses, it doesn’t provide serious message confidentiality, and it is not recommended for use in cryptographic protocols at all.
  - Cipher Block Chaining (CBC) with PKCS#5 padding (or PKCS#7) is susceptible to padding oracle attacks.

## Sensitive Code Example

Builtin functions

    function myEncrypt($cipher, $key, $data, $mode, $iv, $options, $padding, $infile, $outfile, $recipcerts, $headers, $nonce, $ad, $pub_key_ids, $env_keys)
    {
        mcrypt_ecb ($cipher, $key, $data, $mode); // Sensitive
        mcrypt_cfb($cipher, $key, $data, $mode, $iv); // Sensitive
        mcrypt_cbc($cipher, $key, $data, $mode, $iv); // Sensitive
        mcrypt_encrypt($cipher, $key, $data, $mode); // Sensitive

        openssl_encrypt($data, $cipher, $key, $options, $iv); // Sensitive
        openssl_public_encrypt($data, $crypted, $key, $padding); // Sensitive
        openssl_pkcs7_encrypt($infile, $outfile, $recipcerts, $headers); // Sensitive
        openssl_seal($data, $sealed_data, $env_keys, $pub_key_ids); // Sensitive

        sodium_crypto_aead_aes256gcm_encrypt ($data, $ad, $nonce, $key); // Sensitive
        sodium_crypto_aead_chacha20poly1305_encrypt ($data, $ad, $nonce, $key); // Sensitive
        sodium_crypto_aead_chacha20poly1305_ietf_encrypt ($data, $ad, $nonce, $key); // Sensitive
        sodium_crypto_aead_xchacha20poly1305_ietf_encrypt ($data, $ad, $nonce, $key); // Sensitive
        sodium_crypto_box_seal ($data, $key); // Sensitive
        sodium_crypto_box ($data, $nonce, $key); // Sensitive
        sodium_crypto_secretbox ($data, $nonce, $key); // Sensitive
        sodium_crypto_stream_xor ($data, $nonce, $key); // Sensitive
    }

CakePHP

    use Cake\Utility\Security;

    function myCakeEncrypt($key, $data, $engine)
    {
        Security::encrypt($data, $key); // Sensitive

        // Do not use custom made engines and remember that Mcrypt is deprecated.
        Security::engine($engine); // Sensitive. Setting the encryption engine.
    }

CodeIgniter

    class EncryptionController extends CI_Controller
    {
        public function __construct()
        {
            parent::__construct();
            $this->load->library('encryption');
        }

        public function index()
        {
            $this->encryption->create_key(16); // Sensitive. Review the key length.
            $this->encryption->initialize( // Sensitive.
                array(
                    'cipher' => 'aes-256',
                    'mode' => 'ctr',
                    'key' => 'the key',
                )
            );
            $this->encryption->encrypt("mysecretdata"); // Sensitive.
        }
    }

CraftCMS version 3

    use Craft;

    // This is similar to Yii as it used by CraftCMS
    function craftEncrypt($data, $key, $password) {
        Craft::$app->security->encryptByKey($data, $key); // Sensitive
        Craft::$app->getSecurity()->encryptByKey($data, $key); // Sensitive
        Craft::$app->security->encryptByPassword($data, $password); // Sensitive
        Craft::$app->getSecurity()->encryptByPassword($data, $password); // Sensitive
    }

Drupal 7 - Encrypt module

    function drupalEncrypt() {
        $encrypted_text = encrypt('some string to encrypt'); // Sensitive
    }

Joomla

    use Joomla\Crypt\CipherInterface;

    abstract class MyCipher implements CipherInterface // Sensitive. Implementing custom cipher class
    {}

    function joomlaEncrypt() {
        new Joomla\Crypt\Cipher_Sodium(); // Sensitive
        new Joomla\Crypt\Cipher_Simple(); // Sensitive
        new Joomla\Crypt\Cipher_Rijndael256(); // Sensitive
        new Joomla\Crypt\Cipher_Crypto(); // Sensitive
        new Joomla\Crypt\Cipher_Blowfish(); // Sensitive
        new Joomla\Crypt\Cipher_3DES(); // Sensitive
    }
    }

Laravel

    use Illuminate\Support\Facades\Crypt;

    function myLaravelEncrypt($data)
    {
        Crypt::encryptString($data); // Sensitive
        Crypt::encrypt($data); // Sensitive
        // encrypt using the Laravel "encrypt" helper
        encrypt($data); // Sensitive
    }

PHP-Encryption library

    use Defuse\Crypto\Crypto;
    use Defuse\Crypto\File;

    function mypPhpEncryption($data, $key, $password, $inputFilename, $outputFilename, $inputHandle, $outputHandle) {
        Crypto::encrypt($data, $key); // Sensitive
        Crypto::encryptWithPassword($data, $password); // Sensitive
        File::encryptFile($inputFilename, $outputFilename, $key); // Sensitive
        File::encryptFileWithPassword($inputFilename, $outputFilename, $password); // Sensitive
        File::encryptResource($inputHandle, $outputHandle, $key); // Sensitive
        File::encryptResourceWithPassword($inputHandle, $outputHandle, $password); // Sensitive
    }

PhpSecLib

    function myphpseclib($mode) {
        new phpseclib\Crypt\RSA(); // Sensitive. Note: RSA can also be used for signing data.
        new phpseclib\Crypt\AES(); // Sensitive
        new phpseclib\Crypt\Rijndael(); // Sensitive
        new phpseclib\Crypt\Twofish(); // Sensitive
        new phpseclib\Crypt\Blowfish(); // Sensitive
        new phpseclib\Crypt\RC4(); // Sensitive
        new phpseclib\Crypt\RC2(); // Sensitive
        new phpseclib\Crypt\TripleDES(); // Sensitive
        new phpseclib\Crypt\DES(); // Sensitive

        new phpseclib\Crypt\AES($mode); // Sensitive
        new phpseclib\Crypt\Rijndael($mode); // Sensitive
        new phpseclib\Crypt\TripleDES($mode); // Sensitive
        new phpseclib\Crypt\DES($mode); // Sensitive
    }

Sodium Compat library

    function mySodiumCompatEncrypt($data, $ad, $nonce, $key) {
        ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt($data, $ad, $nonce, $key); // Sensitive
        ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt($data, $ad, $nonce, $key); // Sensitive
        ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt($data, $ad, $nonce, $key); // Sensitive

        ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt($data, $ad, $nonce, $key); // Sensitive

        ParagonIE_Sodium_Compat::crypto_box($data, $nonce, $key); // Sensitive
        ParagonIE_Sodium_Compat::crypto_secretbox($data, $nonce, $key); // Sensitive
        ParagonIE_Sodium_Compat::crypto_box_seal($data, $key); // Sensitive
        ParagonIE_Sodium_Compat::crypto_secretbox_xchacha20poly1305($data, $nonce, $key); // Sensitive
    }

Yii version 2

    use Yii;

    // Similar to CraftCMS as it uses Yii
    function YiiEncrypt($data, $key, $password) {
        Yii::$app->security->encryptByKey($data, $key); // Sensitive
        Yii::$app->getSecurity()->encryptByKey($data, $key); // Sensitive
        Yii::$app->security->encryptByPassword($data, $password); // Sensitive
        Yii::$app->getSecurity()->encryptByPassword($data, $password); // Sensitive
    }

Zend

    use Zend\Crypt\FileCipher;
    use Zend\Crypt\PublicKey\DiffieHellman;
    use Zend\Crypt\PublicKey\Rsa;
    use Zend\Crypt\Hybrid;
    use Zend\Crypt\BlockCipher;

    function myZendEncrypt($key, $data, $prime, $options, $generator, $lib)
    {
        new FileCipher; // Sensitive. This is used to encrypt files

        new DiffieHellman($prime, $generator, $key); // Sensitive

        $rsa = Rsa::factory([ // Sensitive
            'public_key'    => 'public_key.pub',
            'private_key'   => 'private_key.pem',
            'pass_phrase'   => 'mypassphrase',
            'binary_output' => false,
        ]);
        $rsa->encrypt($data); // No issue raised here. The configuration of the Rsa object is the line to review.

        $hybrid = new Hybrid(); // Sensitive

        BlockCipher::factory($lib, $options); // Sensitive
    }

## See

- OWASP - Top 10 2017 Category A3 - Sensitive Data Exposure
- OWASP - Top 10 2017 Category A6 - Security Misconfiguration
- CWE - CWE-321 - Use of Hard-coded Cryptographic Key
- CWE - CWE-322 - Key Exchange without Entity Authentication
- CWE - CWE-323 - Reusing a Nonce, Key Pair in Encryption
- CWE - CWE-324 - Use of a Key Past its Expiration Date
- CWE - CWE-325 - Missing Required Cryptographic Step
- CWE - CWE-326 - Inadequate Encryption Strength
- CWE - CWE-327 - Use of a Broken or Risky Cryptographic Algorithm