Last active
August 29, 2015 14:15
-
-
Save tomgidden/a8bf0d21cc29fcce3044 to your computer and use it in GitHub Desktop.
Storing sensitive data in PHP using PKE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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