Skip to content

Instantly share code, notes, and snippets.

@tomgidden
Last active August 29, 2015 14:15
Show Gist options
  • Save tomgidden/a8bf0d21cc29fcce3044 to your computer and use it in GitHub Desktop.
Save tomgidden/a8bf0d21cc29fcce3044 to your computer and use it in GitHub Desktop.
Storing sensitive data in PHP using PKE
<?php
# First, create a key pair:
# openssl genrsa -aes256 2048 > private.pem
# openssl rsa -in private.pem -pubout > public.pem
define('SALT', 'Confidential (but not really critically secret) string that should not change. Just to stop rainbow tabling.');
define('PRIVATE_KEY_FILE', './private.pem');
define('PUBLIC_KEY_FILE', './public.pem');
define('DATA_DIR', '.');
define('DATA_TREE', true);
function hashed_filename($id, $make_tree=true)
// Generate a hashed filename. This will obscure the user ID (which is
// also secret, to some degree)
{
$fn = hash('sha256', SALT.$id.SALT);
if(defined('DATA_TREE') and constant('DATA_TREE')) {
$dir = DATA_DIR.'/'.$fn[0].'/'.$fn[1];
if($make_tree) @mkdir($dir, 0777, true);
$fn = "$dir/$fn.enc";
}
else {
$fn = "$fn.enc";
}
return $fn;
}
function prompt($label, $hidden=false)
// PHP's readline doesn't support hidden passwords, so using shell
// instead.
{
print "$label: ";
$data = exec('read '.($hidden?'-s':'').' FOO; echo $FOO');
if($hidden) print "\n";
return $data;
}
<?php
require_once('pke_common.php');
try {
$user_id = prompt("User ID to retrieve", false);
$passphrase = prompt("Private key passphrase", true);
// Load the encrypted private key
@$private_pem_encrypted = file_get_contents(PRIVATE_KEY_FILE);
if(empty($private_pem_encrypted))
throw new Exception("Could not load private key");
// Decrypt and parse the private key
$private = openssl_pkey_get_private($private_pem_encrypted, $passphrase);
if(FALSE === $private)
throw new Exception("Could not parse private key: wrong passphrase?");
// Construct filename
$fn = hashed_filename($user_id, false);
// Load the encrypted data
if(!file_exists($fn))
throw new Exception("Could not load data for user '$user_id' from file '$fn'");
$encrypted_data = base64_decode(file_get_contents($fn));
$secret_data = NULL;
$res = openssl_private_decrypt($encrypted_data, $secret_data, $private);
if(!$res)
throw new Exception("Could not decrypt data with private key");
// Here it is!
print "Stored data: $secret_data\n\n";
}
catch (Exception $e) {
fwrite(STDERR, "\n\n\n".$e->getMessage()."\n\n\n");
exit(1);
}
<?php
require_once('pke_common.php');
try {
$user_id = prompt("User ID to store", false);
$secret_data = prompt("Secret data to store", false);
// Load the public key
$public_pem = @file_get_contents(PUBLIC_KEY_FILE);
if(empty($public_pem))
throw new Exception("Could not load public key");
// Decrypt and parse the public key
$public = openssl_pkey_get_public($public_pem);
if(FALSE === $public)
throw new Exception("Could not parse public key");
// Construct filename
$fn = hashed_filename($user_id);
// Encrypt the data
$encrypted_data = null;
$res = openssl_public_encrypt($secret_data, $encrypted_data, $public);
if(!$res)
throw new Exception("Could not encrypt data with public key");
// Store the encrypted data. The base64's not really necessary, but
// it's neater.
file_put_contents($fn, base64_encode($encrypted_data));
}
catch (Exception $e) {
fwrite(STDERR, "\n\n\n".$e->getMessage()."\n\n\n");
exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment