I have been using the PHP mcrypt module for encrypting sensitive data at my company. This has been working well. However, I have been requested to create a new master password which should be able to decrypt any data. The problem is that this master password would have to be hardcoded in a script file. Please correct me if I am wrong but the only secure way seems to be to hardcode a public key in the script and use it to encrypt data while keep the private key secure and use it to decrypt only when needed.
mcrypt does not seem to have an implementation for such a scheme. Does anybody know of a library (PHP module or pure PHP) which would do this?
I suggest taking a look at the PHP OpenSSL bindings, and in particular the openssl_public_encrypt() function. You could indeed embed a master public key into the script, and have the script encrypt each user's AES key with this public key. Keep the corresponding master private key in the company safe.
Should you need the master decrypt function, you would pull the encrypted user key, decrypt it with the master private key and then decrypt the original data.
There's a PECL extension for that. http://us2.php.net/manual/en/book.gnupg.php
You can also use gnupg command line tool from php, if it doesn't have to be very fast: http://devzone.zend.com/article/1265
I haven't tried either method.
I don't see how that would work. Any two-way encryption function is only going to decrypt when fed the specific password used to encrypt (unless you're the NSA and you put back doors in the algorithms). You can't have two passwords decrypt the same file (unless there are hash collisions, but that's not something you can make happen easily).
As far as storing your master password in the program, it would be much better to store it in a separate file the program reads in, so you can use tighter OS-level security on that file.
Keep in mind mcrypt is not public key cryptography. With public key cryptography, you might be able to do what you want, though. For instance, with PGP/GPG, you can encrypt a file such that three different users can decrypt it using their private keys, without knowing each other's private keys. So you can have a virtual user with the master password that can decrypt everything.
Another option would be to hold two copies of all encrypted data; one encrypted with the user's password, and one encrypted with the master password.
Just to be sure of your requirement of this master password,
Is it expected to be used only as a 'encrypt this' command that will 'seal' something
which can then only be opened by someone knowing the private key in question? Or,
Is it something you expect to open any encryption done in the enterprise?
I just want to be sure your phrasing is not to be interpreted in this second way
your phrase 'decrypt any data' sounds dangerous
(and not-feasible/practical with asymmetric key encryption)
Update based on the comment.
You are planning for two copies of the data each encrypted with different keys
one copy is to be encrypted with the master public key
can be decrypted with anyone having the master private key
the master private key must then be secured (public key is not critical)
the second copy is to be encrypted with the Rijndael 256 key
purpose is to allow the master to decrypt the data whenever required
particularly, in the absence of the individual who encrypted it
This approach will work for,
easy access of the data by the individual with the Rijndael key,
without need for intervention by the master private key owner.
And, when the master private key owner is trusted with the secrecy of the data.
Your scheme will need to update the master copy (deleting the older one and re-encrypting a new one) every time the user updates their copy.
However, if the user data is trusted with the master (as is clearly the case here),
an easier approach would be to issue the Rijndael key from the master
The master could keep it encrypted with the master-public key itself
The data can then be encrypted with just the issued Rijndael key
it will always be accessible with the master-private key
which can open the user's Rijndael key
If the user needs to sign the data, that can be accomplished separately in the process.
It will save you from keeping double copies and maintaining them.
To sign the data, the user could have a a key pair generated by them.
Before encrypting the data with the Rijndael private-key
the master-public key encrypted with the user-private-key can be appended to it
the user-public key shared with the master (at least)
will be sufficient to authenticate that the user has provided the data
In a worst-case scenario, if the user is unavailable and the key confirmation fails,
the master may be trusted on the authenticity of the data -- which can still be decrypted
Related
I'm looking to encrypt secure data, such as social security numbers, but there will be other people (e.g. my web host, employees) who have full access to the source code of the encryption. Is it possible to somehow encrypt using a key that does not need to be included in the original source, such that only I (who would know the key) would be able to decrypt?
The way you're thinking about it, no, it can't be done. No, just saying "asymmetric encryption" won't help either. When certain operations are gonna accrue on those data (by a legitimate user) you'd have to decrypt them and wherever your decryption key is stored you're code is gonna try to access is it (meaning that any admin on the server can access it too).
Of course if you want to encrypt the clients' data in a semi-permenant fashion (the users won't be able to alter or read the data again) then yes, the people who suggested asymmetric encryption with you (the developer) keeping the private key secret, are 100% right.
A way of doing it is the following:
User signing up: Generate key pair (private & public) store the public in the database, encrypt the private with the user's password's hash and store it in the database. Now hash the hashed password again and store it in the database.
User entering sensitive data: Take the input and encrypt it with the public key from the database (and as suggested by Hugo, use the user's password as the passphrase for the process) and store it in the database.
User accessing/editing his information: Take the user's password, hash 2 times and authenticate him, then if he's a legitimate user then use the first hash to decrypt the private key and use the private key to decrypt the data (Using the user's password as the passphrase for the process).
Keep in mind that there's no 100% security, take this idea and improve it.
Update: I talked to a friend who works with a payment processing company, he described the real life situation as the following:
There's no way around it, the people running server will always have access to the data, encrypted or not. You have to keep the private key some where. We keep SSNs and Credit Card Numbers in a separate data database on a separate server that has physical security and only authorized people are allowed to access that server. We don't query the secure database except using scripts on the same server and those scripts provide us with bare-minimum API that will handle all the payments. In our plain-text database we keep only a portion of the information (XXXX-XXXX-XXXX-4569) for viewing purposes only. All editing, reading, appending, adding, removing happens on that secure server (secure software, locked doors, security cameras) through the API.
The short answer is no.
You could, however, use assymetric keys, such as GPG keys (or SSL keys).
You have a private and public key. The public key is used for encrypting, and the private key for decrypting. You could include the public key in the source code, and only keep the private key to yourself.
you could use mcrypt
example encoding:
$key = "mykey";
$data = "my data";
$enc_data = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_ECB, md5($key));
example decoding:
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $enc_data, MCRYPT_MODE_ECB);
the $key can be given outside of source code or remembered and given through an html form.
I have a website that users submit sensitive data to it then a php script encrypts these sensitive data using rijndael 256 and store it in mysql database
the problem is that I want to store the key in a secure place that can be accessed only by the php script and not to be seen by any other one
Depends on how high a security you need for the data. You could consider having a different security key for each user, by possibly encrypting the data that identifies that particular customer and attaching it onto the 256-bit encrypted key. But better still would be split the key up and insert that encrypted data throughout the key. Makes it more complex to decipher. This would mean if a programmer has access to the key the programmer can't simply decrypt everyones data without having access to the customer encrypted data as well which would be different for every user.
And yes it is true that the programmer can still echo the key out to the screen but they would ALSO need the customer encrypted data for each customer they want to decrypt the data of.
You could also consider Public and Private Key Encryption instead if applicable. The customer/user could generate their own keys. Customer places the public key into a form on the website which gets stored in the database, then the customer/user would have the private key to decrypt the data. You use the public key to encrypt the data. This would mean each user/customer would have their own set of keys. The Private key could possibly be even placed on a keycard and hooked to the computer to verify access.
More information # http://en.wikipedia.org/wiki/Public-key_cryptography
One alternative would be to have the PHP script call an external script (doesn't necessarily have to be another PHP script; it could be anything) that would have access to the key. As long as no one has write access to the external script, or read access to it if you hard-code the key into it, then it should be relatively secure. If you store the key in a separate file, that file needs to be readable/writable only by the owner of the external script.
You could encrypt/decrypt with certificates and have the server request a password for the certificate upon bootup.
The good thing is that your key is only in memory and can be different for every installation/server.
However, this method is quite a pain and generally only works when you have your own system administrators/are not dependent on a third-party hosting provider.
The intermediate solution to generate an encryption key per section/user/client in your database and encrypt the sensitive data with this per client key. These per-client keys are encrypted with a master key and stored in your database, while the master-key is stored somewhere in on disk with minimal priviliges.
This will not safe you when your server gets fully compromised, but does limit the risk in case of -for example- a data-leak/partial compromise.
If the problem is you don't trust a) the programmer or b) the system administrator, you are out of luck.
Or: How to store encrypted data for a bunch of users?
I admit, it's a silly question, a private key is limited to only one person as the term already implies. But I have the following scenario:
User Tom enters data that needs to be stored encrypted in a database. The user decides he wants to make this information available to Jim and Bob. The users John and Jayne must not be able to decrypt it. Of course also not to user Tim who hacked the server and has access to the encrypted data and the scripts that do the encryption/decryption.
I think the public key/private key approach with PHPs openssl_public_encrypt function won't work here as two users need to have that "private" key to decrypt the data.
I guess this a rather general question, but if it's important, it must be done in PHP (and MySQL maybe).
That's how it done in OpenPGP (and, other systems):
- you are generating secret symmetric key, which is used to encrypt the data itself;
- then, this symmetric key is encrypted with Tom's key;
- also, symmetric key can be encrypted with Jim's and Bob's public key, allowing them to decrypt the key and after that to decrypt the data
PHP provides a function for this - openssl_seal(). This function takes an array of public keys, and encrypts the data so that any one of the corresponding private keys can be used to decrypt it (using openssl_open()).
I don't know libraries in PHP. But in general the procedure is as follows:
Data is encrypted using a symmetric key
For each recipient, key is encrypted using the public key of recipient
All this is saved in a PKCS#7 file structure
There should be some results when looking up "PHP and PKCS7"...
Use a data encryption key (call it Kgeneral) that's distinct from Tom's key.
Encrypt Kgeneral with Tom's public key and give the result to Tom - he can use his private key to decrypt it and obtain Kgeneral.
If another user then needs access to the data, Tom (or your application) can then encrypt Kgeneral with his public key, and give him access that way.
I have sensitive information stored in a database which goes through the following process:
user enters information through webform.
information entered is encrypted using AES 256-bit and salted using unique id to each user (although this is stored in the same database, and sometimes same table).
The encrypted pass 1 data is THEN parse through openssl_pub_encrypt function
data is stored in mysql database with fieldtype: varbinary
to decrypt the data:
the private key is stored OFF the server and must be uploaded in a temporary file EVERY time the data needs to be retrieved
the code runs through openssl_private_decrypt
the code is run through a decrypt with the same salt and AES-256 script.
What I am wondering is running the information through the AES-256 bit in this instance even worth it (since key is offline, and the salt is already stored within the table if the data ever became compromised)?
Salting makes no sense on symetrically encrypted data, which is what you've got with AES-256. If anything, it'd just make any potential cracker's job easier by putting some known plaintext within the data. After all, ANY key will "decrypt" the data, but only one key will produce the original data. By putting a chunk of known plaintext in there, you've made it far easier to determine if the key being used is valid or not ("is salt text there, if so key is valid").
If the data's so sensitive that you have to take these precautions, I'd be more worried about the exposure window when the key file is actually stored on the server, as well as the traces it will leave behind in memory and on-disk, even after you've removed the file.
There is no point encrypting the data with a key that is available in the same place as the encrypted data.
However, it would be an advantage if you used a separate public/private key pair for each user - that way, if a private key leaks, you are only exposing one of your records instead of all of them.
By the way, openssl_public_encrypt() / openssl_private_decrypt() is not really the right function to use - it's a lower-level function intended for encrypting randomly generated keys, not to directly operate on the data. The right, higher-level functions are openssl_seal() / openssl_open().
I am new to AES encryption but trying to build a solution which:
Accepts consumer data
Encrypts that data using AES and a
"public" key
Store that data in a MySQL database
Have the ability to pull and decrypt
the data ONLY with a private key
(stored on my personal machine, not
the server itself).
I realize this may be overkill but want to be overly protection for my consumer data.
A few things to note:
This is not credit card information
so please don't write telling me
about PCI-DSS, it is other form of
personal information all under 500
characters in length for each field.
I may store pieces of the consumer
information and others in a second
database tied together by a unique
member ID for additional security.
Incoming MySQL calls can only be
made to my server directly from my
static IP.
SSH root is disabled, ports changed,
and so on so I feel my server is in
faily good shape to prevent any
"basic" misuse.
I have looked for articles online and SO but have not found much in terms of keeping the private key off the server completely. Even if I need to keep on the server itself - thoughts or suggestions for how to move forward are appreciated.
EDIT - CLARIFICATION
Just to be more clear, the goal I am trying to achieve is this (in very basic form):
Customer enters his/her phone number
online.
The phone number entered is encrypted
online using key A and stored within
the mysql db
The customer will never be able to
see the full phone again at this
point, but can certainly update it
(going through key A process a nth
time)
As a system administrator, I am only able to access the data by either downloading and decrypting the data on my local machine (that or I must first upload a temporary file which is used to then decrypt the data I need).
EDIT 2 - I'm a an idiot
I am using Andrew Cooper's response below but am having trouble getting my script to read the contents of the .pem file I generated. Based on the code below - how would I get $public key to correspond to a specific .pem file on my server?
<?php
if (isset($_SERVER['HTTPS']) )
{
echo "SECURE: This page is being accessed through a secure connection.<br><br>";
}
else
{
echo "UNSECURE: This page is being access through an unsecure connection.<br><br>";
}
// Create the keypair
$res=openssl_pkey_new();
// Get private key
openssl_pkey_export($res, $privatekey);
// Get public key
$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];
echo "Private Key:<BR>$privatekey<br><br>Public Key:<BR>$publickey<BR><BR>";
$cleartext = '1234 5678 9012 3456';
echo "Clear text:<br>$cleartext<BR><BR>";
openssl_public_encrypt($cleartext, $crypttext, $publickey);
echo "Crypt text:<br>$crypttext<BR><BR>";
openssl_private_decrypt($crypttext, $decrypted, $privatekey);
echo "Decrypted text:<BR>$decrypted<br><br>";
?>
EDIT 3 - maybe not 'idiot' but semicolons hate me
I had a semicolon misplaced. I am using the function: file_get_contents() but is there a more preferred method of reading in the data for the .pem file?
You should be able to generate the public/private key pair on your personal machine, and then publish the public key in your app so the data can be encrypted. In this way the server never sees the private key, and if the server is hacked the data is still safe.
You'll want to make sure the whole transaction occurs over SSL. The client side can generate a random session key, encrypt the data with that key (using AES), then encrypt the key with the public key from your app (using RSA), and send the encrypted data and key to the server. You could store the whole blob in one database field or two. The only way the data can be decrypted is to decrypt the key first, and the only way that can be done is by using the private key on your personal machine.
Update
Check out http://plugins.jquery.com/project/jQuery-Gibberish-AES. It's a JQuery plugin that appears to allow this type of scenario. I have no experience in using it, but it appears to me to be a good start.
New Update
Just to be clear about what I'm suggesting, and to address your edit:
You can't use only AES encryption. With AES there is one key that is used both to encrypt and decrypt. The key would have to exist wherever the encryption operation occurs, either in the client code, or on the web server. In the first case anyone can get your key. In the second case, if the web-server is compromised, then the key, and the data, are also at risk.
The solution is to use good, strong AES encryption in combination with public-key crypto (RSA). I'd suggest doing to the crypto on the client-side, for reason I'll outline below. Here, though, are the steps I'd suggest:
On your private machine create a public/private key pair, and keep the private key safe.
Put the public key somewhere in the code you send to the client.
When the user submits the form the client code:
Generates a random AES key (the session key)
Encrypts the form data
Uses your public key, and the RSA algorithm, to encrypt the session key
Discards the plaintext session key
Sends the encrypted form data, and the encrypted session key to your server
Your server accepts the encrypted form data, and stores it, along with the encrypted key, in the database.
You now have encrypted data in the database that can only be retrieved using the private key stored on your private machine. Even if the user somehow manages to capture the session key while it's in the clear on his machine, the worst that can happen is that that one record could be decrypted.
The reason I'd suggest this client-side approach is that it means that your server never see the encryption keys in the clear. If the same scheme where employed on the server-side then, theoretically, an attacker could be sitting on your server watching it happen. At the end of the day it basically comes down to how paranoid you want to be.
Following this scheme, when you want to retrieve the data you'd dump the required data, in encrypted form, from the database to your private machine. The for each chunk of encrypted data:
Decrypt the session key using the RSA algorithm and your private key
Decrypt the data using AES with the session key from step 1.
Anyway, that's the approach I'd suggest. I'm sure there's libraries out there to handle this.
Encrypts that data using AES and a "public" key
...
decrypt the data ONLY with a private key
But AES is a symmetric encryption algorithm - i.e. the same key is used for encryption and decryption.
Or do you mean you want to implement something like SSL, where some assymetric algorithm is used for encrypting a randomly generated key then the end points use that key for a symeetric algorithm? This kind of approach is only of benefit where the data to be encrypted is significantly larger than the keys used - is that the case here?
Have a google for PHP and RSA or ELGamal for assymmetric encryption algortihms. (note it'll probably be significantly faster and easier to program if you shell out to something like GPG to do the encryption - there are wrappers on phpclasses for this).
C.
... That doesn't strike me as possible. MySQL's AES_DECRYPT method requires the encoded message as well as the original key in order to decrypt something. This means that anyone that can get the encryption key can decrypt the message.