I want to allow users on my site to create an asymmetric private & public key so they can:
upload the public key to the site so my web application can encrypt
files they upload
download files and decrypt them using a local
application and the private key
My issue is that if the users machine dies then they will most likely loose their private key.
My concept is that the application the users download to pull the files from the site will also allow them to generate the keys for use on the site.
So my question is, Is it possible to create an asymmetric private/public key pair based on a passphrase? This would allow the user to regenerate the private key if required.
One way to do exactly what you are asking is:
Define a security level N, the larger the more secure but slower this process will be.
Generate a "salt" and associate it with the user's id.
Since RSA key generation requires a secure random number generator, use the user's password and salt with PBKDF2, starting at iteration N, to generate secure random data.
This process should deterministically generate a public/private RSA key pair. However, the reasons not to do this are:
It was cooked up by me and, AFAIK, this post is the first time this process will be publicly vetted.
It is not known to me if PBKDF2 actually works as a secure random number generator for use with RSA.
It may or may not be true the PBKDF2 is guaranteed to generate a data from which a public/private RSA key pair will originate.
In practice, while this does work, it takes a very long time and the time it takes is based on the user's password, which is a user experience and security exposure point that needs considered.
A better way to accomplish what you are trying to do is:
Define a security level N, the larger the more secure but slower this process will be.
Generate a "salt" and associate it with the user's id.
Generate an RSA public / private key pair.
Iterate PBKDF2 N times to create a symmetric key based on the user's password and salt.
Use a symmetric encryption algorithm to encrypt the private key.
Upload the unencrypted public key and encrypted private key to the server.
This is better because:
All processes listed above are, AFAIK, standard and vetted.
Generation of public / private keys (time consuming) only occurs once while setting up the user's account.
Accessing the keys always occurs in a fixed amount of time.
This solves your problem:
Since the server only has the encrypted private key it cannot decrypt the user's data.
If the client machine dies the server can re-issue the private key.
Of course there are the obvious warnings like if the user forgets their password all their data is locked until public knowledge on how to crack RSA is available or a billion years of current computing power is put to the task of breaking their password ;-) (depending on N and key size of course). Also, the salt is important to prevent dictionary attacks.
What the fields are for your algorithm (e.g. RSA http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsaparameters.aspx) are more or less up to you. You could easily create an algorithm to generate D and P from some string (calculating the other RSA fields from those). I'd really recommend you wouldn't pick one from an answer on StackOverflow though (that would simply give someone who wanted to get at your data something easy to try).
The reason algorithms like RSA are hard to break is the amount of effort that goes into reverse engineering the private/public key based on the encrypted data. If you introduce a "shortcut" like a reproducible generation algorithm based on a passphrase, the security of your system now depends on how well the passphrase is kept secret, not the encryption algorithm itself.
The same is true for the private key; which is why many organizations don't store the private key on hard drives and store them on secure external devices protected by a password or some biometric information.
I'd recommend you do not generate keys from a passphrase and simply use recommended practices for storing and protecting your private key.
Related
I had a look on
configSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
but I had two questions:
Is there a way to encrypt config file with a key, because any one can decrypt my file if he knows this method, right?
Does the decryption done automatically when retrieving the connection string at run-time? (in any class, or in data-sets)?
thanks
Yes, Encrypting config file is common. DPAPI way uses symmetric key and therefore, if someone gets the key, he can decrypt.
In my case I used an RSA asymmetric key. That way encryption with public key is performed. Decryption can be performed only with private key protected and held by server in SQL database. On application side, users and application don't need the decrypted secret but need to stay encrypted. Simply, public key is to encrypt and private key is to decrypt. And nobody can easily get the private key.
Furthermore, when it comes to cloud platform like Microsoft Azure, we have to use certificate way which is of also RSA.
My case took almost 1 month to understand the complexity. I completed this task just recently.
The decryption is performed automatically by indicating the thumbprint of private key in the config file.
For learning purposes, I'm creating a chat application where the connections are done via SSL/TLS, and the messages are encrypted using AES-CBC-256 and the AES keys are encrypted with RSA-2048.
The AES key is randomly generated (AesProvider.GenerateKey()) per user per session (which means one key for every person an user is chatting with) and the IV is randomly generated (AesProvider.GenerateIV()) by passing in the key generated, each time a message is created (before being sent).
On the RSA side, I'm generating a secure random session name to store the private keys generated in containers, and sending out the public key. I'm also using the same model (one key pair per user per session) as in AES.
I should also state that I'm using HMAC-SHA512 to hash the messages and sending the HMAC key encrypted using the same public key that the AES key/Iv gets encrypted with. Since I've read that it doesn't need to be regenerated often, I'm planning on regenerate the HMAC key every 5000 or 10000 calls.
Questions:
1) Should I be creating only one RSA key pair per user and use it for all sessions, or is it good how it is right now?
2) Is using the same AES key and only changing the IV like explained above considered secure?
Not much to answer because what you are doing is the best practice aready.
Some notes though;
RSA key pairs per session is not required (and generating the key is expensve).
You can have only one 2048 bit strong RSA key throughout the lifecycle of your application or for years, since this is what even the most security demanding web applications like e-commerce sites or financial applications do.
You should have a random AES key/IV pair for each session, that is fine.
It is better to have one HMAC key per session (not process wide) since you are sending the key securely (RSA encrypted) and you are also sending the HMAC value securely (AES encrypted) on the wire.
Changing only the IV is almost equal to changing the key and IV (in a sense) because the encrypted output will be different for the same content if you change the IV.
One note however. To prevent a man-in-the-middle attack mimicking your server certificate, is your client code validating the certificate through means of signature checking, or is it just the public key that you are sending without any validation on the client side?
You should have either a self-signed persistent certificate or generate the random certificate (RSA Key Pair) as is issued by the persistent certificate (eg, CN=FrozenDeathChatServer) where the clients during installation of your client software install under the trusted root certificate authorities.
I have a very specific case for cryptography and I am just not sure what algorithms I need to use to achieve a result I am looking for.
So, it is as follows.
I will distribute an encrypted string to my clients, they will have a password to decrypt it. But I don't want them being able to create such encrypted strings themselves.
So, I need some particular algorithm that would allow me, and only me to encrypt something, and anyone can decrypt it if they have a password. but NOT encrypt.
Can you use certificate based encryption? This is exactly the way HTTPS/SSL encryption works.
The server has a certificate with public and private keys. The private key is used to encrypt data. The certificate with just the public key is distributed to the clients and the public key is used to decrypt data.
Is there a way that my server can provide an encrypted string that can be decrypted on the client, but NOT re-encrypted on the client? I know this seems kind of backwards... here's what my need is.
I have a software key that needs to be activated against our remote server. The server needs to provide something back to the client that says "You are active" and contain info such as a date that it's valid until, how many licenses, etc. However, I need to prevent it from being easily tampered with to increase license count or the dates (i.e, re-encrypt the value with a new date using a key found in the de-compiled binary or w/e).
Is such a thing possible using public/private keys? Or perhaps hashes?
EDIT
Alternatively, can the server provide a hash that the client can validate is really from the server without giving the client the ability to spoof or generate a hash on it's own?
Thanks in advance.
Public/private key encryption should do what you need. Hashes are one way functions; a good hash function will make it impossible to retrieve the original value.
In this case, the server has a public/private key pair and the client has a public/private key pair. The server's public key is embedded into the client, and the server has the client's public key as well. The server can now encrypt your payload using it's private key and the client's public key. When the client wants to decrypt the payload, it uses it's private key and the server's public key. The client cannot re-encrypt the data without access to the server's private key.
http://en.wikipedia.org/wiki/Public-key_cryptography - for an explanation of how it all works
http://msdn.microsoft.com/en-us/library/e970bs09.aspx - as a starting point for .Net classes to make it easier
Sure. Use an asymmetric-key algorithm like RSA. Both keys are required to go from cleartext to cleartext; one will encrypt, the other will decrypt. You cannot use the same key you encrypted with to decrypt, and vice-versa. So, the client could not get ciphertext, decrypt it, then use any of the information it has to come up with the same ciphertext.
HOWEVER, asymmetric-key algorithms do not differentiate between the encryption and decryption keys until one is used to encrypt. They only require that the other key is used to decrypt a message encrypted by the first. So, theoretically, your client could "re-encrypt" a message using its "decryption" key that would be decrypt-able by the server using its "encryption key". I don't know of an algorithm that would disallow this; you'd simply have to build it into your communication library by omitting any way to use the decryption key for anything but decrypting.
I am doing an AES encryption in my C# code, using a key which is generated using PasswordDerivedKey function by passing a password and a salt of 12 byte. I have implemented the logic in my application code and the "password" is the username of the logged in user and the salt is a static byte aray.
What is the best way of storing the password and the salt, as someone can easliy determine the salt (by reflecting my code) and the username of a person.
What are the alternatives I can adopt to store the password and the salt in a secure way. I dont think storing them in my application code is the best way of doing it.
Edit: By password, i meant the passkey used in the PBKDF function (to derive an encryption key) and its not the password provided by the user. I am using Windows Authentication
Why would you need to store password if it is merely an encrypted version of the windows username?
Anytime you need to encrypt/decrypt you know name of user thus can generate key dynamically.
Salt should never be considered a secure asset. No need to hide it. You should always assume attacker knows the salt. Salt is simply a mechanism to defeat rainbow tables and other fast lookups.
Is there something I am not seeing?
On Edit
The issue is misstated in the question. The issue isn't what/how should be stored. That answer is simple. Never store any of the cryptographic data (except salt).
The current implementation creates an encryption key from the username of logged in user. The problem is that is insecure as determining username is rather easy. To get around this one would need to either:
a) accept the implementation is insecure to someone willing to decompile app.
b) ... not a good idea ... hash can change based on groups/roles
c) use a unique secret password for each user.
c is the only secure implementation however it requires prompting the user for a passphrase when encrypting or decrypting.
Against whom must be the data be secure? If the currently logged in user is allowed access to the data, but other Windows Authentication users are not allowed access, what you really want is for the data to be encrypted for the particular logged in user. If you have access rights to configure the PC, you might be able to create an Encrypted folder with permissions only for the desired user. This is not 100% secure (you can still intercept the data at various places if you have root access), but your only other reasonable alternative is to add another password.
Alternately, you can simply accept that the protection is weak and provide minimal obfuscation. It depends on the value of the data and the capabilities of your possible attackers. If your attackers have sufficient privileges to Reflect over your assembly on the actual machine, then it's highly likely that they're also Administrator, which means you're pretty much screwed no matter what you do. There are tools that can connect to a running process and monitor its memory, which means they could simply wait until you've decrypted the data and read it from memory.
Best way to keep the salt is to generate it on runtime and keep it per session along with other user stuff such as username and password:
use signs in and provide username/password
hash with stored salt and check against password hash
create new salt and store it along with the hash
Symmetric encryption (or even asymmetric) is not at all recommended for passwords. You not to hash it which is just one-way.
I added this as an second answer because it is a different solution. I just thought of it tonight because I am working with this class (trying to reverse engineer kindle encryption).
You may want to look into the Protected Data Class
http://msdn.microsoft.com/en-us/library/2c64xe0y(v=VS.90).aspx
This is a class that allows you to store data in the windows cryptographic store.
By using the Protect and Unprotect function you can pass data into and pull data from the cryptographic store.
If you didn't want to force the user to create (and remember) an encryption key you could.
1) Check to see if current user has encryption key in the store.
1a) If not then create a random encryption key
2) Use key to encrypt file and store
3) To decrypt retrieve key from store.
4) Another user may be able to access the file but will be unable to get a copy of the key from the store.
A couple caveats. Only the windows user who stored the key can retreive the key. However this can be bypassed depending on environment. If the user has no windows password (or weak windows password) anyone w/ access to machine can run as the user and windows will gladly hand over the key. In a domain environment anyone (admin) who can impersonate the user and modify password can access they key. If user's windows profile is trashed so is the only copy of your encryption key.