by Enrico Zimuel / @ezimuel
Senior Software Engineer
Zend Technologies a Rogue Wave Company
5th March 2016 - Minneapolis (MN)
|
hash_pbkdf2($algo, $password, $salt, $iterations, $length=0, $raw=false)
hash_hmac ($algo, $data, $key, $raw = false)
function AES_encrypt($text, $key) {
$ivsize = openssl_cipher_iv_length('aes-256-cbc');
$iv = openssl_random_pseudo_bytes($ivsize);
// Encryption key generated by PBKDF2 (since PHP 5.5)
$keys = hash_pbkdf2('sha256', $key, $iv, 80000, 64, true);
$encKey = substr($keys, 0, 32); // 256 bit encryption key
$hmacKey = substr($keys, 32); // 256 bit hmac key
$ciphertext = openssl_encrypt(
$text,
'aes-256-cbc',
$encKey,
OPENSSL_RAW_DATA,
$iv
);
$hmac = hash_hmac('sha256', $iv . $ciphertext, $hmacKey);
return $hmac . $iv . $ciphertext;
}
function AES_decrypt($text, $key) {
$hmac = substr($text, 0, 64);
$ivsize = openssl_cipher_iv_length('aes-256-cbc');
$iv = substr($text, 64, $ivsize);
$ciphertext = substr($text, $ivsize + 64);
// Generate the encryption and hmac keys
$keys = hash_pbkdf2('sha256', $key, $iv, 80000, 64, true);
$encKey = substr($keys, 0, 32); // 256 bit encryption key
$hmacNew = hash_hmac('sha256', $iv . $ciphertext, substr($keys, 32));
if (!hash_equals($hmac, $hmacNew)) { // to prevent timing attacks
return false;
}
return openssl_decrypt(
$ciphertext,
'aes-256-cbc',
$encKey,
OPENSSL_RAW_DATA,
$iv
);
}
Note: hash_equals() requires PHP5.6+
A timing attack is a side channel attack in which the attacker attempts to compromise a cryptosystem by analyzing the time taken to execute cryptographic algorithms
From Wikipedia
Use hash_equals() to prevent timing attacks (PHP 5.6+)
// Generate public and private keys
$keys = openssl_pkey_new(array(
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
// Store the private key in a file
$passphrase = 'test';
openssl_pkey_export_to_file($keys, 'private.key', $passphrase);
// Store the public key in a file
$details = openssl_pkey_get_details($keys);
$publicKey = $details['key'];
file_put_contents('public.key', $publicKey);
$message = 'This is the secret message';
$passphrase = 'test'; // to read the private key
// Encryption
$key = openssl_random_pseudo_bytes(32);
openssl_public_encrypt($key, $encryptedKey, $publicKey);
$ciphertext = AES_encrypt($message, $key);
file_put_contents('encrypted.msg', $encryptedKey . $ciphertext);
// Decryption
$ciphertext = file_get_contents('encrypted.msg');
$encKey = substr($ciphertext, 0, 512);
$ciphertext = substr($ciphertext, 512);
$privateKey = openssl_pkey_get_private('file:///path/to/private.key',
$passphrase);
openssl_private_decrypt($encKey, $key, $privateKey);
$result = AES_decrypt($ciphertext, $key); // equal to $message
// Compute the signature
$passphrase = 'test';
$privateKey = openssl_pkey_get_private('file:///path/to/private.key',
$passphrase);
$data = file_get_contents('/path/to/file_to_sign');
openssl_sign($data, $signature, $privateKey, "sha256");
printf("Signature : %s\n", base64_encode($signature));
// Verify the signature
$publicKey = openssl_pkey_get_public('file:///path/to/public.key');
$result = openssl_verify($data, $signature, $publicKey, "sha256");
echo $result === 1 ? 'Signature verified' : 'Signature not valid';
zend-crypt is the cryptographic component of Zend Framework
use Zend\Crypt\BlockCipher;
$blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
$blockCipher->setKey('encryption key');
$ciphertext = $blockCipher->encrypt('this is a secret message');
use Zend\Crypt\PublicKey\RsaOptions;
use Zend\Crypt\PublicKey\Rsa;
// Generate public and private key
$rsaOptions = new RsaOptions(array( 'pass_phrase' => 'test' ));
$rsaOptions->generateKeys(array( 'private_key_bits' => 2048 ));
file_put_contents('private_key.pem', $rsaOptions->getPrivateKey());
file_put_contents('public_key.pub', $rsaOptions->getPublicKey());
// Sign and verify
$rsa = Rsa::factory(array(
'private_key' => 'path/to/private_key',
'pass_phrase' => 'passphrase of the private key'
));
$file = file_get_contents('path/file/to/sign');
$sign = $rsa->sign($file, $rsa->getOptions()->getPrivateKey());
$verify = $rsa->verify($file, $sign, $rsa->getOptions()->getPublicKey());
Rate this talk at joind.in/talk/0cf0f
Contact me: enrico [at] zend.com
Follow me: @ezimuel
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.