MySQL encrypted columns - mysql

Say each row in a table has data pertaining to one particular user. The user has a password to access the system.
How do I encrypt a column of data using InnoDB so that no one other than the user who's data it is can read the data ? I was thinking of something like using one of the MySQL encryption functions (say AES) with a key based on a hash calculated from the user's password.
Does any one have any pointers to how I could do this ? Am I on the right track ?
One of the answers below
The issue of modifying user's password involves re-encrypting the user key by means of the new password which is much more straight forward than re-encrypting the whole bunch of user's data that can be arbitrarily large. The user key remains the same accross the life of the user data in the system.
How does this help ? Say the password is pass1. And there are a bunch of records encrypted with a key generated from this. If the user now resets the password to pass2, I have no way of decrypting the data that was encrypted using pass1. In the case of a user forgetting the password entirely, all his encrypted data will be lost.

I don't know if there is much sense in encrypting data with user's password hash, especially if you keep hash itself in the database. In that case anyone who can access the encrypted data can also access the password hash and decrypt the data.
Another approach would be to encrypt the data with the application-specific key salted with some user-specific data. However, then you face another problem: how to securely store the application key. To that question I do not know an easy answer, but keeping it in your source code is probably good enough if you fear that your database data can be compromised, but not the source code itself, e.g. if your database is stored off-site (think Amazon S3).
Salting the app key with the user's password helps if you keep only password's hash in the database, but can introduce another security flaw: you have to keep user's password in clear text in the applications session.
As for technical solution, it is quite simple and sample code is available. You could modify it as follows to encrypt the data with the application password salted with password hash:
INSERT INTO secure_table VALUES (
1,
AES_ENCRYPT(
'plain text data',
CONCAT(#application_password, #user_password))
);
In any case you would have to store your application password somewhere so I don't think that there is an easy approach that provides perfect security.
Another approach I can think of is to ask user for a short PIN which you could use as an encryption key. The PIN would not be stored in the database, but you would need to ask user for it every time you access their data.
And of course your have to think of is the feasibility of the encryption. You won't be able to index or to search it without decryption. It is probably required for a limited set of data (e.g. credit card number), but I wouldn't go to far with it.

To clarify one of the answers mentioned in the question: "user/app key" is a randomly generated private key, which is used to encrypt the data. The private key never changes (unless it's compromised). You encrypt and store the private key with a password. Since the private key is much smaller than the data, it's much cheaper to change the password: you simply decrypt the private key with the old password and re-encrypt it with the new password.

For data that is not user-specific (global), you could maybe use a combination of symmetric and asymmetric cipher. You could have an extra password field that all users are required to enter so that even if one user changes one's password, the global data will still be usable to other users with different passwords.
The extra password can be bitwise xor'ed with another salt-like string inside the source code. Together, it can form the symmetric passkey to decrypt a private key stored in the database (which will never change). After private key is decrypted using the extra password, the private key can decrypt and read all the data in the db. Private key can be stored as session variable.
The public key, as the name suggests, can reside as plain text string in the db. When you need to write to db, use public key to encrypt the data.
You can routinely provide the users with a new extra password and re-encrypt the static private key, followed by an xor'ing with salt-like string.
If the data is user-specific data and not meant for other users, you could use the user's password without the extra-password field to encrypt the private key. The administrator could have another copy of the private keys for specific users, which can be decrypted using his password.

I don't think that's the best approach, unless you're enforcing that users can never change their password, or you have a way to re-encrypt everything each time a user changes his/her password.

You could store another key to encrypt/decrypt user specific data which could be generated when a new user is created. Let's call this new key user key. This user key should also be encrypted in database and the most direct approach would be to encrypt it by means of the user's password or any other data which cointained the password (such as the password and creation/modification time, etc.).
I would keep in user's session the decrypted user key to access user's data at any desired time within session.
The issue of modifying user's password involves re-encrypting the user key by means of the new password which is much more straight forward than re-encrypting the whole bunch of user's data that can be arbitrarily large. The user key remains the same accross the life of the user data in the system.
Of course this method can only be used if authentication is carried out by sending the actual user password to the server at logon, since database only desirably contains the hash of the password.

Say the password is pass1. And there are a bunch of records encrypted with a key generated from this. If the user now resets the password to pass2, I have no way of decrypting the data that was encrypted using pass1
The key would need to be encrypted in a reversable manner, so that it could be decrypted
using pass1 and re-encrypted using pass2.
To summarize:
Stored in the database is: the one-way encrypted password (for password checking),
the encryption key for other data, reversibly encrypted using the clear password (or at any rate, the password encrypted in some different manner than the way it is stored in the database), and the other data, reversibly encrypted using the clear encryption key.
Whenever you need the other data, you must have the clear (or differently encrypted than as stored in the database) password, read the encryption key, decrypt it with the password, and use that to decrypt the other data.
When a password is changed, the encryption key is decrypted using the old password, encrypted using the new password, and stored.

If you need to access the data without user interaction (for database migration for example), you won't have the key to decrypt.

Related

Authentication management using "in-database" design

I want to discuss wether good or bad idea:
I got a MySQL DB and created a common table "user" to authenticate an login.
|User|
|user_id|username|password|created_at|
I implemented a stored function and some triggers.
First of all:
ON BEFORE UPDATE
will generate a SHA256 hash and salt when password was changed.
salt is generated out witha mix of created_at, user_id and a global salt_mod which is stored in another "config-table".
So when entering 123 in "password" via normal UPDATe it will produce user-unique password and salt hashes.
Next I implemented a stored function
checkUserAuth('username', 'password')
returns: bool true or false
Ofcourse: receives PLAIN username and password, replicates same hashing logic and returns
bool "true" or "false", depends on if the credentials have been correct.
Pro:
This makes completely sync of password algorithm changes obsolete to any connected apps.
Database-account that is being used by the app can work without SELECT privileges on "username", "password" and "salt" privileges.
Even if the user-account of the database is stolen, passwords are still safe due to lacking permissions to read the FUNCTIONS source-code and the columns that store login-information. We only have an EXECUTE privilege here.
Contra:
Well if someone breaks in on the DB with root privileges, pretty much the source-code on "how to generate the hashes" is leaked (pretty much the salting formula) together with all information in one place. However its still hard to rainbow-table that due to unique hashes on created_at date and user_id in mix with global_salt.
The question to above scenario:
Is this a good approach or totally vulnerable in point of data-security?
I mean on one side, a break-in inside the database is always a problem that should never happen
On the other side, even with stolen source-code of the apps or stolen database-account by a bug in the app you cannot steal any login related data.
The root account is ofcourse excluded from being using elsewhere then on the localhost/server.
What do you think about this?
The primary weakness is that you pass the password in plaintext when you create the row, and every time you call your checkUserAuth() function.
This can be wiretapped (unless you ensure using SSL connections between app and database) and it will be written to the query log if you have the query log enabled. It's also visible in the processlist and the performance_schema statements history tables.
This is a good reason to do the hashing in the client, and send only the salted hash of the password when you create the row. When you authenticate, fetch the salted hash from the database, and validate it against user input in the client.

Encrypting with one hash and storing another

I want to implement a system where by encrypted data can be stored alongside everything you need to decrypt it except a human memorable password. The system I have in mind is that the encrypted data would be stored with the key that was used to encrypt that data, only that key would have been encrypted again using the hash of the users password. There would then be another hash of the password also stored in the same place, but this hash would have used a different hash function.
The decryption process would be:
user enters password
the password is hashed using hash function A and that hash is checked against the stored hash to ensure it was correct
if the password was correct, you rehash the given password with hash function B to get Key 1
Key 1 can then be used to decrypt Key 2 which was used to encrypt a block of data
This way you could store unlimited encrypted data, all encrypted using different randomly generated AES keys that are all encrypted by the hash of the password (Key 1). Ideally you could give this block of data to anyone and they couldn't decrypt it without the password. You could also send the password hash and a single block of encrypted data over a network and the end user can decrypt it on their end assuming they know the password.
I know the standard response to these things is don't roll your own, but I would like to know out of interest what the security concerns are for this system. Primarily Could it work and what pair of hash functions should be used and why? I am also interested in what the standard way to achieve this would be.

Password storage?

Okay, I have an extremely basic knowledge on how to make a secure, login system.
If you try to login, you get the attempted password, hash it to example md5, try to match the hashed password with the password stored on some sort of database/server (also hashed).
When registering it stores the md5 hash on the server, but NOT the original. So even if it's breached it's untraceable. (Even though there are services that have a database of hashes, and can attempt to reverse).
My problem is: How to store the hash? If i used a mysql database, it would have the details hard coded inside, and I don't code in php so can't really make an online one.
How would I hide the mysql credentials in my software?
Don't generate your own salts.
Research PHP password_hash and password_verify functions, which do pretty much all you ask, automatically and fairly securely in PHP 5.5+.
http://php.net/manual/en/function.password-hash.php
Also
http://php.net/manual/en/faq.passwords.php
You can also use this on PHP 5.3 with a good fix made by IRCMaxwell. Here: https://github.com/ircmaxell/password_compat
MD5 has been severely compromised and there are various rainbow tables and collision functions that can find out what an MD5 hash string originally was (down to a handful of options, which are peanuts to compute). Do Not use MD5 for hashing private data.
"How to store the hash"
By Storing the hash I think you mean that you want to store the:
$hash = md5($password_plaintext');
if this is so, then you can store this in a MySQL VARCHAR field, on the record, typically people submit login info with a username password so the username is used for the MySQL engine to find the row, and then the password hashes are compared to see if they match.
Using password_hash(), you would look up the username, then retrieve the associated password hash field value (just that value), and then compare the hash with the plaintext password from the form with:
if(password_verify($posted_login_password_plaintext, $hashfromDatabase)){
//if TRUEPassword matches.
}
That's all you need. You do not need and actually should not store any salts for hashing with.

MySQL ENCRYPT field to MD5

I am having trouble to transfer email user account which is saved in MySQL to another server. Here is the detail:
I have an old email server which using MySQL to store user account information. The password field uses MySQL ENCRYPT function to save the users password. So if I want change the user's password I can do:
UPDATE `mail`.`users` SET `password` = ENCRYPT( '12345' ) WHERE CONVERT( `users`.`email` USING utf8 ) = 'g#veecall.com' LIMIT 1 ;
Then the new password "12345" saved in the table as string of " 2I6JOeg.JukJ."
Now I build a new server using iRedMail. When I try to transfer user account I have trouble to transfer the password field. Because the iRadMail/dovecot is using MD5-CRAM to encrypt the password then save it in the MySQL. All the password string is started with "$1$".
So, is there a way to make the MySQL encrypted password string "2I6JOeg.JukJ." convert to MD5 hash "$1$................."?
Thanks for help.
Firstly MD5 is a hashing algorithm not a encryption algorithm. The main reason for this is that it is virtually impossible to calculate the original password from the hash value generated by MD5. MD5 creates a hash value and it basically a trap door function in other words it is a one way function.
Encryption will allow you to encrypt and decrypt IF you knew the key. Big difference. Hope you understand that.
Now for your problem.
Unless you have the original password before it was encrypted there is no reasonable way besides brute force to create the MD5 equivalent of the password. The encrypted passwords hash and the unecrypted/plain text password hash will be two different think.
If you can decrypt all the passwords you currently have to their plain text form you can perform the MD5 hashing on the plain text values. If you cannot get the original plain text then you are out of luck.

Hashing in phpMyAdmin

I have a mySQL database and I am using phpMyAdmin to access it. The database has table employees with fields like name, address, email and password.
Initially the password field was just VARCHAR (20). But now I want to hash my password with SHA-256 hashing technique.
I do not have much experience with databases so I want to know is -
can I hash all my current employees passwords without affecting the other fields or the entire table?
In future when I am entering data in the database (from a web application), where do I write the hashing function to hash the password? i.e. does the hashing occurs at the front end and then the hashed password is stored in the DB or the password goes to the DB where it is hashed and then stored.
Solution and Suggestions are appreciated.
Q1: Can I hash all my current employees passwords without affecting the other fields or the entire table?
A: Yes. But you need to alter the size of your column of the password by 40-42. You will use the PASSWORD( ) built-in function to encrypt your password
ALTER TABLE tableName MODIFY `password` VARCHAR(42);
after that you can now update the password column
UPDATE tablename
SET `password` = PASSWORD(`password`);
ex.)
abcde12345 => *20B30AFAF441808B50273EDA287132EC25B02DE2
Q2: In future when I am entering data in the database (from a web application), where do I write the hashing function to hash the password?
A: In your INSERT query
INSERT INTO tableName (name, address, email, password)
VALUES ('aa','bb',''cc,PASSWORD('abcde12345'))
when you want to search for the password, encrypt first the text:
SELECT *
FROM tableName
WHERE `password` = PASSWORD('abcde12345')
one more thing, don't forget to escape your Password column with backtick since it is a MySQL Reserved Word.
You can hash the password in php and then store it in the DB:
$pwd = hash('sha256',$_POST['password']);
MySQL does not support sha256 function so you need to hash by code and then store/update your password table. Otherwise you can consider this http://stuge.se/mysql-sha256/
can I hash all my current employees passwords without affecting the
other fields or the entire table?
Yes. For example, if you’re going to use the SHA-1 hashing function, you can add the corresponding column and hash all your passwords with one query:
alter table employee add column password_hash varchar(40);
update employee set password_hash = sha1(password);
It is assumed that your plain text password column is called “password”. You can drop the original column after you have the hashes, of course (and, most likely, this is exactly what you want to do next).
However, I strongly advice you to read more on hashing algorithms and pick something better. For example, you may want to use a different hashing function and/or add salt.
In future when I am entering data in the database (from a web
application), where do I write the hashing function to hash the
password? i.e. does the hashing occurs at the front end and then the
hashed password is stored in the DB or the password goes to the DB
where it is hashed and then stored.
Most commonly, the hashing occurs on the server side each time a user logs in. Then an authentication session is created and the session ID is stored in the user’s cookies (so you never store the password or it’s hash on the client side, however, you transmit it to the server when the user logs in, and this is why it is good to use SSL at least for authentication).
In some cases, you may want to even build a separate authentication backend which only accepts password hashing requests (so even if someone cracks into your system, the exact hashing schema would be still secret until they crack the hashing backend as well, which can be a lot harder if it’s built carefully enough). However, you would only need something like this in case you really care a lot about the security and it is really important. Otherwise the typical server side hashing will be enough.