openfaux / openfaux-server

Browser add-on for encrypting and masking internet traffic.
https://openfaux.org
GNU Affero General Public License v3.0
72 stars 18 forks source link

Change Encrypted Transport to RSA #26

Open Hunter-Dolan opened 10 years ago

Hunter-Dolan commented 10 years ago

This is also an enhancement that should go on openfaux/openfaux-client

The following is a list of suggestions for the future structure of OpenFaux and outlining what was already discussed privately.

OFS (OpenFaux Sever) needs an extremely well trusted and robust encryption mechanism. One that is simple enough to be implemented effectively in both Python and JS but also one that has variable difficulty (for when the user needs it).

RSA checks all the boxes above.

The steps I would suggest to have a secure RSA transport are listed below.

Handshake

1) User Connects to Server through unencrypted connection (Web sockets would be the best option here but you could also achieve this with just regular old XHR).

The request has the following information in plain text:

{
    "data": {
         "command": "handshake",
         "keysize": "1028",
         "timestamp": "<TIMESTAMP>"
    }
}

Keysize can be set by the user, but the higher the key size the more work for both the server and the client, so you may want to set a limit

2) Server generates the keypair with the specified keysize. It then saves the private key (preferably in a database) and assigns the key an id.

Then returns with the following information in plain text:

{
    "data": {
        "command": "set_key",
        "keysize": "1028",
        "public_key": "<PUBLIC KEY, BASE 64 Encoded>",
        "session_id": "<SHA256(RANDOM DATA + timestamp)>",
        "timestamp": "<TIMESTAMP>"
    },
    "signature": "<SIGNED SIGNATURE DATA>"
}

3) Client takes the public key from the server and stores that locally. The client then generates it's own RSA Keypair and stores it's private key.

The client would then sned the following information to the server encrypted with the servers private key:

{
    "data": {
        "command": "set_key",
        "keysize": "1028",
        "public_key": "<PUBLIC KEY, BASE 64 Encoded>",
        "session_id": "<SESSION_ID>",
        "timestamp": "<TIMESTAMP>"
    },
    "signature": "<SIGNED SIGNATURE DATA>"
}

(as you might notice this is the same format as what the server just sent to the client, this is no mistake)

4) The server recieves the data and then stores the client's public key with the server's private key (in the database).

It then sends back the following data (encrypted with the clients public key)

{
    "data": {
        "command": "handshake_complete",
        "session_id": "<SESSION ID>",
        "timestamp": "<TIMESTAMP>"
    },
    "signature": "<SIGNED SIGNATURE DATA>"
}

Handshake Complete

Now, the handshake is complete. Data can be transmitted to and from the server and client without the risk of being listened in on. All data is encrypted with the oppsite machine's public key and cannot be decrypted without the opposite machine's private key. Since the private key was never sent over the wire it would take an extremely long time to crack (exponentially longer by the size of the key).

Basic Communication

Communication should maintain the structure above. A HTTP request could look like this:

{
    "data": {
        "command":"request",
        "protocol":"http", # Could be HTTP, HTTPS, FTP, etc
        "method": "GET",
        "request_headers": {
            # More for post requests    
        },
        "url": "https://openfaux.org/",
        "session_id": "<SESSION ID>",
        "timestamp": "<TIMESTAMP>"
    },
    "signature": "<SIGNED SIGNATURE DATA>"
}

Which the server could respond with:

{
    "data": {
        "command":"response",
        "response_headers": {
            # Various Response Headers
        }
        "body": "<RESPONSE BODY DATA>",
        "session_id":"<SESSION ID>",
        "timestamp": "<TIMESTAMP>"
    },
    "signature": "<SIGNED SIGNATURE DATA>"
}

Assumptions

{
    "data": {
        "command": "<COMMAND>"
        "timestamp": "<TIMESTAMP>",
        "session_id":"<SESSION ID>"
    },
    "signature": "<SIGNED SIGNATURE DATA>"
}
schumannd commented 10 years ago

As far as I know the problem with using RSA as encryption for EVERY data packet is, that it's simply too slow. Thats why we intended to use RSA as this has been developed to be feasible for continuos encryption. RSA is usually only used for the exchange of a shared secret which is then used for a simpler (i.e. easier to compute) but just as safe encryption. This is what we were planning to do.

Hunter-Dolan commented 10 years ago

RSA key generation can take a some time. Seconds usually, but it's all dependent on your key size.

However the actual encryption process is much quicker.

I wrote a system a while back that used RSA for communication between two servers. The servers would send status and load information, as well as any log data, between each other. We added RSA encryption and signature validation as a security layer because the logs had IP addresses and did not notice a performance impact. Granted this was done in a much lower level programming language (C) but it should act similarly in modern JavaScript and surely Python.

I will run some benchmarks when I get time sometime next week.

If you were to use RSA to simply transfer the secret then you're opening up a new realm of issues. The largest being, how long is it going to take someone who is determined, and can rent out a few GPU servers, to break the smaller, easier to digest, key. If we're dealing with people who can perform a man in the middle attack, a shared secret isn't going to stop them.

Just my two cents though.

schumannd commented 10 years ago

I just ran some benchmarks on AES using pyCrypto: AES seems to work with about 3 MB/s This isn't amazingly fast but way better than the 0.5 kb/s I was working with earlier.

If you could run some benchmarks on RSA that would be great.

Regarding your concerns: A MITM Attack would still be just as possible using RSA. Its nearly always a possibility.

If they decrypt the shared secret, they have our private key. That would mean that the solution of encrypting everything with RSA would be broken as well.

Hunter-Dolan commented 10 years ago

However finding the primes to get the private key is much harder than guessing the shared secret.

If I have the encrypted data all I would have to is use a brute force application on a grid of GPU servers.

Speed is the enemy. Faster encryption means faster guessing. Not to mention the key is going to be shorter than the

Hunter-Dolan commented 10 years ago

... One of these days I'll learn not to hit buttons before I'm done typing.

As I was saying the secret is going to be shorter than the primes.

boxtown commented 10 years ago

We're not encrypting everything with RSA. We should be encrypting the body with AES and only encrypting the AES shared secret with RSA. Thus, a MITM would have to break RSA to get the shared secret. In general, that won't occur unless the MITM is EXTREMELY dedicated

boxtown commented 10 years ago

Also with regards to the key length, AES keys are at least 256 bits meaning 2^256 brute force possibilities. I imagine that's not going to be that easy to brute force

Hunter-Dolan commented 10 years ago

I don't see then what the difference between this and HTTPS Everywhere.

This project has some great potential to actually be a security extension that is actually secure instead of just giving the user a false sense of security and giving the hacker an easy job.

I understand the concept of what you want to do. Transfer secret with RSA, encrypt with AES. It's what everyone's doing and it doesn't stop a determined hacker (one with botnet, or tax payer dollars).

I can guess the Secret Key much faster because not only will the key be shorter than a RSA primes it require a lot less math because I won't have to find the modular multiplicative inverse which is why RSA key generation takes so long. Which in return makes guessing almost impossible. All I have to do is guess and check until I find solution that gives me a non garbled solution.

AES has no process in key generation. It's as simple as input data and any secret you want.

RSA has a whole process to go through before you can get to a point to start encrypting.

This is the same reason why you don't use MD5 or SHA1 to hash passwords and instead use a much more resource expensive system like BCrypt.

schumannd commented 10 years ago

The "whole process" of key generation you are talking about does not add security or safety against brute forcing to the protocol. It makes the public / private scheme possible, thats why it is so complicated. Not because it is more secure.

And in regards to brute forcing a random 256 bit secret: 2^256 is a number with 77 digits. lets just assume its a 1 and 76 zeroes.

A normal computer can guess about 10 million (10^7) passwords per second as of 2009 [1]. As this is old info we will generously up that number to 100 million (10^8)

The biggest machine in the world today (Milky Way-2) is capable of 33.86 petaflops. its about as strong as a million regular computers. so a million times 100 million guesses / sec... 10^8 * 10^6 = 10^14 [2]

So the strongest computer on earth today can guess 10^14 passwords per second. How long would it take to guess 10^76 passwords? 10^62 seconds. Or about 10^55 years.

Life on earth will approximately end in about 3 billion (or 10^9) years. [3]

As a bonus: http://xkcd.com/936/

What I am trying to say is: AES-256 is brute force safe.

[1]http://www.lockdown.co.uk/?pg=combi [2]http://www.voanews.com/content/china-boasts-worlds-fastest-computer/1683465.html [3]http://news.nationalgeographic.com/news/2013/10/131028-earth-biosignature-doomsday-space-science/

Researching all that just now was actually very interesting. I mean we always get taught things about security of protocols or security of password lengths. But nothing beats looking up and verifying the numbers yourself.

boxtown commented 10 years ago

Yes this is exactly it. AES is incredibly safe as long as the shared secret is not revealed. Also, I believe we are adding custom layers of encryption as well as AES and RSA, we just need to get that portion down first

Hunter-Dolan commented 10 years ago

Might I add that it does add security.

If I have to go through a process to guess the primes, then another process to get the private key (that fastest way to break RSA, you don't simply guess the private key data like you do with AES shared keys). Because of this each guess is going to take longer (exponentially depending on your key size).

But okay. I was approached to contribute on this project but I will not work on a project that a) offers nothing new, and b) has security that is deemed "good enough".

Computers are going to advance in the future faster than they ever had. I figured if you wanted to build a security system you'd want it to be as close to future proof as possible.

schumannd commented 10 years ago

I have run the RSA benchmarks. RSA runs with a speed of about 5 kb/s. This is too slow. I hope you see why this disqualifies RSA as an option.

I have also noticed an error in my AES benchmark. AES actually runs with 50 MB/s

I pushed the benchmarks to my branch so you can run them on your own and check for errors. I just hacked them together so there might be errors, please check. The scripts are only a few lines each.

I am not going to discuss whether RSA or AES is more secure. Both are brute force safe in the near future given a big enough key. It depends on whether or not someone finds another attack against them in the future.

boxtown commented 10 years ago

RSA runs slow on large bodies of data. That's why we use AES to encrypt the data, but the caveat is that AES needs to transport a shared secret to the other party. That's why we use RSA to encrypt the shared secret (generally a 256 bit key). On 256 bits, the slowness of RSA is negligible.

With regards to @Hunter-Dolan 's worries on future proofing and adding nothing new, we are adding custom layers of encryption. The thing is, it's important to first lay down the foundation which means successfully implementing AES + RSA encryption first. With regards to future proofing AES and RSA, AES is nearly impossible to brute force without a notion of what the shared secret is. Like mentioned above, trying to brute force something with 2^256 possibilities is in practice impossible and likewise so is cracking RSA unless (1) quantum computers become a reality and (2) someone discovers a polynomial time algorithm for factoring integers into primes.

Sp3ctr3 commented 10 years ago

To clear up a few things: Current plan is to encrypt data with random AES 256 key, encrypt the key with the server's public key and send it. As to @Hunter-Dolan 's question on how this is different from other offerings, encryption is only one of the steps. We plan to implement stego in such a way that any captured data between the client and the server will look like benign data. Our real data will be hidden in the benign data. Even if someone extracted the real data from the benign data, it's still encrypted. Here's a (crudely) drawn flowchart: openfaux

admwx7 commented 10 years ago

@Hunter-Dolan about "good enough" as it stands you have to factor in more than just security, we have to make a usable tool that won't overly impact the user experience, if we implement a highly secure encryption that limits our users throughput to 5kb/s we'll have no users which would defeat the purpose. If we use a "good enough" (as you put it) encryption that manages 50MB/s we'll actually have users interested. As servers hardware improves or as encryption algorithms improve to allow us to eventually use those more secure algorithms without completely sacrificing performance then we'll work towards implementing those, that's the whole point behind a modular system design.