I was wondering if it was possible to hold an encrypted text field within my database and have the ability to decrypt this piece of text based on a salt and authorized password?
For example:
$Salt = $_POST['Salt'];
$Password = $Query_Results['Password'];
if ($salt == $Stored_Salt AND $Authorized_Password == $Password){
//Perform a decryption of the stored results
echo $Decrypted_TextField;
}
I am in the process of creating a completely encrypted/encoded database. Nothing will be plain text apart from the integer fields for the identifiers. Everything else will be encrypted/encoded.. Many will use a one way encryption, but some fields need to house a two way encryption type.
I cannot house non-encrypted text in the database. Everything needs to be encrypted before storing. But the approach to this is an unknown process to me. So I was wondering if I could get some assistance on where to start
It is impossible to decrypt it. However, you may be able to crack it using the brute force method to find matching passwords in a dictionary. Best tool to use would be hashcat. Save this answer.
Can we decrypt SHA256 with salt? Since SHA256 is a hash based on non-linear functions, there is no decryption method.
it would require the salt to be stored. if the salt were lost/corrupted the user would not be able to decrypt the file anymore.
It sounds like you might want to do some more background on crypto generally, and DB encryption options specifically (you don't mention the data store, but there are MySQL and Postgres options for full encryption). In general, it is almost always a bad idea to "roll your own", and unfortunately, between mcrypt() and openssl_*() functions, there are frankly too many options presented to a novice (such as presenting EBC and CBC as equally valid options). While this thread: https://security.stackexchange.com/questions/18197/why-shouldnt-we-roll-our-own is mainly talking about the futility of creating "novel" cryptographic primitives, the principle also applies to naive attempts at implementing application- and database-level encryption as well.
As a practical matter, the most challenging thing you will likely have to deal with is the issue of password/key management. The code below puts all of the responsibility on the client (sender) - and unless you save the submitted password (which sort of defeats the whole purpose), if the user forgets or is otherwise unable to supply their password in the future, encrypted data in the database will be unrecoverable. (And, yes, if you really want to go down the Yak Shaving path, there are options for multi-key envelope encryption).
If you store the key/password server-side you are, at best, only putting a small road bump in the path of an adversary: if she can manage to read your key file, she can retrieve the data. But worst, by saving the password locally, you are giving a false sense of security to your users, and if this is financial, health, or otherwise protected information, you and your organization take on that burden of that liability.
Finally, there is a mature library here: http://phpseclib.sourceforge.net/crypt/examples.html but in my opinion, it offers too many options for a novice user (see, for example, the default EBC mode in the code generator). For password hashing, take a close look at the phpPass library here: http://www.openwall.com/phpass/.
All that said, here is a working start for simple two-way, reasonably strong encryption, with randomly generated initialization vectors and salts, and a 256-bit AES symmetric (e.g., non-public key) cipher. Tested on OSX Lion & CentOS/RedHat 6.
Good luck!
//$message = escapeshellarg( $_POST['message'] );
$message = 'This is my very secret data SSN# 009-68-1234';
// Set to some reasonable limit for DB.
// Make sure to size DB column +60 chars
$max_msg_size = 1000;
$message = substr($message, 0, $max_msg_size);
// User's password (swap for actual form post)
//$password = escapeshellarg( $_POST['password'] );
$password = 'opensesame';
// Salt to add entropy to users' supplied passwords
// Make sure to add complexity/length requirements to users passwords!
// Note: This does not need to be kept secret
$salt = sha1(mt_rand());
// Initialization Vector, randomly generated and saved each time
// Note: This does not need to be kept secret
$iv = substr(sha1(mt_rand()), 0, 16);
echo "\n Password: $password \n Message: $message \n Salt: $salt \n IV: $iv\n";
$encrypted = openssl_encrypt(
"$message", 'aes-256-cbc', "$salt:$password", null, $iv
);
$msg_bundle = "$salt:$iv:$encrypted";
echo " Encrypted bundle = $msg_bundle \n\n ";
// Save it... (make sure to use bind variables/prepared statements!)
/* db_write( "insert into sensitive_table encrypted_msg values (:msg_bundle)",
$msg_bundle ); */
Now retrieve it:
// Retrieve from DB...
//$password = escapeshellarg( $_POST['password'] );
$password = 'opensesame';
// Swap with actual db retrieval code here
//$saved_bundle = db_read( "select encrypted_msg from sensitive_table" );
$saved_bundle = $msg_bundle;
// Parse iv and encrypted string segments
$components = explode( ':', $saved_bundle );;
var_dump($components);
$salt = $components[0];
$iv = $components[1];
$encrypted_msg = $components[2];
$decrypted_msg = openssl_decrypt(
"$encrypted_msg", 'aes-256-cbc', "$salt:$password", null, $iv
);
if ( $decrypted_msg === false ) {
die("Unable to decrypt message! (check password) \n");
}
$msg = substr( $decrypted_msg, 41 );
echo "\n Decrypted message: $decrypted_msg \n";
Sample output:
Password: opensesame
Message: This is my very secret data SSN# 009-68-1234
Salt: 3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37
IV: 00c1d3b4c6a6f4c3
Encrypted bundle = 3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37:00c1d3b4c6a6f4c3:KB6k+GlM+0EHbETUgEe8Lck0nF5qBz+51wc5LtmS4XMOm0Pfyyr2PIXMVEyzs/41
array(3) {
[0]=>
string(40) "3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37"
[1]=>
string(16) "00c1d3b4c6a6f4c3"
[2]=>
string(64) "KB6k+GlM+0EHbETUgEe8Lck0nF5qBz+51wc5LtmS4XMOm0Pfyyr2PIXMVEyzs/41"
}
Decrypted message: This is my very secret data SSN# 009-68-1234
Not a complete answer but an expansion of how salting works that was too long for a comment..
The salt shouldn't be treated as a string to be compared, it should be a part of the password that the end user doesn't have to type but is unique to that user. It's used to prevent a single compromised password breaching multiple accounts.
Eg let's say we've got a really simple system on which Bob has the password ABCDEF
.
Passing ABCDEF
through our hashing algorithm results in (say) ED6522687
If an attacker gets access to the password list, they can only see the stored hash.
Of course, if Jane also uses the same password, her hash is going to be ED6522687
too - which means if you break into either account (through brute-force, social engineering, etc) you're going to get access to both accounts as you can see their hashes match.
Salting is where something is done to the password before hashing that's unique to each user and repeatable. Salt should be predictable so let's say Bob and Jane's salts are random numbers.
Now if you hash the password for bob ABCDEF123
, you get a different hash to Jane's ABCDEF456
.
Note that this isn't a complete explanation. Some other things to consider:
bcrypt
are designed to be computationally expensive. unlike (say) SHA2
Another observation which isn't usually emphasised enough... You should never trust anything you read on the internet about a topic like this - there are too many people who have incomplete understanding (I consider myself among them). So take this as reasons not to do it yourself, not a guide on how to do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With