Cryptography is hard!
- Use only standard algorithms (e.g. AES)
- Use well known libraries (e.g. OpenSSL, libsodium)
- Ask to review your code by a security expert
- Be updated, attacks are around the corner
Cryptography in PHP
Mcrypt, deprecated since PHP 7.1
- OpenSSL extension, public key and symmetric encryption
- Sodium extension, from PHP 7.2+
OpenSSL
- Ciphers: RSA, AES, CAMELLIA, DES, RC2, RC4, check with openssl_get_cipher_methods()
- Block modes: CBC, CFB, CTR, ECB, XTS
- Padding: PKCS#1, No padding, SSLV23, PKCS1_OAEP
- Authenticated encryption: GCM, CCM (PHP 7.1+)
Sodium
- Authenticated encryption
- Stream encryption/file encryption
- Public-key cryptography
- Hashing/Password hashing
- Key derivation/Key exchange
Authenticated Encryption
- Encryption only provides confidentiality
- An attacker can easily alter the encrypted message
- Padding Oracle Attacks can be applied to retrieve the plaintext without the key!
Authenticated Encryption
PHP 7.1 provides AEAD support for OpenSSL: Galois/Counter Mode (GCM),
Counter CBC-MAC (CCM)
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 = "")
Example: encrypt
function encrypt(string $data, string $key): string
{
$iv = random_bytes(16); // size for aes-256-gcm
$ciphertext = openssl_encrypt(
$data,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
if (false === $ciphertext) {
throw new Exception ('Error on encrypt');
}
return $iv . $tag . $ciphertext;
}
Example: decrypt
function decrypt(string $ciphertext, string $key): string
{
$plaintext = openssl_decrypt(
mb_substr($ciphertext, 32, null, '8bit'),
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
mb_substr($ciphertext, 0, 16, '8bit'),
mb_substr($ciphertext, 16, 16, '8bit')
);
if (false === $plaintext) {
throw new Exception('Error on decrypt');
}
return $plaintext;
}
Encryption keys
- If possible use random bytes, e.g. random_bytes()
- PBKDF2 (Password-Based Key Derivation Function 2) is a key derivation function RFC 2898
hash_pbkdf2($algo, $password, $salt, $iterations, $length=0, $raw=false)
- Suggestion: use SHA-256 as $algo
- In 2017 a reasonable $iterations is around 80k
HMAC
- Hash-based message authentication code (RFC 2140)
where H is hash function, K is key, K' derivated key, opad is outer padding (0x5c), ipad is inner padding (0x36), ⊕ is XOR, and || is concatenation
- In PHP:
hash_hmac ($algo, $data, $key, $raw_output = false)
hash_hmac_file ($algo, $filename, $key, $raw_output = false)
- Suggestion: use SHA-256 as $algo
Public key encryption
&
Digital signature
Hybrid cryptosystem
- Public key algorithms are too slow to encrypt a full text message
- We need a different approach (Hybrid cryptosystem):
- generate a random session key;
- encrypt the session key using a public key algorithm;
- encrypt the message with a symmetric cipher using the session key;
- send the ciphertext and the encrypted session key;
Public and private key
// 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);
Hybrid encryption
$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
Digital signature
- How to provide authentication and non-repudiation?
- A digital signature is a mathematical scheme for demonstrating the authenticity of a digital message or document
- Commonly used for software distribution, financial transactions, and in other cases where it is important to detect forgery or tampering
Signature with OpenSSL
// 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';
Protect a user password
- Don't encrypt the password, use a password hashing
- Never use a simple hash (e.g. MD5, SHA1), even + salt
- Use bcrypt or Argon2
- password_hash($password, PASSWORD_BCRYPT)
- password_hash($password, PASSWORD_ARGON2I), from PHP 7.2
- The default PASSWORD_DEFAULT is bcrypt, at the moment
Articles and books
- Serge Vaudenay, Security Flaws Induced by CBC Padding Applications to SSL, IPSEC, WTLS..., EUROCRYPT 2002
- J. Rizzo, T. Duong, Practical Padding Oracle Attacks, USENIX WOOT 2010
- M. Bellare, C. Namprempre, Authenticated Encryption: Relations among notions and analysis of the generic composition paradigm, ASIACRYPT 2000
- D. Brumley, D. Boneh, Remote Timing Attacks are Pratical, USENIX Security Symposium, August 2003
- N. Ferguson, B. Schneier, T. Kohno, Cryptography Engineering, John Wiley & Sons, 2010
- Joshua Davies, Implementing SSL / TLS Using Cryptography and PKI, John Wiley & Sons, 2011
- A.J. Menezes, P.C. van Oorschot, S.A. Vanstone, Handbook of Applied Cryptography, CRC Press, 2001
- Ross J. Anderson, Security Engineering, John Wiley & Sons, 2008
Blog and websites
- Rob Heaton, The Padding Oracle Attack - why crypto is terrifying, 29 Jul 2013
- Dennis Fisher, Padding Oracle’ Crypto Attack Affects Millions of ASP.NET Apps, 13 Set 2010
- J. Rizzo, T. Duong, Practical Padding Oracle Attacks (slides), Black Hat Europe, 2010
- Brian Holyfield, Automated Padding Oracle Attacks with PadBuster, 14 Set 2010
- Moxie Marlinspike, The Cryptographic Doom Principle, 13 Dec 2011
- Matthew Green, How to choose an Authenticated Encryption mode, Hopkins University, 19 May 2012
- Dan Boneh, Cryptography course Stanford University, Coursera
- Thomas & Erin Ptacek, Applied Cryptography Engineering, 22 July 2013
- Thomas Hühn, Myths about /dev/urandom, 20 March 2014
- Enrico Zimuel, Protecting passwords with Argon2 in PHP 7.2, 17 August 2017
- Enrico Zimuel, Authenticated Encryption in PHP 7.1, 31 October 2016
- Pádraic Brady, Nanosecond Scale Remote Timing Attacks On PHP Applications: Time To Take Them Seriously?, 20 Oct 2010
- Paragon Initiative, Using Libsodium in PHP Projects
Thanks!
Contact me: enrico [at] zend.com
Follow me: @ezimuel