Home » Php » Two-way encryption in PHP

Two-way encryption in PHP

Posted by: admin April 23, 2020 Leave a comment


My application (obviously) uses a unique ID to distinguish records. This UID is passed in URLs (e.g. ./examplepage.php?UID=$example_int), among other things.

While I obviously have server-side validation in place to make sure clients don’t access other clients’ data, is there a two-way encryption method I can use in PHP to only pass encrypted UIDs (e.g. ./examplepage.php?EUID=$encrypted_int), to further reduce the chance of anyone thinking “hey, what happens if I increment this integer?”


How to&Answers:

Placing a hash next to the ID to ensure it’s security, or padding the ID with extra data, or even converting the ID to hex would all work fairly well I think.


PHP 5.3 has introduced a new encryption method that is really easy to use: openssl_encrypt and openssl_decrypt. It’s not well-documented here, so here’s a simple example:

$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";  // AES is used by the U.S. gov't to encrypt top secret documents.
$secretHash = "25c6c7ff35b9979b151f2136cd13b0ff";

//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash);

//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);

echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";

I chose 256-AES because it’s solid and fast. It’s been adopted by the U.S. gov’t to encrypt top secret documents. It’s fast considering machine and software. Here’s a list of available encryption methods:

AES-128-CBC, AES-128-CFB, AES-128-CFB1, AES-128-CFB8, AES-128-ECB, AES-128-OFB, AES-192-CBC, AES-192-CFB, AES-192-CFB1, AES-192-CFB8, AES-192-ECB, AES-192-OFB, AES-256-CBC, AES-256-CFB, AES-256-CFB1, AES-256-CFB8, AES-256-ECB, AES-256-OFB, BF-CBC, BF-CFB, BF-ECB, BF-OFB, CAMELLIA-128-CBC, CAMELLIA-128-CFB, CAMELLIA-128-CFB1, CAMELLIA-128-CFB8, CAMELLIA-128-ECB, CAMELLIA-128-OFB, CAMELLIA-192-CBC, CAMELLIA-192-CFB, CAMELLIA-192-CFB1, CAMELLIA-192-CFB8, CAMELLIA-192-ECB, CAMELLIA-192-OFB, CAMELLIA-256-CBC, CAMELLIA-256-CFB, CAMELLIA-256-CFB1, CAMELLIA-256-CFB8, CAMELLIA-256-ECB, CAMELLIA-256-OFB, CAST5-CBC, CAST5-CFB, CAST5-ECB, CAST5-OFB, DES-CBC, DES-CFB, DES-CFB1, DES-CFB8, DES-ECB, DES-EDE, DES-EDE-CBC, DES-EDE-CFB, DES-EDE-OFB, DES-EDE3, DES-EDE3-CBC, DES-EDE3-CFB, DES-EDE3-CFB1, DES-EDE3-CFB8, DES-EDE3-OFB, DES-OFB, DESX-CBC, RC2-40-CBC, RC2-64-CBC, RC2-CBC, RC2-CFB, RC2-ECB, RC2-OFB, RC4, RC4-40, SEED-CBC, SEED-CFB, SEED-ECB, SEED-OFB, aes-128-cbc, aes-128-cfb, aes-128-cfb1, aes-128-cfb8, aes-128-ecb, aes-128-ofb, aes-192-cbc, aes-192-cfb, aes-192-cfb1, aes-192-cfb8, aes-192-ecb, aes-192-ofb, aes-256-cbc, aes-256-cfb, aes-256-cfb1, aes-256-cfb8, aes-256-ecb, aes-256-ofb, bf-cbc, bf-cfb, bf-ecb, bf-ofb, camellia-128-cbc, camellia-128-cfb, camellia-128-cfb1, camellia-128-cfb8, camellia-128-ecb, camellia-128-ofb, camellia-192-cbc, camellia-192-cfb, camellia-192-cfb1, camellia-192-cfb8, camellia-192-ecb, camellia-192-ofb, camellia-256-cbc, camellia-256-cfb, camellia-256-cfb1, camellia-256-cfb8, camellia-256-ecb, camellia-256-ofb, cast5-cbc, cast5-cfb, cast5-ecb, cast5-ofb, des-cbc, des-cfb, des-cfb1, des-cfb8, des-ecb, des-ede, des-ede-cbc, des-ede-cfb, des-ede-ofb, des-ede3, des-ede3-cbc, des-ede3-cfb, des-ede3-cfb1, des-ede3-cfb8, des-ede3-ofb, des-ofb, desx-cbc, rc2-40-cbc, rc2-64-cbc, rc2-cbc, rc2-cfb, rc2-ecb, rc2-ofb, rc4, rc4-40, seed-cbc, seed-cfb, seed-ecb, seed-ofb


Thanks Hobo and Jorwin for pointing out that in PHP 5.3.3 > there is a new parameter that makes this function a little more secure.

Jorwin referenced this link in his comment, and here is an excerpt that is applicable:

In 5.3.3 they added a new parameter, string $iv (initialization
vector) Real parameters are: string openssl_encrypt ( string $data ,
string $method , string $password, bool $raw_output = false, string
$iv )

If $iv is missing, a warning is issued: “Using an empty Initialization Vector (iv) is potentially insecure and not recommended”.

If $iv is too short, another warning: “IV passed is only 3 bytes long, cipher expects an IV of precisely 8 bytes, padding with \0”

same IV should be used in openssl_decrypt()


You don’t need two-way encryption – encryption is for maintaining secrecy, but what you’re really looking for here is authenticity.

HMACs (essentially, keyed hashes) are one way of getting cryptographic authenticity. Accompany the UID with a HMAC of the UID (PHP has a HMAC implementation), using a key that only the server knows. At the start of each request, check the HMAC.

Basically, use the right tool for the right job.


While PHP supports many two way hashing algorithms I do not see it being useful in this example. What you need to do is:

  1. Load the row from storage by the provided id
  2. Check that the owner of the row is the authenticated user and if not throw an exception and inform the user not to do that again

But if your heart is set on hashing just pick one of the algorithms provided.


For two-way encryption check mcrypt, or if you prefer a pure implementation phpseclib.


First, encrypting URL parameters is usually a bad idea, and a separate lookup (based on an index CHAR column generated by a CSPRNG) is better for 99.9% of use cases.

With that said: Yes, you can use the OpenSSL extension (don’t use mcrypt) to encrypt the data like espradley suggested, however I would caution you to not stop at merely encryption.

Encryption without message authentication is dangerous, especially if you’re trusting an end-user with the ciphertext.

The solution, therefore, is to use authenticated encryption, which can be easily accessed with libsodium, available on PECL.

If you cannot for whatever reason install a PECL extension, there are two PHP libraries to choose from: defuse/php-encryption and zend-crypt. They both offer standards compliant authenticated encryption and they’re both safe to use (for what it’s worth, I frequently perform code audits for cryptography implementations in PHP, I’m not merely some random person on the internet).