• Aucun résultat trouvé

Modern encryption techniques have to account for the advances in computer speed and cost. Cheaper, faster computers allow the building of arrays of CPU power that calculate a billion plus passwords a second, which has killed MD5 and DES as encryp-tion methods. This attack capability will continue to improve.

Good encryption needs to overcome the problems of randomness, strength of cipher, and speed of brute force cracking. To overcome the first problem, cryptographically secure pseudo random number generators (CSPRNG) have been developed to ensure very high levels of randomness. If these are not used, then any encryption will already have a weak link. The second is cipher strength. Newer ciphers employ higher levels of complication. The last problem is addressed specifically by Blowfish which contains an algorithm which actually slows itself down against faster computers, giving it a great deal of future proof ability against faster and faster computers.

This chapter presents two methods of encrypting data, a two-way method for encrypt-ing and decryptencrypt-ing messages and a one-way hashencrypt-ing method for storencrypt-ing passwords.

Another technique used in the example is for hashing and then encrypting passwords.

This creates a defense in depth for password protection is several ways. The original clear text password can be deleted after hashing. The hash becomes the password and keeps the system from knowing or exposing the password. Most importantly, it does not limit user password choices. It allows the user to enter any characters, of any length. This will become increasingly more important to prevent password guessing. The hash func-tion does not care what the password is comprised of. The hash funcfunc-tion will take any untrusted data, even if it is garbage, and return 60 characters consisting of a–f, 0–9. This is then safely stored in a database table column 60 characters wide. Another benefit is that if the database is somehow compromised and the passwords are decrypted, only the hashes are exposed. A second decryption would need to take place to find the actual password.

The price to be paid for stronger encryption is additional setup to properly configure all the parameters. These examples walk you through each step, explaining each parameter.

These functions are reusable and once configured should not need to be configured again.

Using MCrypt for Two-Way Encryption

The following in an example of using mcrypt() correctly.

$key = "*768whatever_YOU_want";

$msg = "Hello Dr. Evil, Glad you can't read this. Groovy";

//Encryption Options

//MCRYPT_RIJNDAEL_256 MCRYPT_BLOWFISH //MCRYPT_TWOFISH MCRYPT_SERPENT

const CIPHER = MCRYPT_RIJNDAEL_256;

function encryptMSG($text, $key) {

$keySize = mcrypt_get_key_size(CIPHER, MCRYPT_MODE_CBC);

$ivSize = mcrypt_get_iv_size(CIPHER, MCRYPT_MODE_CBC);

$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);

$encrypted = mcrypt_encrypt(CIPHER, $key, $text,

MCRYPT_MODE_CBC, $iv);

$hmac = hash_hmac('sha256',

$iv. CIPHER. $encrypted,

$key);

$encryptedB64 = base64_encode($encrypted);

$ivB64 = base64_encode($iv);

$b64Output = $hmac. ':'. $ivB64. ':'. $encryptedB64;

return $b64Output;

}

function decryptMSG($data, $key) {

list($storedHMAC, $ivB64, $encryptedB64) = explode(':',$data);

$iv = base64_decode($ivB64);

$encrypted = base64_decode($encryptedB64);

$checkHMAC = hash_hmac('sha256',

$iv. CIPHER. $encrypted,

$key);

if ($checkHMAC ! = = $storedHMAC) { return false;

}

$decoded = mcrypt_decrypt(CIPHER, $key,

$encrypted, MCRYPT_MODE_CBC, $iv);

//trim only 0 padding, not spaces return rtrim($decoded, "\0");

}

$encryptedMsg = encryptMSG($msg, $key);

$decryptedMsg = decryptMSG($encryptedMsg, $key);

The first thing that encryptMsg() does is to configure the cipher key size, and IV size. IV stands for initialization vector, which is a strong random number that serves as a salt. There are several points that need to be understood just in these first three function calls. The first is the choice of cipher, in this case MCRYPT_RIJNDAEL_256. It is currently a very strong cipher that has not been broken. Second, is the CBC cipher block, MCRYPT_MODE_CBC. There are other blocks to choose. EBC is out-dated and does not use an IV. Use MCRYPT_MODE_CBC. mcrypt_create_iv() is a CSPRNG, and will generate a very strong number. It is strongly advised to use either this, or openssl_pseudo_random_bytes() for number generation. Do not use other methods.

MCRYPT_DEV_URANDOM is also an important parameter. It determines the source for randomness selection, and URANDOM is the highest source of randomness for Linux. It is also a non-blocking source of randomness, so access calls are quicker.

These functions and the parameters chosen will enable mcrypt() to obtain the high-est level of encryption.

$keySize = mcrypt_get_key_size(CIPHER, MCRYPT_MODE_CBC);

$ivSize = mcrypt_get_iv_size(CIPHER, MCRYPT_MODE_CBC);

$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);

Next is the call to mcrypt with the chosen parameters. Again, configuration is the key to strength.

$encrypted = mcrypt_encrypt(CIPHER, $key, $text,

MCRYPT_MODE_CBC, $iv);

Once the message is encrypted, an option is to make an authenticated message digest with hash_hmac(). This provides a message signature to ensure the integrity of the encrypted message later.

$hmac = hash_hmac('sha256',

$iv. CIPHER. $encrypted,

$key);

Another optional step is to base 64 encode the message for transport across  different media: sending via email, uploaded via HTML, store as file, etc. The individual parts are encoded, and then appended together via the colon character.

$encryptedB64 = base64_encode($encrypted);

$ivB64 = base64_encode($iv);

$b64Output = $hmac. ':'. $ivB64. ':'. $encryptedB64;

Once this string is assembled, this is the encrypted message that is stored.

The decryption process has a few additional steps. First, the string is exploded, based on the colon separator into a named, three-part list.

list($storedHMAC, $ivB64, $encryptedB64) = explode(':',$data);

Then each part is decoded, and message digest is checked for integrity.

$iv = base64_decode($ivB64);

$encrypted = base64_decode($encryptedB64);

$checkHMAC = hash_hmac('sha256',

$iv. CIPHER. $encrypted, $key);

If the digest check fails, it is a bad message, either from tampering or transmission damage.

if ($checkHMAC ! = = $storedHMAC) { return false;

}

Then the message is decrypted with the key.

$decoded = mcrypt_decrypt(CIPHER, $key,

$encrypted, MCRYPT_MODE_CBC, $iv);

Finally, trim() is used to remove any trailing null bytes. "\0" needs to be removed, not spaces.

return rtrim($decoded, "\0");

Encrypting Hashed Passwords with Blowfish

Hashing with Blowfish also has a few extra configuration steps that must be imple-mented correctly or the encryption will be undermined. These steps are as follows.

1. Create CSPRNG with openssl_random_pseudo_bytes(). 2. Turn CSPRNG binary blob into Base64 string.

3. Replace all plus signs (+) with periods (.). Plus signs are not allowed in the BCrypt salt.

4. Extract only the first 22 characters from previous Base64 encoded salt because the required salt length for BCrypt is 22.

5. Append $2y$12$ to previous salt and the password with it. $2Y designates the Blowfish cipher, 12 indicates the rounds used. This can be higher or lower.

Higher is stronger as it requires more time to complete the hash.

Each step for configuring and hashing with Blowfish is explained inline.

Encryption Constants

const PRE_BLOWFISH '$2y$' const PRE_SHA256 '$5$' const PRE_SHA512 '$6$'

const ROUNDS '12$', note, can be higher or lower. Lower is faster and weaker.

Higher is slower and stronger const BLOWFISH_SALT_SIZE 22

const CSPRNG_SIZE 32

//hashing a complex and dangerous password

$password = '<script>alert(1);</script>';

//hash is safe—no dangerous characters—a–f, 0–9

$passHash = hash('sha256', $password);

//after hashing password, delete it to remove access

$password = "";

//create CSPRNG byte blob

$bytes = openssl_random_pseudo_bytes(CSPRNG_SIZE);

//1 st: MUST turn this binary blob into a string by encoding it to base64

//2nd: MUST replace all plus signs (+) with periods (.) //BECAUSE plus signs are not allowed in the bcrypt salt.

$salt = strtr(base64_encode($bytes), '+', '.');

//3 rd: MUST extract only the first 22 characters from previous base64 encoded salt

//because the required salt length for bcrypt is 22

$salt = mb_substr($salt, 0, BLOWFISH_SALT_SIZE);

//4th: Append $2y$12$ to previous salt and the password with it //2y tells crypt to use BlowFish

//12 tells is how many rounds

$bcrypt = crypt($passHash, PRE_BLOWFISH. ROUNDS. $salt);

//this is the column size needed for DB Table //remains constant regardless of password length

$len = mb_strlen($bcrypt);

//SAVE $bcrypt hash to database or file //to test password,

//retrieve $bcrypt hash from database //and call crypt with password and hash

//crypt is smart enough to know that the salt is included in hash //compare this password hash to the stored hash

//if they match, the password is correct, user logs in //testing reentered complex password from user

$reEnteredPassword = '<script>alert(1);</script>';

$passHash = hash('sha256', $reEnteredPassword);

//have retrieved $bcrypt from storage, and compare with $passHash if (crypt($passHash, $bcrypt) = = $bcrypt) {

//password is correct

echo "Password Hash Works!";

} else {

echo "Bad Password!";

}

16 5

12