Encryption Strategy for Bank Account Data
PHP
Difficulty Level:
Snippet Description
1. Encryption Helper Functions
<?php
/**
* Encryption Helper Functions for Bank Account Data
* Uses OpenSSL for AES-256-CBC encryption
*/
/**
* Get encryption key from wp-config.php
* IMPORTANT: Add this constant to your wp-config.php file
*/
function get_encryption_key() {
if (!defined('BANK_DATA_ENCRYPTION_KEY')) {
// Fallback - but you should define this in wp-config.php
error_log('BANK_DATA_ENCRYPTION_KEY not defined in wp-config.php');
return hash('sha256', AUTH_KEY . SECURE_AUTH_KEY);
}
return hash('sha256', BANK_DATA_ENCRYPTION_KEY);
}
/**
* Encrypt sensitive data
*/
function encrypt_bank_data($data) {
if (empty($data)) {
return '';
}
$encryption_key = get_encryption_key();
$iv_length = openssl_cipher_iv_length('aes-256-cbc');
$iv = openssl_random_pseudo_bytes($iv_length);
$encrypted = openssl_encrypt(
$data,
'aes-256-cbc',
$encryption_key,
0,
$iv
);
// Combine IV and encrypted data, then base64 encode
return base64_encode($iv . $encrypted);
}
/**
* Decrypt sensitive data
*/
function decrypt_bank_data($encrypted_data) {
if (empty($encrypted_data)) {
return '';
}
$encryption_key = get_encryption_key();
$data = base64_decode($encrypted_data);
$iv_length = openssl_cipher_iv_length('aes-256-cbc');
$iv = substr($data, 0, $iv_length);
$encrypted = substr($data, $iv_length);
$decrypted = openssl_decrypt(
$encrypted,
'aes-256-cbc',
$encryption_key,
0,
$iv
);
return $decrypted;
}
/**
* Mask bank account number for display (show last 4 digits)
*/
function mask_account_number($account_number, $show_last = 4) {
$decrypted = decrypt_bank_data($account_number);
if (strlen($decrypted) <= $show_last) {
return str_repeat('*', strlen($decrypted));
}
return str_repeat('*', strlen($decrypted) - $show_last) . substr($decrypted, -$show_last);
}
2. Encrypt Data on Form Submission
<?php
/**
* Encrypt bank account data before saving to database
* Hooks into JetFormBuilder before form submission
*/
add_filter('jet-form-builder/form-handler/before-send', 'encrypt_bank_account_before_save', 10, 2);
function encrypt_bank_account_before_save($request, $form_id) {
// Only apply to the bank account form (form ID 1616)
if ($form_id != 1616) {
return $request;
}
// Encrypt account_number if present
if (isset($request['account_number']) && !empty($request['account_number'])) {
$request['account_number'] = encrypt_bank_data($request['account_number']);
}
// Encrypt routing_number if present
if (isset($request['routing_number']) && !empty($request['routing_number'])) {
$request['routing_number'] = encrypt_bank_data($request['routing_number']);
}
return $request;
}
3. Decrypt Data When Retrieving
<?php
/**
* Get user's bank accounts with decrypted data (for processing)
*/
function get_user_bank_accounts_decrypted($user_id = null) {
if (!$user_id) {
$user_id = get_current_user_id();
}
global $wpdb;
$table = $wpdb->prefix . 'jet_cct_bank_accounts';
$accounts = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table WHERE cct_author_id = %d AND cct_status = 'publish' ORDER BY cct_created DESC",
$user_id
));
// Decrypt sensitive fields
foreach ($accounts as $account) {
$account->account_number_decrypted = decrypt_bank_data($account->account_number);
$account->routing_number_decrypted = decrypt_bank_data($account->routing_number);
// Keep encrypted versions for display
$account->account_number_masked = mask_account_number($account->account_number);
$account->routing_number_masked = mask_account_number($account->routing_number, 2);
}
return $accounts;
}
/**
* Get user's bank accounts with masked data (for display)
*/
function get_user_bank_accounts_masked($user_id = null) {
if (!$user_id) {
$user_id = get_current_user_id();
}
global $wpdb;
$table = $wpdb->prefix . 'jet_cct_bank_accounts';
$accounts = $wpdb->get_results($wpdb->prepare(
"SELECT _ID, cct_author_id, account_holder_name, bank_name, account_number, routing_number, is_default, cct_created
FROM $table
WHERE cct_author_id = %d AND cct_status = 'publish'
ORDER BY cct_created DESC",
$user_id
));
// Only show masked versions
foreach ($accounts as $account) {
$account->account_number = mask_account_number($account->account_number);
$account->routing_number = mask_account_number($account->routing_number, 2);
}
return $accounts;
}
4. Security Configuration
Add this to your wp-config.php file (above the “That’s all, stop editing!” line):
/**
* Encryption key for sensitive bank account data
* IMPORTANT: Generate a unique key and keep it secure
* Never commit this to version control
*/
define('BANK_DATA_ENCRYPTION_KEY', 'your-unique-256-bit-encryption-key-here');
To generate a secure encryption key, run this PHP snippet once:
<?php
// Run this once to generate a secure key
echo bin2hex(random_bytes(32));
5. Update Validation Function
Update your validation to work with encrypted data:
<?php
/**
* Validate bank account form (updated for encryption)
*/
add_filter('jet-form-builder/form-handler/before-send', 'validate_bank_account_form_encrypted', 5, 2);
function validate_bank_account_form_encrypted($request, $form_id) {
if ($form_id != 1616) {
return $request;
}
// Check if user is logged in
if (!is_user_logged_in()) {
wp_die('You must be logged in to add a bank account.');
}
$user_id = get_current_user_id();
$account_number = isset($request['account_number']) ? $request['account_number'] : '';
// Check for duplicate account numbers
// Note: We need to check against all encrypted values
global $wpdb;
$table = $wpdb->prefix . 'jet_cct_bank_accounts';
$existing_accounts = $wpdb->get_results($wpdb->prepare(
"SELECT account_number FROM $table WHERE cct_author_id = %d AND cct_status = 'publish'",
$user_id
));
// Decrypt and compare each account
foreach ($existing_accounts as $existing) {
$decrypted_existing = decrypt_bank_data($existing->account_number);
if ($decrypted_existing === $account_number) {
wp_die('This account number is already registered.');
}
}
return $request;
}