C.3. Storing Credit Card Numbers
One of the most frequent questions I am asked is how to store credit card numbers securely. My first instinct is always to inquire whether it is absolutely necessary to store them. After all, regardless of implementation, taking unnecessary risks is never wise. There are also strict laws governing the processing of credit card information, and I am always careful to note that I am not a legal expert.
Rather than discussing methods uniquely related to credit card processing, I have chosen to demonstrate how to store encrypted data in the database and decrypt it upon retrieval. This approach incurs a performance penalty, but it does offer an extra layer of protection. The primary advantage is that a compromised database doesn't necessarily expose the encrypted data, but this is true only if the key is kept secret. Therefore, the secrecy of the key is as important as the implementation itself.
To store encrypted data in the database, first encrypt the data, then concatenate the initialization vector and the ciphertext together to create a string to store in the database. Because this is a binary string, use base64_encode( ) to convert it to a string that is safe to treat as plain text:
<?php $crypt = new crypt(); $crypt->cleartext = '1234567890123456'; $crypt->generate_iv(); $crypt->encrypt(); $ciphertext = $crypt->ciphertext; $iv = $crypt->iv; $string = base64_encode($iv . $ciphertext); ?>
Store this string in the database. Upon retrieval, reverse this process as follows:
<?php $string = base64_decode($string); $iv_size = mcrypt_get_iv_size($algorithm, $mode); $ciphertext = substr($string, $iv_size); $iv = substr($string, 0, $iv_size); $crypt = new crypt(); $crypt->iv = $iv; $crypt->ciphertext = $ciphertext; $crypt->decrypt(); $cleartext = $crypt->cleartext; ?>