Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Crypto for everyone - libsodium in PHP 7.2

Crypto for everyone - libsodium in PHP 7.2

PHP 7.2 includes the libsodium cryptography library by default in the base language - the first time that a popular language has shipped with strong, modern crypto support as standard. Everyone can build secure apps without the risks of rolling your own crypto or using outdated libraries. So what's in libsodium? What kind of things can you do? What risks remain? You'll get a tour of cryptographic functions, how they have been done in the past, and how to switch to libsodium to give you a security edge.

I gave this talk at Laracon EU 2018 in Amsterdam.

B4814d6790e91f01c77cac9d25db12b6?s=128

Marcus Bointon

August 31, 2018
Tweet

Transcript

  1. CRYPTO FOR EVERYONE Libsodium in PHP 7.2 Marcus Bointon Synchromedia

    Limited, Smartmessages.net, Radically Open Security, PHPMailer @SynchroM
  2. WHAT’S CRYPTO? Cryptography Crypto: secret Graphy: writing Writing messages that

    can only be read by the intended recipient Confidentiality Proving that you wrote a message Authenticity Proving that a message has not been altered Integrity Marcus Bointon @SynchroM
  3. CRYPTOGRAPHIC FUNCTIONS 0 keys: hashes, PRNGs, key derivation MD5, SHA1,

    SHA2, BLAKE2, bcrypt, PBKDF2, argon2 1 key: message authentication codes (MACs), secret key encryption HMAC*, Poly1305, RC4, Blowfish, 3DES, AES, ChaCha20 2 keys: key exchange, public key encryption, digital signatures Diffie-Hellman, RSA, DSA, ECDSA, EdDSA, PGP Related non-crypto: encoding, compression, math operations base64, charsets, gzip, bin2hex, hash_equals Marcus Bointon @SynchroM
  4. CORE & EXTENSION CRYPTO IN PHP mhash: PHP 4 mcrypt:

    PHP 4.0.2 - 7.1 openssl: PHP 4.0.4 pecl-gnupg: PHP 4.3 hash: PHP 5.1.2 pecl-scrypt: PHP 5.2 password_hash: PHP 5.5 hash_equals: PHP 5.6 CSPRNG: PHP 7.0 pecl-libsodium: PHP 5.6 sodium: PHP 7.2 Marcus Bointon @SynchroM
  5. WHICH EXTENSION TO USE? Marcus Bointon @SynchroM MCRYPT MCRYPT SODIUM

    SODIUM OPENSSL OPENSSL SODIUM OPENSSL MCRYPT
  6. PHP CRYPTO LIBRARIES pear crypt_* phpseclib/phpseclib defuse/php-encryption paragonie/sodium_compat paragonie/halite phpseclib/mcrypt_compat

    zendframework/zend-crypt Marcus Bointon @SynchroM
  7. WHAT’S LIBSODIUM? NaCl - “Salt” Networking and cryptography library, 2008

    nacl.cr.yp.to High-performance, legacy-free, heavily scrutinised open-source C library Resistant to many forms of attack & side channels Libsodium Fork of NaCl, also open-source, libsodium.org Cross-platform, multiple language bindings, audited code Available in PHP via pecl since 2014, standard in PHP 7.2 Marcus Bointon @SynchroM
  8. SALTY PEOPLE NaCl Daniel J. Bernstein (“DJB”), Tanja Lange, Peter

    Schwabe University of Eindhoven in the Netherlands Numerous other contributors Marcus Bointon @SynchroM Libsodium Frank Denis @jedisct1 Developer & photographer in Paris pure-ftpd Scott Arciszewski @CiPHPerCoder, @ParagonIE Documentation & wisdom on https://paragonie.com
  9. WHAT’S A SIDE-CHANNEL ATTACK? Any attack based on information gained

    from the physical implementation of a system, rather than weaknesses in the implemented algorithm itself Timing, thermal, RF emissions, light, sound, power Examples: Spectre & meltdown, password hash timing, Ethernet switch lights Marcus Bointon @SynchroM
  10. EXAMPLE: SIDE CHANNEL VULNERABILITY //Old, insecure $pw = md5($_POST['password']); $r

    = mysqli_query($db, "SELECT id, name FROM users WHERE email = ‘user@example.com’ AND password = '$pw'"); if (count($r) <= 0) die('Go away!'); Marcus Bointon @SynchroM //Safe $r = mysqli_query($db, "SELECT id, name, password FROM users WHERE email = 'user@example.com'"); $f = mysqli_fetch_assoc($r); if (!password_verify($_POST['password'], $f['password'])) die('Go away!’); //or, using sodium if (!sodium_crypto_pwhash_str_verify($_POST['password'], $f['password'])) die('Go away!’);
  11. HASHING Hash algorithms are designed for different purposes Small ones

    for binning/distributing: FNV Fast ones for checksumming, verification: MD[245], SHA[123], BLAKE2 Slow ones for password hashing: bcrypt, scrypt, PBKDF2, Argon2 Reference implementations – SHA-256 vs SHA-512/256 Argon2i, Argon2d, Argon2id When writing new apps, use the strongest available; To upgrade, rehash on login Marcus Bointon @SynchroM
  12. HASHING WITH SODIUM crc32(), hash() ➜ sodium_crypto_shorthash() Short hashes are

    often used for non-crypto purposes md5(), sha1(), hash() ➜ sodium_crypto_generichash() Uses BLAKE2b As strong as SHA-3, faster than MD5 password_hash() ➜ sodium_crypto_pwhash_str() Gives you access to Argon2id, everywhere PHP 7.2 runs Marcus Bointon @SynchroM
  13. MESSAGE AUTHENTICATION CODES Like a hash, but uses a key

    as well as the input data Used to authenticate messages Most common: HMAC Hash-based message authentication code Adds a key to an existing hash algorithm HMAC-MD5, HMAC-SHA256, HMAC- SHA512-256, HMAC-SHA512/256 Poly1305 Marcus Bointon @SynchroM
  14. MACS IN SODIUM hash_hmac ➜ sodium_crypto_auth $mac = substr(hash_hmac('sha512', $message,

    $key), 0, 64) $mac = bin2hex(sodium_crypto_auth($message, $key)) hash_equals ➜ sodium_crypto_auth_verify hash_equals($mac, substr(hash_hmac('sha512', $message, $key), 0, 64)); sodium_crypto_auth_verify($mac, $message, $key); Marcus Bointon @SynchroM
  15. WHAT’S A NONCE? A Number used Once Random, or pseudo-random

    number, often containing a timestamp Used in many crypto scenarios HTTP digest auth Preventing replay attacks What bitcoin miners are looking for Initialisation vectors (“IV”s) Secret and public key encryption Never re-use with the same key Marcus Bointon @SynchroM
  16. SECRET-KEY ENCRYPTION Encrypt and decrypt with the same key Symmetric

    cipher Does not guarantee integrity or authenticity Add a MAC to do that sodium_crypto_secretbox* functions Combined encrypt-then-MAC sodium_crypto_aead_* functions Achieves the same, but more efficiently Uses ChaCha20-Poly1305 or AES256-GCM AEAD ciphers Marcus Bointon @SynchroM
  17. SECRET-KEY ENCRYPTION EXAMPLES //Encrypt: $key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

    $ciphertext = sodium_crypto_secretbox('test', $nonce, $key); $ciphertext = sodium_crypto_aead_chacha20poly1305_encrypt('test', $nonce, $nonce, $key); //Decrypt: $plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key); $plaintext = sodium_crypto_aead_chacha20poly1305_decrypt($ciphertext, $nonce, $nonce, $key); //Variants: sodium_crypto_aead_chacha20poly1305_ietf_encrypt() sodium_crypto_aead_xchacha20poly1305_ietf_encrypt() //Future: sodium_crypto_aead_encrypt(); Marcus Bointon @SynchroM
  18. PUBLIC-KEY ENCRYPTION Sender & receiver each have two keys: private/secret

    & public Messages encrypted with a public key can be decrypted with a private key Critical component of Key Exchange Public key encryption used to exchange a secret key, so that faster symmetric ciphers can be used Popular algorithms: RSA, Diffie-Hellman, X25519 Marcus Bointon @SynchroM
  19. PUBLIC KEY ENCRYPTION IN SODIUM sodium_crypto_box_* functions Uses X25519 key

    exchange, XSalsa20 stream cipher, Poly1305 MAC Marcus Bointon @SynchroM
  20. EXAMPLE: PUBLIC KEY ENCRYPTION Create a key pair on node

    A: $aliceKeypair = sodium_crypto_box_keypair(); $aliceSecretKey = sodium_crypto_box_secretkey($aliceKeypair); $alicePublicKey = sodium_crypto_box_publickey($aliceKeypair); Create a key pair on node B: $bobKeypair = sodium_crypto_box_keypair(); $bobSecretKey = sodium_crypto_box_secretkey($bobKeypair); $bobPublicKey = sodium_crypto_box_publickey($bobKeypair); Encrypt a message on Node A to send to Node B using B’s public key + A’s private key $message 'Hi there! :)'; $aliceToBob = $aliceSecretKey . $bobPublicKey; $nonce = random_bytes(24); /* Never repeat this! */ $ciphertext = $nonce . sodium_crypto_box($message, $nonce, $aliceToBob); On Node B, decrypt an encrypted message from Node A using A’s public key + B’s private key $bobToAlice = $bobSecretKey . $alicePublicKey; $nonce = mb_substr($ciphertext, 0, 24, '8bit'); $encrypted = mb_substr($ciphertext, 24, null, '8bit'); $decrypted = sodium_crypto_box_open($encrypted, $nonce, $bobToAlice); Marcus Bointon @SynchroM
  21. OTHER CRYPTO FUNCTIONS Key derivation Avoid using your real, private

    key, generate one from it and use that instead sodium_crypto_pwhash Key exchange sodium_crypto_kx_* Great explanation on Wikipedia! Digital Signatures Like using public key encryption backwards Marcus Bointon @SynchroM
  22. NOT ALL ROSES password_hash in 7.2 supports PASSWORD_ARGON2I by default

    But that implementation is provided by libargon2 which isn’t included by default so you can’t use it Sodium provides a better Argon2 implementation supporting Argon2id But it’s not used by password_hash being added in PHP 7.3 Use sodium_crypto_pwhash_str Marcus Bointon @SynchroM
  23. EXAMPLE: STATELESS API TOKEN GENERATION IN LARAVEL $key = env('APP_KEY');

    $expires = gmdate('Y-m-d H:i:s', strtotime('now +2 hours')); $nonce = random_bytes(SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES); $encrypted = sodium_crypto_aead_chacha20poly1305_encrypt( json_encode(['expires' => $expires, 'user_id' => $userid,]), $nonce, $nonce, $key ); return response() json( [ 'api_token'  base64_encode($nonce . $encrypted), 'user_id'  $userid, 'expires'  $expires, ], 200 ); Marcus Bointon @SynchroM
  24. EXAMPLE: STATELESS API TOKEN VALIDATION IN LARAVEL $header = $request

    header('Api-Token'); $tokentext = base64_decode($header); $nonce = substr($tokentext, 0, SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES); $ciphertext = substr($tokentext,SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES); $key = env('APP_KEY'); $decrypted = sodium_crypto_aead_chacha20poly1305_decrypt( $ciphertext, $nonce, $nonce, $key ); sodium_memzero($key); $token = json_decode($decrypted); if (array_key_exists('user_id', $token) and array_key_exists('expires', $token)) { if (gmdate('Y-m-d H:i:s') <= $token['expires']) { //Token has not expired $expected_user = User where('email', $request email) first(); if ($expected_user id  $token['user_id']) { return $expected_user; } } } Marcus Bointon @SynchroM
  25. DOCUMENTATION Marcus Bointon @SynchroM

  26. DOCUMENTATION Fortunately there are other sources: https://download.libsodium.org/doc/ https://paragonie.com/book/pecl- libsodium https://paragonie.com/blog/

    Guide to Building Secure PHP Software http://www.phptherightway.com Marcus Bointon @SynchroM
  27. SUMMARY Don’t roll your own crypto Don’t use legacy crypto

    in new apps Sodium in PHP Removes ambiguity & doubt Raises the security bar Needs your help for docs! Questions? Thank you! Marcus Bointon @SynchroM