• Dec
  • 16
  • 2010

CreditCardFreezer is a PHP Class to Encrypt Credit Card Data for storage in a Database

by Andrew Kandels

Credit CardCreditCardFreezer is a PHP class which automates the storage and retrieval of encrypted credit card information to and from a database. One of the issues with working in the software-as-a-service industry is that credit card numbers often have to be stored locally in a database, for various reasons:

  • Recurring subscriptions (often with variable amounts).
  • Customers wanting to keep their card on file for future purchases.
  • Transactional based software providers (such as cloud providers).
  • Customer service wanting to verify the card on file with a customer.
  • Managers wanting to authorize certain charges for employees.

When storing information as confidential as credit card data, even though it's behind multiple passwords and buried in a database, it should be encrypted. CreditCardFreezer simplifies the encryption, storage and retrieval steps. It stores attributes you would need to run a credit card transaction, such as the card number and expiration. It also stores unsecured data like names and addresses for verification.

Download and Installation

The source code for the package can be found on Github.

Download / View Source

AES 128-Bit Encryption

CreditCardFreezer uses PHP's mcrypt extension with the MCRYPT_RIJNDAEL_256 cipher in CFB mode. A unique 32-byte IV is generated upon retrieving any secure value, so any two separate retrievals of encrypted values will return different results. This helps to reduce predictability when looking at encrypted values. The size of the encrypted text for credit card number and expiration storage is just under 100 bytes in length.

You should always set a secure passkey using setPassKey(). The key should ideally by a binary value, 32 bytes long. CreditCardFreezer will pad or truncate the value to the correct size. The same passkey must be used for encryption and decryption.

Storing Values with Setters

CreditCardFreezer supports a number of different syntaxes so that it can be adopted quickly. In most cases, just include the class and start using it in your project. A simple example of writing and reading data uses CreditCardFreezer's fluent interface, which allows you to chain methods together:

$obj = new CreditCardFreezer();
$secure = $obj->set(CreditCardFreezer::NUMBER, '1234-1234-1234-1234')
    ->set(CreditCardFreezer::EXPIRE_MONTH, '12')
    ->set(CreditCardFreezer::EXPIRE_YEAR, '2010')
    ->setPassKey('super secret')
    ->get();
 
// Store $secure in a database here, then retrieve it
 
$obj->set(CreditCardFreezer::NUMBER, $secure, true);
echo $obj->get(CreditCardFreezer::NUMBER); // 1234123412341234

But wait! Each attribute is also assigned a text label, so intead of writing CreditCardFreezer::EXPIRE_MONTH you could identify it in camel or underscore notation:

$obj = new CreditCardFreezer();
$secure = $obj->set('number', '1234-1234-1234-1234')
    ->set('expireMonth', '12')
    ->set('expireYear', '2010')
    ->setPassKey('super secret')
    ->get();

The second syntax allows you to query the attributes directly. This might be more familiar to users of an ORM:

$obj = new CreditCardFreezer;
$obj->number = '1234-1234-1234-1234';
$obj->expireMonth = '12';
$obj->expireYear = '2010';
$secure = $obj->setPassKey('super secret')
              ->secureStore;

Note: The text labels can be changed and the attributes can be appended to by extending the CreditCardFreezer class. Just override the _getTextLabels() protected method and assign your own names and attribute constants.

Retrieving Values / Getters

The get(), getValues() and toArray() methods all make retrieving encrypted attributes easy. You'll want to get the encrypted text if you plan on storing the values in a database.

To return the credit card number (a secure attribute) as encrypted text for storage in a database:

$obj->get('number', true); // Ve4-xSj...

To return an associative array of all values (with secure attributes as encrypted text):

$obj->toArray(true); // array('number' => 'Ve4-xSj...', 'first_name' => 'Andrew', ...)

To return the values for specified attributes (with secure attributes as encrypted text):

$obj->getValues(array('number', CreditCardFreezer::EXPIRE_MONTH), true);
// array('Ve4-xSj...', 'Sj3Xs-...')

For real values, simply omit the true parameter in any of the three previous examples.

Restoring Real Values from Encrypted Text

If you have retrieved encrypted text or values from a database and need to restore those values into the object, use the set() method:

$encrypted = $obj->get('number', true);
$firstName = $obj->get('firstName', true);
 
// Later...
 
$obj->set('number', $encrypted, true)
    ->set('first_name', $firstName, true);
Or for multiple values, use fromArray():
$encrypted = $obj->get('number', true);
$firstName = $obj->get('firstName', true);
 
// Later
 
$obj->fromArray(array(
    'number' => $encrypted,
    'firstName' => $firstName
));

SECURE_STORE Example

If you request a secure attribute, you'll receive a piece of encrypted text for each value. To reduce storage requirements, you can retrieve all secure attributes as one piece of encrypted text with the CreditCardFreezer::SECURE_STORE (or "secure_store") attribute:
$obj = new CreditCardFreezer();
$secure = $obj->set('number', '1234-1234-1234-1234')
    ->set('expire_month', '12')
    ->set('expire_year', '2010')
    ->setPassKey('super secret')
    ->get('secure_store'); // 'secure_store' is optional, this is the default attribute
 
// Store $secure in a database, then retrieve it...
 
$obj = new CreditCardFreezer();
$obj->set('secure_store', $secure, true); // the true is not actually required here
echo $obj->number; // 1234123412341234

PDO Implementation

The CreditCardFreezer_PDO class extends the base CreditCardFreezer class and adds some ORM-like functionality. If you're storing credit card information into a PDO data source, this class can easily automate the insertion, update, deletion, and retrieval of that information for you. It can even create the base table, if you so desire. The following example creates a base table in an SQLite data source, sets three attributes and saves them as a row:
$dbh = new PDO('sqlite:/test.sdb');
$obj = new CreditCardFreezer_PDO($dbh);
$obj->number = '1234123412341234';
$obj->expireMonth = '12';
$obj->expireYear = '2010';
$cardId = $obj->createTable()
              ->insert(); // return auto-increment id, which is 1

You can retrieve rows using the find() method:

echo $obj->find(1);
         ->number; // 1234123412341234

You can delete rows using the delete() method:

$obj->find(1);
    ->delete();

And finally, you can update rows using save():

$obj->find(1)
    ->set('expireMonth', '1')
    ->save();

Additional Notes

CreditCardFreezer is written in well documented, PHP 5 object oriented source code. It is tested using a PHPUnit test suite. The class is released under the BSD license and is free for anyone to use, however they like. I have either started working on or am planning some additional classes which will be included in the package at some point in the future:

  • CreditCardFreezer_AuthorizeDotNet: Code which integrates CreditCardFreezer with the Authorize.net payment gateway for creating one-time charges or managing recurring credit card subscriptions.
  • CreditCardFreezer_Paypal: Paypal integration similar to AuthorizeDotNet.
  • Credit card validation methods (although these are already widely available in popular frameworks like Zend).

Suggestions or code contributions are welcome. Just email me at me [at] andrewkandels.com or submit a request on the Github project page.