Skip to content

Instantly share code, notes, and snippets.

@nh-mike
Last active January 25, 2021 07:49
Show Gist options
  • Save nh-mike/7b156fd3159fa9446b5c2340acf38ff4 to your computer and use it in GitHub Desktop.
Save nh-mike/7b156fd3159fa9446b5c2340acf38ff4 to your computer and use it in GitHub Desktop.

This is purely a PROOF OF CONCEPT.

This is licensed under GNU Lesser General Public License v3.0

What this aims to achieve.:
To implement a system by which multiple users may have access to a password management database in which passwords are encrypted but may be decrypted via each users. Users need not share a common password between them and all commonalities in this regard must be abstracted away from the user.

How this works:

  • Every password in the passwddb is encrypted to a global secret.
  • The global secret should be defined by the sysadmin when the first account is created ONLY.
  • The global secret is encrypted against the user's password NOT THE PASSWORD HASH.
  • The global secret can then be used to decrypt any password in the password database.
  • This does not factor in any access control mechanisms which must be implemented separately.
<?php
/**
* See the original GIST:
* https://gist.github.com/nh-mike/7b156fd3159fa9446b5c2340acf38ff4
*/
set_error_handler('exceptions_error_handler');
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
if(!extension_loaded('openssl'))
{
throw new Exception('This app needs the Open SSL PHP extension.');
}
$userdblocation = __DIR__.'/user.db';
$passwddblocation = __DIR__.'/passwd.db';
$userdb = file_get_contents($userdblocation);
$passwddb = file_get_contents($passwddblocation);
$userdbmd5 = md5($userdb);
$passwddbmd5 = md5($passwddb);
$userdb = unserialize($userdb);
$passwddb = unserialize($passwddb);
//Parse the CLI
if (isset($argv[1])) {
switch ($argv[1]) {
case 'add-first-user':
try {
$newusername = $argv[2];
$newpassword = $argv[3];
$globalsecret = $argv[4];
} catch (\exception $e) {
output_cli_help();
exit;
}
add_user($userdb, $newusername, $newpassword, $globalsecret);
break;
case 'add-user':
try {
$authusername = $argv[2];
$authpassword = $argv[3];
$newusername = $argv[4];
$newpassword = $argv[5];
} catch (\exception $e) {
output_cli_help();
exit;
}
$globalsecret = get_global_secret($userdb, $authusername, $authpassword);
add_user($userdb, $newusername, $newpassword, $globalsecret);
break;
case 'get-global-secret':
try {
$authusername = $argv[2];
$authpassword = $argv[3];
} catch (\exception $e) {
output_cli_help();
exit;
}
$globalsecret = get_global_secret($userdb, $authusername, $authpassword);
print_r($globalsecret);
break;
case 'encrypt':
try {
$authusername = $argv[2];
$authpassword = $argv[3];
$data = $argv[4];
} catch (Error | Exception $e) {
output_cli_help();
exit;
}
$globalsecret = get_global_secret($userdb, $authusername, $authpassword);
$encrypted_password = encrypt_password($data, $globalsecret);
$passwddbentry = array (
'encrypted_password' => $encrypted_password,
'plain_password' => $data
);
$passwddb[] = $passwddbentry;
break;
case 'decrypt':
try {
$authusername = $argv[2];
$authpassword = $argv[3];
$index = $argv[4];
} catch (\exception $e) {
output_cli_help();
exit;
}
$globalsecret = get_global_secret($userdb, $authusername, $authpassword);
if (!isset($passwddb[$index])) {
throw new \Exception(sprintf(
'No password exists at index %s',
$index
));
}
$data = $passwddb[$index]['encrypted_password'];
$decrypted_password = decrypt_password($data, $globalsecret);
print_r($decrypted_password);
break;
default:
output_cli_help();
exit;
}
} else {
output_cli_help();
exit;
}
$userdb = serialize($userdb);
$passwddb = serialize($passwddb);
if ($userdbmd5 !== md5($userdb)) {
file_put_contents($userdblocation, $userdb);
}
if ($passwddbmd5 !== md5($passwddb)) {
file_put_contents($passwddblocation, $passwddb);
}
function output_cli_help() {
echo 'usage: php openssl.php action'.PHP_EOL.
'actions:'.PHP_EOL.
' add-first-user newusername newpassword globalsecret'.PHP_EOL.
' add-user authusername authpassword newusername newuserpassword'.PHP_EOL.
' get-global-secret authusername authpassword'.PHP_EOL.
' encrypt authusername authpassword data'.PHP_EOL.
' decrypt authusername authpassword index'.PHP_EOL;
}
function add_first_user(&$userdb, $username, $password) {
$globalsecret = '';
$account = add_user($userdb, $username, $password, $globalsecret);
return $account;
}
function add_user(&$userdb, $username, $password, $globalsecret) {
$pw_hash = password_hash($password, PASSWORD_BCRYPT);
$encrypted_globalsecret = encrypt_password($globalsecret, $password);
$account = array(
'username' => $username,
'password' => $pw_hash,
'encrypted_globalsecret' => $encrypted_globalsecret
);
$userdb[] = $account;
}
function get_global_secret(&$userdb, $username, $password) {
for ($i=0; $i<=count($userdb); $i++) {
if ($i === count($userdb)) {
throw new Exception(sprintf(
'User %s does not exist',
$username
));
}
if ($userdb[$i]['username'] === $username) {
return decrypt_password(
$userdb[$i]['encrypted_globalsecret'],
$password
);
break;
}
}
}
function encrypt_password($data, $key) {
$method = 'AES-256-CBC';
$iv = hex2bin('34857d973953e44afb49ea9d61104d8c');
$encrypted_password = openssl_encrypt(
$data,
$method,
$key,
0,
$iv
);
return $encrypted_password;
}
function decrypt_password($data, $key) {
$method = 'AES-256-CBC';
$iv = hex2bin('34857d973953e44afb49ea9d61104d8c');
$decrypted_password = openssl_decrypt(
$data,
$method,
$key,
0,
$iv
);
return $decrypted_password;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment