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.

Marcus Bointon

August 31, 2018

More Decks by Marcus Bointon

Other Decks in Technology


  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

  6. 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
  7. 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
  8. 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
  9. EXAMPLE: SIDE CHANNEL VULNERABILITY //Old, insecure $pw = md5($_POST['password']); $r

    = mysqli_query($db, "SELECT id, name FROM users WHERE email = ‘[email protected]’ 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 = '[email protected]'"); $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!’);
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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

    $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
  17. 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
  18. PUBLIC KEY ENCRYPTION IN SODIUM sodium_crypto_box_* functions Uses X25519 key

    exchange, XSalsa20 stream cipher, Poly1305 MAC Marcus Bointon @SynchroM
  19. 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
  20. 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
  21. 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

    $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

    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
  24. 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