OK... to the point...
I have a e-mailshot program that sends out thousands of emails - each with str_replace()
merge fields (fields that get replaced by a row value in a recordset).
One of the important parts is my ability to track those mails on open so I include a single server-side generated pixel...
<img src="http://...trace.php?email=<<<EMAIL>>>" alt="" height="1" width="1">
The str_replace()
replaces <<<EMAIL>>>
with a unique real email address.
The trace.php
file reads the $_GET['email']
and either logs it or sends mail confirmation.
My issue is security :)
I want to use two-way encryption so that the $_GET
variable sent in the URL is an encrypted email. The trace.php file then needs to decrypt it.
As it's being sent in a URL, It has to be in ASCII format otherwise it will corrupt before decrypting.
I can't use openssl_encrypt()
& openssl_decrypt()
and I'm having to work with php 5.2.0 (don't hurl abuse at me!).
Any help would be greatly appreciated!!
While many of the comments you have received offer other valid ways of solving the problem e.g. a table of email addresses with primary keys, I am of the position that the best way to solve the problem is the way you originally intended: including the email address encrypted in the query URL.
I feel that this way is better because:
The issue is that for this way to be better, you have to do it well. I've included an excerpt in PHP from this repository below. If you can't use openssl_*
then upgrade your PHP version. Do not, ever, use the mcrypt_
functions. They are deprecated for a reason. You may need to hex encode instead of base64 encode the email addresses as is done in the example below.
<?php
define("ALGORITHM_NAME", "aes-128-gcm");
define("ALGORITHM_NONCE_SIZE", 12);
define("ALGORITHM_TAG_SIZE", 16);
define("ALGORITHM_KEY_SIZE", 16);
define("PBKDF2_NAME", "sha256");
define("PBKDF2_SALT_SIZE", 16);
define("PBKDF2_ITERATIONS", 32767);
function encryptString($plaintext, $password) {
// Generate a 128-bit salt using a CSPRNG.
$salt = random_bytes(PBKDF2_SALT_SIZE);
// Derive a key.
$key = hash_pbkdf2(PBKDF2_NAME, $password, $salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE, true);
// Encrypt and prepend salt and return as base64 string.
return base64_encode($salt . encrypt($plaintext, $key));
}
function decryptString($base64CiphertextAndNonceAndSalt, $password) {
// Decode the base64.
$ciphertextAndNonceAndSalt = base64_decode($base64CiphertextAndNonceAndSalt);
// Retrieve the salt and ciphertextAndNonce.
$salt = substr($ciphertextAndNonceAndSalt, 0, PBKDF2_SALT_SIZE);
$ciphertextAndNonce = substr($ciphertextAndNonceAndSalt, PBKDF2_SALT_SIZE);
// Derive the key.
$key = hash_pbkdf2(PBKDF2_NAME, $password, $salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE, true);
// Decrypt and return result.
return decrypt($ciphertextAndNonce, $key);
}
function encrypt($plaintext, $key) {
// Generate a 96-bit nonce using a CSPRNG.
$nonce = random_bytes(ALGORITHM_NONCE_SIZE);
// Encrypt and prepend nonce.
$ciphertext = openssl_encrypt($plaintext, ALGORITHM_NAME, $key, OPENSSL_RAW_DATA, $nonce, $tag);
return $nonce . $ciphertext . $tag;
}
function decrypt($ciphertextAndNonce, $key) {
// Retrieve the nonce and ciphertext.
$nonce = substr($ciphertextAndNonce, 0, ALGORITHM_NONCE_SIZE);
$ciphertext = substr($ciphertextAndNonce, ALGORITHM_NONCE_SIZE, strlen($ciphertextAndNonce) - ALGORITHM_NONCE_SIZE - ALGORITHM_TAG_SIZE);
$tag = substr($ciphertextAndNonce, strlen($ciphertextAndNonce) - ALGORITHM_TAG_SIZE);
// Decrypt and return result.
return openssl_decrypt($ciphertext, ALGORITHM_NAME, $key, OPENSSL_RAW_DATA, $nonce, $tag);
}
?>