Encrypt and decrypt in php

Before you do anything further, seek to understand the difference between encryption and authentication, and why you probably want authenticated encryption rather than just encryption.

To implement authenticated encryption, you want to Encrypt then MAC. The order of encryption and authentication is very important! One of the existing answers to this question made this mistake; as do many cryptography libraries written in PHP.

You should avoid implementing your own cryptography, and instead use a secure library written by and reviewed by cryptography experts.

Update: PHP 7.2 now provides libsodium! For best security, update your systems to use PHP 7.2 or higher and only follow the libsodium advice in this answer.

Use libsodium if you have PECL access [or sodium_compat if you want libsodium without PECL]; otherwise...
Use defuse/php-encryption; don't roll your own cryptography!

Both of the libraries linked above make it easy and painless to implement authenticated encryption into your own libraries.

If you still want to write and deploy your own cryptography library, against the conventional wisdom of every cryptography expert on the Internet, these are the steps you would have to take.

Encryption:

  1. Encrypt using AES in CTR mode. You may also use GCM [which removes the need for a separate MAC]. Additionally, ChaCha20 and Salsa20 [provided by libsodium] are stream ciphers and do not need special modes.
  2. Unless you chose GCM above, you should authenticate the ciphertext with HMAC-SHA-256 [or, for the stream ciphers, Poly1305 -- most libsodium APIs do this for you]. The MAC should cover the IV as well as the ciphertext!

Decryption:

  1. Unless Poly1305 or GCM is used, recalculate the MAC of the ciphertext and compare it with the MAC that was sent using hash_equals[]. If it fails, abort.
  2. Decrypt the message.

Other Design Considerations:

  1. Do not compress anything ever. Ciphertext is not compressible; compressing plaintext before encryption can lead to information leaks [e.g. CRIME and BREACH on TLS].
  2. Make sure you use mb_strlen[] and mb_substr[], using the '8bit' character set mode to prevent mbstring.func_overload issues.
  3. IVs should be generating using a CSPRNG; If you're using mcrypt_create_iv[], DO NOT USE MCRYPT_RAND!
    • Also check out random_compat.
  4. Unless you're using an AEAD construct, ALWAYS encrypt then MAC!
  5. bin2hex[], base64_encode[], etc. may leak information about your encryption keys via cache timing. Avoid them if possible.

Even if you follow the advice given here, a lot can go wrong with cryptography. Always have a cryptography expert review your implementation. If you are not fortunate enough to be personal friends with a cryptography student at your local university, you can always try the Cryptography Stack Exchange forum for advice.

If you need a professional analysis of your implementation, you can always hire a reputable team of security consultants to review your PHP cryptography code [disclosure: my employer].

Important: When to Not Use Encryption

Don't encrypt passwords. You want to hash them instead, using one of these password-hashing algorithms:

  • Argon2
  • scrypt
  • bcrypt
  • PBKDF2-SHA256 with 86,000 iterations

Never use a general-purpose hash function [MD5, SHA256] for password storage.

Don't encrypt URL Parameters. It's the wrong tool for the job.

PHP String Encryption Example with Libsodium

If you are on PHP < 7.2 or otherwise do not have libsodium installed, you can use sodium_compat to accomplish the same result [albeit slower].

Chủ Đề