2
\$\begingroup\$

I want to do simple encryption using PHP 5.5. By “simple” I mean I want to use native PHP functions. I have created this code that works, can it be improved? It's to encrypt/decrypt strings and binary files that are to be stored in a database and accessed via a website. Assume that it is done over SSL and that the password isn't hard-coded or stored anywhere on the web server.

Here's what I have (and it works). Is this secure? All the examples I found do not use PHP 5.5's hash_pbkdf2 function. I wanted a simple example that uses this.

Are there any downsides to using MCRYPT_MODE_CFB? Are 5000 iterations enough for PBKDF2 in this context?

// Check hash_pbkdf2 exists as it's not available < 5.5
if(function_exists('hash_pbkdf2') === false) {

    // A fallback could be implemented here
    exit('hash_pbkdf2() does not exist');

}

// Settings
$stringToEncrypt                = 'This was encrypted';        // The plain text string to encrypt; binary files should be base64 encoded
$encryptionPassword             = 'MyP@$$w0rd';                // The password; the only data that should be kept private
$pbkdf2Iterations               = 5000;                        // More iterations = more secure, 1000 should be used as a minimum
$pbkdf2HashAlgo                 = 'sha256';                    // 256-bit key size
$cipher                         = MCRYPT_RIJNDAEL_128;         // Note: 128 refers to block size, not key size; MCRYPT_RIJNDAEL_128 is similar to 256-bit AES
$blockMode                      = MCRYPT_MODE_CFB;            // CFB mode requires a random IV and does not require padding
$ivSource                       = MCRYPT_DEV_URANDOM;        // URANDOM is faster than RANDOM in some environments

// Create key using PBKDF2 hash
$ivSize                         = mcrypt_get_iv_size($cipher, $blockMode);
$pbkdf2Salt                     = mcrypt_create_iv($ivSize, $ivSource);
$key                            = hash_pbkdf2($pbkdf2HashAlgo, $encryptionPassword, $pbkdf2Salt, $pbkdf2Iterations);

// Pack the key into a binary hex string
$key                            = pack('H*', $key);

// Create random IV
$iv                             = mcrypt_create_iv($ivSize, $ivSource);

// Encrypt the data
$encryptedData                  = mcrypt_encrypt($cipher, $key, $stringToEncrypt, $blockMode, $iv);

// Prepend the IV as it's needed for decryption
$encryptedData                  = $iv . $encryptedData;

// Base64 encode it
$encryptedData                  = base64_encode($encryptedData);

// Decrypt
$decryptedData                  = base64_decode($encryptedData);

// Get the IV
$ivDecrypted                    = substr($decryptedData, 0, $ivSize); // Don't need to use mb_substr as it's hexadecimal

// Get the encrypted data on its own
$decryptedData                  = substr($decryptedData, $ivSize);

// Decrypted data
$decryptedData                  = mcrypt_decrypt($cipher, $key, $decryptedData, $blockMode, $ivDecrypted);

// Output for testing
echo "<p>stringToEncrypt: $stringToEncrypt</p>";
echo "<p>encryptionPassword: $encryptionPassword</p>";
echo "<p>pbkdf2Iterations: $pbkdf2Iterations</p>";
echo "<p>pbkdf2HashAlgo: $pbkdf2HashAlgo</p>";
echo "<p>ivSize: $ivSize</p>";
echo "<p>iv: $iv</p>";
echo "<p>pbkdf2Salt: $pbkdf2Salt</p>";
echo "<p>key: $key</p>";
echo "<p>encryptedData: $encryptedData</p>";
echo "<p>ivDecrypted: $ivDecrypted</p>";
echo "<p>decryptedData: $decryptedData</p>";
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.