by Enrico Zimuel / @ezimuel
Senior PHP Engineer - Zend Technologies
Software Engineer since 1996. Senior PHP Engineer at Zend Technologies, since 2008. I did research in computer science at the Informatics Institute of Amsterdam University. Open source contributor of Apigility and Zend Framework. Author of articles and books about web programming and applied cryptography. Co-founder of PUG Torino (Italy).
P'2 = I2 ⊕ C'1 ⇒ I2 = P'2 ⊕ C'1
We know C'1[i] = x ⇒ we know I2[i]
I2 is the same as in the real ciphertext ⇒ P2[i] = C1[i] ⊕ I2[i]
function AES_encrypt($text, $key) {
// Padding PKCS#7
$text = PKCS7_pad($text, 16);
// Random IV
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
// Encryption key generated by PBKDF2 (since PHP 5.5)
$keys = hash_pbkdf2('sha256', $key, $iv, 10000, 64);
$encKey = substr($keys, 0, 32); // 256 bit encryption key
$hmacKey = substr($keys, 32); // 256 bit hmac key
// Encryption
$ciphertext = mcrypt_encrypt('rijndael-128', $encKey, $text, 'cbc', $iv);
// $ciphertext = openssl_encrypt($text, 'AES-256-CBC', $encKey, OPENSSL_NO_PADDING, $iv);
$hmac = hash_hmac('sha256', $iv . $ciphertext, $hmacKey);
return $hmac . $iv . $ciphertext;
}
function PKCS7_pad($text, $blockSize)
{
$pad = $blockSize - (strlen($text) % $blockSize);
return $text . str_repeat(chr($pad), $pad);
}
function PKCS7_unpad($text)
{
$end = substr($text, -1);
$last = ord($end);
$len = strlen($text) - $last;
if (substr($text, $len) == str_repeat($end, $last)) {
return substr($text, 0, $len);
}
return false;
}
function AES_decrypt($text, $key) {
$hmac = substr($text, 0, 64); // 64 bytes HMAC size
$iv = substr($text, 64, 16); // 16 bytes IV size
$text = substr($text, 80);
// Generate the encryption and hmac keys
$keys = hash_pbkdf2('sha256', $key, $iv, 10000, 64);
$encKey = substr($keys, 0, 32); // 256 bit encryption key
$hmacNew = hash_hmac('sha256', $iv . $text, substr($keys, 32));
if (!compareStrings($hmac, $hmacNew)) { // to prevent timing attacks
return false;
}
// Decryption
$result = mcrypt_decrypt('rijndael-128', $encKey, $text, 'cbc', $iv);
// $result = openssl_decrypt($text, 'AES-256-CBC', $encKey, OPENSSL_NO_PADDING, $iv);
return PKCS7_unpad($result);
}
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
function compareStrings($expected, $actual)
{
$expected = (string) $expected;
$actual = (string) $actual;
$lenExpected = strlen($expected);
$lenActual = strlen($actual);
$len = min($lenExpected, $lenActual);
$result = 0;
for ($i = 0; $i < $len; $i++) {
$result |= ord($expected[$i]) ^ ord($actual[$i]);
}
$result |= $lenExpected ^ $lenActual;
return ($result === 0);
}
Public key algorithms are too slow to encrypt a full text message
We need a different approach (Hybrid cryptosystem):
// 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 = mcrypt_create_iv(32, MCRYPT_DEV_URANDOM);
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 of ZF2 offers crypto features with a simple API:
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());
The slides of this talk are available here: http://www.zimuel.it/slides/dpc2014
The code presented in this talk is on github:
https://github.com/ezimuel/dpc2014
Rate this talk at:
https://joind.in/10877
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.