by Enrico Zimuel / @ezimuel
Senior Software Engineer
Zend Technologies a Rogue Wave Company
21th October 2016 - ZendCon - Las Vegas
|
hash_pbkdf2($algo, $password, $salt, $iterations, $length=0, $raw=false)
hash_hmac ($algo, $data, $key, $raw_output = false)
hash_hmac_file ($algo, $filename, $key, $raw_output = false)
function encrypt(string $text, string $key): string {
$iv = random_bytes(16); // iv size for aes-256-cbc
$keys = hash_pbkdf2('sha256', $key, $iv, 80000, 64, true);
$encKey = mb_substr($keys, 0, 32, '8bit');
$hmacKey = mb_substr($keys, 32, null, '8bit');
$ciphertext = openssl_encrypt($text, 'aes-256-cbc', $encKey,
OPENSSL_RAW_DATA, $iv
);
$hmac = hash_hmac('sha256', $iv . $ciphertext, $hmacKey);
return $hmac . $iv . $ciphertext;
}
function decrypt(string $text, string $key): string {
$hmac = mb_substr($text, 0, 64, '8bit');
$iv = mb_substr($text, 64, 16, '8bit');
$ciphertext = mb_substr($text, 80, null, '8bit');
$keys = hash_pbkdf2('sha256', $key, $iv, 80000, 64, true);
$encKey = mb_substr($keys, 0, 32, '8bit');
$hmacKey = mb_substr($keys, 32, null, '8bit');
$hmacNow = hash_hmac('sha256', $iv . $ciphertext, $hmacKey);
if (! hash_equals($hmac, $hmacNow)) {
throw new Exception('Authentication error!');
}
return openssl_decrypt($ciphertext, 'aes-256-cbc', $encKey,
OPENSSL_RAW_DATA, $iv
);
}
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
To compare two strings in PHP use
hash_equals($known, $user) to prevent timing attacks
PHP 7.1 provides AEAD support for OpenSSL:
openssl_encrypt ($data, $method, $key, $options = 0, $iv = "",
&$tag = null, $aad = "", $tag_len = 16)
openssl_decrypt ($data, $method, $key, $options = 0, $iv = "",
$tag = null, $aad = "")
$data = 'Hello World!';
$key = random_bytes(32); // 256 bit
// GCM and CCM
$modes = ['aes-256-gcm', 'aes-256-ccm'];
foreach ($modes as $mode) {
$iv = random_bytes(openssl_cipher_iv_length($mode));
$ciphertext = openssl_encrypt($data, $mode, $key,
OPENSSL_RAW_DATA, $iv, $tag
);
printf("%s, tag size: %d bytes\n", $mode, mb_strlen($tag, '8bit'));
$text = openssl_decrypt($ciphertext, $mode, $key,
OPENSSL_RAW_DATA, $iv, $tag
);
printf("Decrypt %s\n\n", $text === $data ? 'Ok' : 'Failed');
}
// 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);
$msg = 'This is the secret message';
// Encryption
$key = random_bytes(32);
openssl_public_encrypt($key, $encKey, $publicKey);
$ciphertext = encrypt($msg, $key);
file_put_contents('encrypted.msg', $encKey . $ciphertext);
// Decryption
$ciphertext = file_get_contents('encrypted.msg');
$encKey = mb_substr($ciphertext, 0, 512, '8bit');
$ciphertext = mb_substr($ciphertext, 512, null, '8bit');
$privateKey = openssl_pkey_get_private(
'file:///path/to/private.key',
$passphrase // to access the private key
);
openssl_private_decrypt($encKey, $key, $privateKey);
$result = decrypt($ciphertext, $key); // $result === $msg
// Compute the signature
$priKey = openssl_pkey_get_private(
'file:///path/to/private.key',
$passphrase
);
$data = file_get_contents('/path/to/file_to_sign');
openssl_sign($data, $sign, $priKey, "sha256");
printf("Signature : %s\n", base64_encode($sign));
// Verify the signature
$pubKey = openssl_pkey_get_public(
'file:///path/to/public.key'
);
$result = openssl_verify($data, $sign, $pubKey, "sha256");
echo $result === 1 ? 'Signature ok' : 'Signature not valid';
Rate this talk at https://joind.in/talk/90174
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.