MySQL Column for Encryption - mysql

I need to build a small private app. I want to store a piece of personally identifiable information (it's an internal account number -- not an SSN or anything like super-sensitive) in a table that "encrypts" it.
I put encrypts in quotes because I wish the data to be stored as follows:
stored in a way that if someone physically looked at the table data the piece of info would not be discernible
stored in a way that if someone did a simple query select the resulting data output would not not be discernible
yet when I write my own query select statement I can still decrypt the data and present it in a readable fashion
In other words, I want it only moderately encrypted so that I can still decrypt it and read it. I know MD5 hashing locks the value from ever being read. I want something less than that.
Thanks

MD5 is NOT encryption. It's hashing.
If you don't mind passing the crypt key around in each query, it's trivial to have this in MySQL:
SELECT AES_DECRYPT(crypted_field, 'crypt key goes here') AS decrypted
and
INSERT INTO yourtable (crypted) VALUES (AES_ENCRYPT('some string', 'crypt key'));

I think what you're looking for is "Symmetric Key Encryption". You can use a key to encrypt your data, and the same key to decrypt it as needed (as opposed to a hash function which as you said - makes the original data irrecoverable). In MySQL I would take a look at the AES_Encrypt and AES_Decrypt functions.. Hopefully that gets you pointed in the right direction!

MySQL provides both DES and AES encryption. You will need to figure out key management, but the encryption algorithms are available.

Related

Hashing data at database layer or application layer

I will take example of my case . I am using PostgreSql .I have gone through postgresql crypt() function documentation .
This function is provided as extension for postgresql .
If i migrate my data to another database by different vendor , Will the passwords still be evaluated properly or not ?.
If i try to compare the the hash generated in postgresql with hashing utilites provided by mysql/mongodb using same source string will it evaluate to be equal or not
According to docs, crypt()
Calculates a crypt(3)-style hash of password. When storing a new
password, you need to use gen_salt() to generate a new salt value. To
check a password, pass the stored hash value as salt, and test whether
the result matches the stored value.
It means if you migrate your data to another database (if stored hash value is part of your data of course), the result of comparison will not depend on the system.
Can you move up the encryption/decryption to the application level? In that case, you can migrate data as encrypted and other database vendor don't need to worry would consider them as normal data?
Another option is to encrypt disk level instead of applying encryption at a database level.
After going through lot of posts it came to me that encrypting at application layer is better . like for example to encrypt passwords in java, we can use jBcrypt library .

Is there an --des-key-file equivalent for AES?

When you use the DES_ENCRYPT/DES_DECRYPT function in mySQL you can point to your keyfile from my.cnf using the --des-key-file variable.
I thought this should also exist for
AES_ENCRYPT/AES_DECRYPT
So I searched for hours but couldn't find it: is there an equivalent for AES for this?
As far as I can tell from the documentation, no such option exists for AES_ENCRYPT. Instead, you are supposed to pass the key as a parameter directly in the query.
This answer on DBA.SE suggests writing a User Defined Function that returns the key as one possible work-around.
Alternatively, you might want to consider not using the MySQL AES functions at all, and instead just doing all encryption and decryption in the client application. One potential advantage of such an approach is that, in order to obtain and decrypt the data, an attacker then needs to compromise both your database and your application.

MySQL Uncompress issue

I am facing issue with MySQL, UNCOMPRESS function.
I have table named as user and user_details stores COMPRESS values. In this case before search for values from the user_details i have to UNCOMPRESS it.
But issue is after I do UNCOMPRESS, search become case-sensetive.
Like.. e.g
If I tries below sql, it will only search for values which contain CAPITAL TESTING word and ignore small case testing word
SELECT * FORM user WHERE UNCOMPRESS(user_details) LIKE '%TESTING%'.
I want case-insensitive search.
But issue is after I do UNCOMPRESS, search become case-sensetive.
This is because COMPRESS() "Compresses a string and returns the result as a binary string." (emphasis mine)
When you perform a LIKE operation on a binary string, a binary comparison will be performed (which is case-sensitive).
You may be able to circumvent this by putting a CAST() around the COMPRESS() statement.
But you probably shouldn't be doing this in the first place. It's an extremely inefficient way to search through huge amounts of data. MySQL will have to uncompress every row for this operation, and has no chance of using any of its internal optimization methods like indexes.
Don't use COMPRESS() in the first place.
Try this:
SELECT * FROM `user` WHERE LOWER(UNCOMPRESS(user_details)) LIKE '%testing%'
But as Pekka well pointed or its very inefficient . If your using MyIsam Engine another alternative is myisampack which compresses the hole table and its still query-able.

How to dump database from mysql with sensitive data removed or corrupted?

I am using mysql. Some of the tables contain sensitive data like user names, email addresses, etc. I want to dump the data but with these columns in the table removed or modified to some fake data. Is there any way to do it easily?
I'm using this approach:
Copy contents of sensitive tables to a temporary table.
Clear/encrypt the sensitive columns.
Provide --ignore-table arguments to mysqldump.exe to leave the original tables out.
It preserves foreign key contraints, and you can keep columns that are not sensitive.
The first two actions are contained in a stored procedure that I call before doing the dump. It looks something like this:
BEGIN
truncate table person_anonymous;
insert into person_anonymous select * from person;
update person_anonymous set Title=null, Initials=mid(md5(Initials),1,10), Midname=md5(Midname), Lastname=md5(Lastname), Comment=md5(Comment);
END
As you can see, I'm not clearing the contents of the fields. Instead, I keep a hash. That way, you can still see which rows have the same value, and between exports you can see if something changed or not, without anyone being able to read the actual values.
There is a tool called Jailer that is typically used to export a subset of a database. We use this at work to create a smaller test database from a production backup, with all sensitive data obfuscated.
The GUI is a bit crude, but Jailer is the best alternative I have found so far.
You can simply unselect the sensitive tables or columns and get a full copy of the rest. Jailer also supports obfuscating data during export - you could for instance md5 hash all user names or change all email addresses to user#example.org.
There is a tutorial to get you started.
ProxySQL is another approach.
Here is an article explaining how to obfuscate data with proxysql.
https://proxysql.com/blog/obfuscate-data-from-mysqldump

how to encrypt emails in mysql database but still be able to query them?

I want to store the email addresses of users in a MySQL database using encryption to ensure that they won't be made public if the database gets compromised. I believe if I encrypt them with mysql's AES_ENCRYPT() function I can not create an index in an INNODB table because I have to use a BLOB datatype. If the table gets very large selects it will take a long time.
What is the best solution for securing email address but still being able to query them fast and preserve them as unique values in the column?
When a user registers on your site, use AES_ENCRYPT() to encrypt the email.
INSERT into users (email) VALUES (AES_ENCRYPT('someemail#example.com', 'aeskey'));
When you query your database, you can call the AES_DECRYPT() function like this:
SELECT AES_DECRYPT(email, 'aeskey') from users;
If you hash the addresses with SHA-256 or something similar, you can still index your tables, you can still do fast address lookups (when a user searches for example#example.com, you'll just hash the input and select matching hashes in the tables).
ssh uses a very similar hashing trick. (Look for the -H option in that manpage for details.)
AES_DECRYPT(email, 'secretkey') and AES_ENCRYPT(email, 'secretkey') is optimal solution,
I am not 100% sure about beeing unique after encryption but theory said if email is unique encription should be unique