Providing encrypted data, and the means to decrypt it, insecure? - php

I'm developing an add on to a system I have that will allow my clients websites to pull data from it to display on their sites.
Now, most of the time the information being stored in the system is not in any way sensitive (because its just published to their website) but some users have set up tables that they want to manage in the system out of convenience, but not publish on their website - though they might want to make a request on it (ie, to check a customer has a login to their website perhaps, or to grab an email address). So I need to encrypt the responses to reduce the chances of someone getting the data that shouldn't have it.
My plan is that the user will identify themselves with a user ID, a public key, and the name of a query they want to run (which they will have defined in the system itself beforehand) - and the request will take a form something like this:
require("backend-api.php");
$myUserID = "bobs-restaurant.com";
$myPublicKey = "sdg136MAGHYasfadgHGQ"; //send this with the request
$myPrivateKey = "adgljavd8i1356avdilj"; //never send this anywhere
$queryName = "LIST_OF_DISHES";
$backend = new backend-api();
$response = $backend->getData($myUserID,$myPublicKey,$queryName);
$list_of_dishes = $backend->decrypt($response,$myPrivateKey);
//user then goes on to use the data in their code or maybe just display it as-is.
It has to be simple, because the users are either not going to be seasoned PHP'ers or they're going to be time poor, and using the system to instead of having to write their own content management solution.
Assuming the above user ID and public key were a match, and the query existed and returned data - I was going to have my system encrypt the response to a private key which is known to the user ($myPrivateKey) and which is known to my system, but never exchanged between the two in a request so that it couldn't be intercepted, and I was going to use something like this reversible encryption class to do the encryption.
The problem is, I'm going to have to provide users with the decryption class so that they can get the data out of the response.
So if Mr Malicious somehow obtains a user ID and public key belonging to someone else, and he has downloaded a copy of the decryption class from the tutorial/user manual on my systems website, am I right in saying that he wouldn't need to know the private key, because he could just work out how to decrypt it from studying the code?
If the answer is yes, what is it that I haven't thought of that will prevent that from happening?

Mr Malicious wouldn't know how to decrypt anything from simply studying the code. The best he could do would be to brute force the "private key".
I put that in quotes because this actually isn't public key encryption or cryptography. This would only be public key cryptography if your server encrypted the data using the client's public key, then the client decrypted that using their private key. If that were the case, the server would have no need to know the private key at all. But it sounds like you're using the public key for something entirely different.
What you seem to be talking about here is symmetric key cryptography (using the same key to encrypt and decrypt the data).
If you use a strong encryption / decryption method, your method seems fine, but I would go with an existing algorithm such as Blowfish or AES.

A good encryption method never relies on people not knowing how it works for its security. In fact, if you're going to use encryption, you never want to try and make your own. If the method used to encrypt something is simple, like ROT13, then yes, knowing the method will allow an attacker to decrypt it pretty easily.
However, an encryption method like AES is widely known, published, and used all over the world. Everyone knows how it works, but without knowing the keys used to encrypt and decrypt, it's hard to break.
The biggest issue that you have is that both the encryption class that you linked, and AES are symmetric or pre-shared key encryption methods. This means that you must use the same key to encrypt and decrypt the data. This doesn't work for your purposes, because you and your users don't know the same key. If you have a way to know the same key, check out mcrypt for PHP
Otherwise, use asymmetric key cryptography. This works using the method you described, where something can be encrypted using a public key that anyone can know, but only decrypted by the person with the private key. The easiest version of this to use is GPG, and it's possible to use it in PHP, although probably more work to setup. See this article

Related

Only require password once to decrypt files at different times?

User's content is encrypted, but needs to be decrypted. There are multiple files that need decryption to be viewed, and they will definitely not be viewed at the same time.
I am currently encrypting by using the user's plaintext password to encrypt a randomly-generated key, which encrypts the user's data. The password is hashed and verified normally before doing anything. I am using PHP's aes-128-gcm openssl_encrypt() function.
My current system requires a password every time the user wants to read a file.
I have thought about decrypting all of the content at one, but this doesn't scale well. I have also thought about storing the user's key as a cookie, but I'm worried about security.
Is there a standard way to do this?
Thanks!
The first thing to do is separate the users password out of this. You'll have to decrypt and re-encrypt all their files. There may be other ways around this such as allowing only new files to use this system. But that is very use case specific, such as how long do you keep their files, what is the turn over on them etc..
In any case this is a way to do that:
Encrypt the files they submit using a password you generate.
Store this password in another file we'll call it key.txt for now. Encrypt this file using the users password.
When user logs in (if they don't have it stored) take their password, decrypt key.txt and get the generated password.
Now you can save this generated password anywhere you want, without affecting the users account.
What they see (the end user experience) will look like always they go to downlaod a file, put their password in and get the file. They wont ever know you did this, which is nice for them.
So problem one is fixed.
Now where should we store this?
You could simply store it on the server in the DB. This sort of depends on how confidential the data is, and how secure your server is. Your ultimately responsible for the security of someone else's data, at least this way you can control it.
Make a table with these fields
user_id | ip | password | last_access
When a user goes to download a file, check their last access time and IP address to invalidate the password and make them refresh it. This is very easy to setup and totally under your control. If you save the encryption key, it will always have some level of vulnerability at least this way its all under your control.
Even if you don't want to store it in your DB, the biggest disadvantage here is if someone gets a hold of that table, but if they do that and your storing important data you probably have plenty of problems already.
At least use the first part as that solves a big problem with tying this to their actual account password. Even if a hacker gets the file password from the client (stolen cookies etc.) because it's separate, having that alone wont let them login to your site like the account password would. I am assuming here, a user must login to even get to the download part. Using the same password for both gives them them access to both the means of the getting this data and the method to download it.
To be clear, their is an argument to be made about storing it on the client side. Then if your site is compromised there is less chance someone could get a hold of the password as it (depending how you do it) only exist in memory on both the client and server etc. It puts the responsibility on them.
ASYMMETRIC ENCRYPTION
You could also use asymmetric encryption. Currently it looks you are using AES, which is fine, but it's a Symmetric Key block cypher. Basically there are three common forms of "encryption" (in vernacular):
Hashing (which really isn't encryption) - md5, sha1, sha256 - these are one way, can't be decoded. They have fixed lengths, and always encrypt to the same thing. It's common to see this for file checksum (for validating the contents of the file), Block Chain, Passwords or anything else where you need to compare two "encrypted" values.
Symmetric - AES, 3DES, Blowfish, Twofish - anything you need to encrypt and decrypt. The same key can do both. Generally these will encrypt the same thing to different values each time, because of the IV.
Asymmetric - SSL, DSA, RSA, PGP, used in Crypto currency wallets, TLS etc. With these you have 2 keys, a public one and a private one. The keys cannot decrypt their own encrypted data, only the other key can. So with this if you have one key on the server and the client has the other. You can encrypt their files using your key (decryptable by only their key) and you don't have to worry so much about someone getting your key as it won't allow them to decrypt the files. You can give one key to the client, who can use that key to decrypt their data you encrypted (even without your key). These also encrypt to different "Stuff" each time you use them.
So you can see Asymmetric form has a few advantages to use in a two(or more) party system. It also has the benefit that you don't need their key to encrypt a file. All you need is your part of the pair. So for example if you generate data for them and wan't to encrypt and later have them decrypt it with the same system, you can do that with no issues. This probably eliminates a step, as you would need to ask them, or keep track of their Symmetric anytime you wanted to encrypt something. Here you just need your part of the key pair.
It really isn't much harder to implement (on the server), its just harder to understand what it does. That's why I decided to add this, without this knowledge (which you may or may not already know) it's hard to use these terms and have them make sense. The only real disadvantage for you (if you call it that) if you used Asymmetric encryption, is if a client loses their key you would have no way to decrypt the file. So I would make sure they know to back them up in a secure place. It's the same problem that you see in the news when it comes to losing a crypto currency wallet which is encrypted Asymmetrically
As I said most of my knowledge has to do with encrypting and dealing with data on a server. So I am not sure how to tie that in to the "client experience". I do know for example how to use RSA keys for password less login for SSH etc. Which is kind of the same thing but not quite.
Hope it helps!
they will definitely not be viewed at the same time
Wouldn't the most secure answer here be to simply require the password every time? I would assume (although I'm sure this isn't the answer you're looking for) that simply asking for the password each time might be the best solution.
Although it may be tedious for the user, I would also assume it imparts some sense of security - since it's not quite as simple as logging in (as the files are encrypted).
From my perspective, I would argue that encrypted files should not be mass decrypted anyways?
Sorry, I know this isn't the answer you're looking for - but if you have more information about your motivation, maybe then a more reasonable solution can be found?
Don't do decryption on the server-side - do it client side. It is safe to keep the user's password in memory on their own device.

Electronic signature requirements [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Hello Stackoverflow community,
I have a difficulty regarding electronic signature and especially how to apply the law of Singapore in terms of technical requirements.
By law, Singapore accepts electronic signatures if the signature is:
unique to the person using it;
capable of identifying such person;
created in a manner or using a means under the sole control of the
person using it; and
linked to the electronic record to which it relates in a manner such that if the record is changed, the electronic signature would be invalidated.
We are able to make the electronic signature via HTML5 canvas then save it as a data base64 string. That means point 1., 2. and 3. are ok.
Problem comes with point 4., we can indeed combine the signature and data in an encrypted string however, as we have both the signature and data we would be able to edit the data and create a new string:
|id|name|price|signature|final_hash|
------------------------------------
|12|test|40000|data:base|3edcde4642|
So we thought of another way, which is to mix some parameter we do not know into the final_hash such as the IP address of the signatory, his/her user agent... however, as we do not save these values, this means that we will not be able to check later on if some values were modified.
That's where we are stuck, do you have any idea on how to do this? To me, it seems impossible to satisfy both being able to check if no data was modified and being unable to modify the data later, but I may be wrong of course.
Thanks a lot for your help!
Note: I use the term "document" to refer to whatever it is you want to sign.
Some Misconceptions
First off, what you get from using HTML5 canvas or similar approaches is not a signature but a fingerprint. What I mean by that is that it identifies the client, but it cannot sign a document (at least not alone). Two caveats:
The fingerprint is of the browser, not of the user.
There will be collisions. In fact, for the sake of privacy, there is a push to make fingerprinting browsers harder, mainly because companies could use fingerprinting to track you without cookies.
You should not sign by concatenating the fingerprint to the data. That is not a signature, that is a salt, and not the best approach to salt either.
By the way, ClientJS is a good tool to create browser fingerprints
Your requirements
unique to the person using it;
capable of identifying such person;
Those requirements spell "Identification". It means you need an ID of the person.
created in a manner or using a means under the sole control of the
person using it; and
This requirement spell "Authentication". It means you need to verify that people are who they claim to be. You probably have seen the theory, you do this by: a) something the person is (i.e. biometric) b) something the person knows (i.e. a password) or c) something the person has (i.e. access to an email account, a cellphone, etc...).
It bothers me that you seem to be using browser fingerprint to do both identification and authentication. This could make it too easy to fake requests to appear to be another user.
Usually what you would do in this situation is to have a traditional authentication process with username and password, then issue a cookie. Why do you avoid that?
linked to the electronic record to which it relates in a manner such that if the record is changed, the electronic signature would be invalidated.
This requirement spell "Signature". This probably means that the electronic record will be public and we want to have protection against counterfeits.
it seems impossible to satisfy both being able to check if no data was modified and being unable to modify the data later
The general idea is to have the signature become invalid when the document is modified. If you want to make the modification official, you need to create a new signature.
In order to prevent third parties to create a signature from the modified message you need to add some secret key. Now, that raises two questions:
Should third parties be able to verify the signature? If they should, you need an asymettric algorithm.
Should the documents be protected against you (or people with rigthful access to the server)? If they should be protected, it suggests you need a secret for each user. The simplest solution is to have a password.
Asymmetric solution
To implement an asymmetric solution in PHP I suggest to use phpseclib.
Follow their example to create a key pair:
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$pair = $rsa->createKey();
$privatekey = $pair['privatekey'];
$publickey = $pair['publickey'];
The code will use entropy collected from the server to generate the key pair.
Then you can use it to do simple RSA signature and verification.
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey('...'); // private key
$plaintext = '...';
$signature = $rsa->sign($plaintext);
$rsa->loadKey('...'); // public key
echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
If you need to verify signatures on the client, you can use jsrsasign.
For your use case, you only need one key pair for the server. The concept here is that the server is signing the document. If the signature matches, it means that the fingerprint is correct.
Either way, you should keep your private keys secret (do not ever send it to the client), and you can share the public key with whoever you need to be able to verify the signatures.
Using this, the server can sign the document that identifies the user / client (including the fingerprint, for example) and publish the document plus the signature. The document would be perfectly readable (it is not encrypted), but if somebody modifies it, the signature would no longer be valid.
To verify the signature they need the public key. However, the public key is not useful to create a fake signature, to do that they would need to get the private key.
Symmetric solution
The main advantage of a symmetric algorithm is in performance. The disadvantage of a symmetric algorithm is that you need the key to verify it.
Therefore, if you need third parties to be able to verify the signature (or even if you need the verification to happen on the client side) you would be exposing the key used to create the signatures.
In this case, the signature is easier to implement. To sign use hash_hmac with the key. To verify the signature, repeat the process and compare it with the signature you got.
A key for each user
I am not sure if you are trying to protect the data from yourself. That is, if your objective is to prevent you (or your team / or whoever manages the servers) from tampering the data.
If that is what you want, you can password protect your keys. For the asymmetric solution, phpseclib allows you to set a password used to cipher the private key (and therefore needed to be able to sign). For the symmetric solution, you can use the password directly as key.
If what you want is to generate that password from your fingerprint, you can do that with a key derivation function... yet, remember that there will be fingerprint collisions, and that having a unique browser fingerprint can be considered a privacy concern.
Key derivation functions
You can get a cryptographic key from external input (browser fingerprint, user password, etc...) using a key derivation function.
From worst to best option:
Truncate to size the fingerprint. DON'T DO THIS EVER. This wastes entropy from the fingerprint. It makes collisions very likely.
Hash the fingerprint. DON'T DO EITHER. Anybody who can take the fingerprint and knows what hash you use can get the key.
Hash the fingerprint concatenated with pepper (the same salt for everybody). Still not good
Hash the fingerprint concatenated with salt (unique for each individual). Many say this is the first sane option. Yet, you should keep in mind to use a good hashing algorithm.
Use a hash based message authentication code. hash_hmac. For me, this is the first sane option. It costs you virtually nothing to change a hash of a concatenation to a call to hash_hmac. In addition, it will protect you from partial preimage vulnerabilities of the hash algorithm (known or to be discovered).
Use a dedicated key derivation algorithm. Among the standard PHP function, I suggest hash_hkdf or hash_pbkdf2.
Note: sometimes people (including me from the past) refer to these key derivation functions as hash functions. The reason is that when you use them, you do not call your regular hash function (directly) and what they give you is technically a hash. Yet, in reality, they are not hashing algorithms; they are algorithms build on top of hashing… in fact, one of the parameters to use them is what hash function to use internally.

In PHP, is it possible to encrypt a string using a key that someone who has full access to the code would not know?

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.

Two-key encryption/decryption?

I'm looking to store some fairly sensitive data using PHP and MySQL and will be using some form of reversible encryption to do so since I need to get the data back out in plain text for it to be of any use.
I'll be deriving the encryption key from the users' username/password combination but I'm stumped for what to do in the (inevitable) event of a password being forgotten. I realise that the purpose of encryption is that it can only be undone using the correct key but this must have been addressed before..
I'm trying to get my head around whether or not public key cryptography would apply to the problem but all I can think of is that the private key will still need to be correct to decrypt the data..
Any ideas?
It's not clear what you are striving for, so advice on how to implement it is hard.
Standards like PGP and S/MIME encrypt each message with a new symmetric key. Those keys are then encrypted for each recipient of the message. This way, instead of duplicating the message (which could be very large) for each recipient, everyone gets the same ciphertext, and only the key (which is small) is duplicated—but encrypted differently for each recipient.
Maybe you could do something similar here, encrypting the key with the user's password, and encrypting another copy with your public key. If the user forgets their password, you can recover the message for them (after an appropriate backup identity verification) using your private key.
The conventional solution is to have a "recovery agent": one user that holds a second password that can be used to decrypt all data. Strict usage policies would apply to using the recovery password, such as putting it physically into a safe.
Then, either encrypt all data twice: once with the user key and once with the recovery key; alternatively, generate a session key for every set of data, and encrypt the data only once, but the session key twice.
For that to work, at least the key of the recovery agent must be asymmetric, since the private part will live in the safe, and the public key in the software.
As yet another alternative using the same scheme: encrypt the user's passwords with the recovery key on password change. This is simpler to implement, but will allow to recover the passwords and not just the data, which may be undesirable.
I'm looking to store some fairly
sensitive data using PHP and MySQL and
will be using some form of reversible
encryption to do so since I need to
get the data back out in plain text
for it to be of any use.
Protecting sensitive data is good. Now:
Whose data is it? (yours, your user's, or a third party?)
What does it need to be protected from? (disclosure, corruption (accidental or intentional...)
Who does it need to be protected from
Uninvolved parties goes without saying.
Do you need / want to avoid accessing the plaintext data yourself (useful for deniability),
Do you need to protect either your user's data from being visible to a third party,
Or a third party's data from the user,
Or your data from the user or a third party?
What are likely attacks?
Do you need to protect in the case where the server is completely compromised?
Do you need to protect against an application level attack where the user simply gains access to some but not all available data (e.g. access to the SQL database, but not the filesystem)?
Will the amount of data be small enough that the attacker can guess and simply check whether he/she got it right? (short passwords, numbers, simple words, fixed form text are likely candidates)
Will the attacker have known plaintext with which to attack?
Is it better for the data to go away (or to re-retrieve the data) if the user forgets their password, or is it worth an increased risk of exposing the data to avoid that cost?
There are probably other questions, but this is the type of thing you want to think about when using encryption. The answers will help you figure out what you need vs. what you want, and will probably help point in the right direction. You might not want to share all of the answers with us.
I'll be deriving the encryption key
from the users' username/password
combination but I'm stumped for what
to do in the (inevitable) event of a
password being forgotten. I realise
that the purpose of encryption is that
it can only be undone using the
correct key but this must have been
addressed before..
You might have decided on a solution without considering the impact. That doesn't mean the solution is wrong, but this question suggests you should think about what you are willing to risk for security. Sometimes data will be risked.
I'm trying to get my head around
whether or not public key cryptography
would apply to the problem but all I
can think of is that the private key
will still need to be correct to
decrypt the data..
This too sounds like a solution in search of a problem. Public key cryptography is useful when you have two (or more) separate actors with an interest in communicating data between them. Those actors can be real (people) or functional (components of a system), but without two actors, there is no reason to have a separate public and private key.
Basically, if you encrypt something, and lose the encryption key, you're screwed.
When it comes to securing data, you need to consider why you're securing it, and what you're attempting to secure it against. And what tradeoffs are worth making in order to do so - the only truly secure system is one that is completely isolated from the internet, which is a level of security that is self-defeating for most applications.
So here are some questions to ask yourself:
If someone compromises my database, is it acceptable for them to be able to access this data?
What if someone compromises my entire application stack?
If the answers to the above two questions are "no", then the key material must be held by the user. And they will lose access to their data if they lose the key.
You can provide an option for manual key recovery if you also have a "master key" that you don't store anywhere near your application, only you hold it and you use it to manually reset passwords. If that's also not an option (say, only the user should be able to access the data, not the system administrator), then you're going to have to make a compromise somewhere.
This is a question I have thought about myself and as I see it the following options are available (with option #1 being the most secure):
Provide no reset password functionality - if they have forgotten their password then they are locked out.
Generate a new secure master key and encrypt & hash the user's key with this master key and store the cipher text and hash result in the database. The secure key is then made known to the user either by adding it to a file that the user downloads, emailing to the user or displaying the secure master key on screen. To reset the password the user would have to enter this master key which is then hashed and compared and if they match, the user's key in the database is decrypted.
Ask the user to provide 2 security questions and answers when registering; hash the answers and store the questions and answer hash in the database. The second answer is used as the master key to encrypt the user's key. To receive a password reset request email the user has to answer the first question correctly. Once they click the link in the email the web page then asks the second question, if this is correct and the query string parameter values are valid then use the answer to the second question to decrypt the user's key.
Use an application global master key (maybe stored in the web/UI application and use this to encrypt and store the user's key. Once a user is verified through a password reset email process the user's key is decrypted using the application global master key and then reencrypted with their new password.
In summary, the benefits of each option is as follows:
This is the ultimate for security and would possibly be the only option if the data was critical to be kept encrypted. However, in the real world people forget their passwords as sure as the sun rises and not providing a reset password function could be a bad commercial decision.
This is secure as the master key is not stored on the front end or database so if the platform is compromised then the data would require some significant effort to decrypt. However, the downside is the user could still lose their master key anyway.
The weakness here is if the database is compromised the answer to the question could be researched and then used to decrypt the users encrypted key.
This approach leaves the application key in the stack leaving your data vulnerable if your platform is hacked. The only protection you have is that if the database server is hacked then the data would still be safe.
As with most things in the world of software development you need to consider what is best for what you are trying to accomplish and aim for the correct balance.
Why are you using a different key for every user?
If you choose one key, it is much easier to handle.
Store your encryption key outside of the database.
Your application will still have to have access to it, but someone with a db dump will not be able to read the encrypted info.
Generate a random session key.
Use the session key to encrypt the data.
Encrypt the random key with any number of user passwords that you need.
This way you can use any user password to decrypt the data.

PHP, MySQL, and AES Encryption / Decryption for User Data

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.

Categories