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.
Related
I am using a Token based authentication. My web server would generate and encrypt the token. I want the client to decrypt the token to read certain payload information.
What algorithm I should use to achieve this?
In my understanding if I use RSA, I can decrypt in c# using private key whereas the encryption has to happen from other hand so this doesn't fit-in my scenario. Is there any other asymmetric algorithm or ways to achieve this?
Server encrypt - private key.
Client decrypt - public key.
Is there any other asymmetric algorithm or ways to achieve this please suggest.
I want to correct your understanding of asymmetric encryption. Asymmetric encryption allows anyone with the public key to send a secret message to anyone with the private key. Since the public key is public, asymmetric encryption allows many possible senders to send private messages to a few special recipients.
My web server would generate and encrypt the token. I want the client to decrypt the token to read certain payload information.
In that case, with the server sending a secret message to the client, if you are using asymmetric encryption, then the server will encrypt with the public key, and the client will decrypt with the private key.
Server encrypt - private key. Client decrypt - public key.
That is not correct. In asymmetric cryptography, the public key does the encryption and the private key does the decryption.
What you might be thinking about is a digitally signed message. In that case, the sender signs the message with the private key and the receiver verifies the signature with the public key. Digitally signed messages are not secret, though, whereas encrypted messages are secret.
Is there any other asymmetric algorithm or ways to achieve this please suggest.
Since your use case is not entirely clear, I will stop the answer there, and leave it at correcting your understanding of asymmetric encryption. It might be that you need symmetric encryption or a digital signature. I encourage you to ask another, separate StackOverflow question as a follow up to this one.
As a final note, I'll refer you to the Internet Security Glossary. In particular, the section named "$ asymmetric cryptography" has a precise and brief description about how "Asymmetric cryptography can be used to create algorithms for encryption, digital signature, and key agreement."
From your other (unfortunately on hold) question https://stackoverflow.com/questions/49610839/protecting-jwt-signing-and-encryption-c-sharp-solution, it sounds like you require the following:
Send a payload from the server to the client.
Only the client can read the payload, because it is encrypted.
The client can verify who sent the payload, because it is signed.
The recommended approach is to sign-and-then-encrypt. If you are wanting to use asymmetric encryption for both:
use a private to key to sign the payload,
then use a public key to encrypt the signed payload.
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.
I have a big XML that needs to be encrypted on one server (by one c# application), and needs to be decrypted on another server (by another c# application). The XML contains the critical information for which this encryption needs to be done.
My real need is that my server that does the encryption should only know the public key and the private key is known only to the server which is doing the decryption. Also, this private key should be stored in a safe area on the server such as certificates.
What should be the steps that can help me achieve so?
Can I generate my private key and store that in certificates or the certificates will generate the private key on their own?
Also, if certificates generate the public and private key, can the public key be separated from the certificate and exported to the server where the encryption has to be done?
How the key-pair and certificate are generated depends on the software used.
The private key can be obtained from a certificate.
The general method is to encrypt data with a symmetric encryption algorithm such as AES and encrypting the symmetric key with asymmetric encryption algorithm such as RSA or EC and the public key. This is done for two reasons: 1. Asymmetric encryption is very slow compared to symmetric encryption. 2. The data length for Asymmetric encryption is limited by the key size: a typical key size is 2048-bits and that limits the data length to 245-bytes.
There is in general no way to securely store a private key (or anything) on the server other than the server being secure short of the server having an HSM or access to a TPM. The main step on making the server secure is 2-factor authentication. But if it is on a shared computer beware of root escalation exploits by other users of the server.
HSM - Hardware Encryption Module
TPM - Trusted Platform Module
Asymmetric encryption is very processor intensive and, consequently very slow. For that reason, it is not normally used to encrypt large amounts of data.
What is normally done is symmetric encryption is used to encrypt the bulk of the data and asymmetric encryption (public key) is used to encrypt the keys used in the symmetric encryption.
The encrypted keys are transmitted with the encrypted data. The keys are decrypted (private key), then using the symmetric keys the bulk data is decrypted.
This is how I have achieved it.
On my server 2, I am generating a certificate(.cer) and a private key(.pvk) using the 'makecert.exe' command. Then, using the 'pvk2pfx.exe', I am generating a .pfx file. This is the file which will now house the certificate and private key.
Now I export the certificate with just the public key to the server 1, where I encrypt the data, and on Server 2 using the certificate's private key I decrypt the data.
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.
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.