Skip to content

infinet/gappproxy-pg

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GAppProxy Privacy Guard (GAppProxyPG)

GAppProxyPG uses RSA and AES to secure GAppProxy. The communication between the client and server is encrypted by AES.

Requirement

  • Python: >= 2.7: Google App Engine has switched to Python 2.7, so do we.

  • Pycrypto: >= 2.6: Pycrypto 2.5 added PKCS#1 RSA encryption and signature schemes which been used by GappProxyPG. Since App Engine only provide Pycrypto 2.3 and 2.6, the version 2.6 is choosen. Binary package for windows can be found here

Usage

  1. Generate RSA keypairs for server and client, run

     local/rsa_keygen.py
    

    will generate two new RSA public/private keypairs, and copy the server's public key to local/, client's public key to fetchserver/

  2. Upload to App Engine, run

     $ path_to_app_engine_sdk/appcfg update path_to_fetchserver
    

    Please refer to App Engine Document for appcfg options.

  3. edit local/proxy.conf, the fetch_server is the address of your-appid.appspot.com

Security Design

The AES key negotiation try to simulate TLS 1.2 as specified in RFC 5246.

RSA Public Key

The client and the fetch server have each other's RSA public key, which they use to negotiate a MasterSecret, then the key for AES and HMAC.

Login into App Engine

Because client and server know each other's public key, and the encryption method are pre-determined, the login takes only one step.

ClientHello

The clients use HTTP POST method to send the hello message to login.py.

The client generate a 48 bytes long PreMasterSecret, together with a Client Random.

Structure of Client Random:

    struct {
        uint32  timestamp;
        opaque  random(28);
    }

The format of Client Hello message:

    struct {
        RSA Encrypt Object  (UserName | PreMasterSecret | Client Random);
        RSA Signature       Signature of above message;
    }

ServerFinish

Upon receive the client hello message, the server first decrypt it by server's RSA private key, then the cleartext is partitioned into username, PreMasterSecret, and Client Random. The server then lookup the user's public key, use it to verify the RSA signature of client hello message.

The server then generate the Server Random, which is in the same format like Client Random; a random session id also generated as this stage.

Use a PseudoRandom Function(PRF) defined in RFC 5246, the server calculate MasterSecret as:

    PRF(PreMasterSecret, 'master secret', Client Random + Server Random)[48]

Then create the key block:

    PRF(MasterSecret, 'key expansion', Client Random + Server Random)

The key block contains 4 keys:

  • client AES write key
  • client HMAC write key
  • server AES write key
  • server HMAC write key

A timestamp is attached to the key block, then it is stored into AppEngine memcache. Every time the fetchserver retrieve the key block from the memcache, it read the timestamp to verify the key block is not expired. A expired key block will make fetchserver send a custom HTTP 521 error to the client.

The server create Server Finish message as:

    Server_Random + Session_id + verify_data

Where verify_data is generated by PRF:

    PRF(MasterSecret, 'server finished', HASH(Session id + Client_Random + Server_Random + PreMasterSecret))

The final server finish message is:

    struct {
        RSA Encrypt Object  (Server_Random + Session_id + verify_data);
        RSA Signature       Signature of above;
    }

ClientFinish

After receive the ServerFinish message, client decrypt it using own private key, then verify the signature by Server's public key.

Client partition the cleartext into ServerRandom, Session Id, and verify_data. Client generate the MasterSecret, key block, and verify_data using the exact same PRF like server does. Client also verify the verfify_data hasn't been changed.

Client then partition the key block into client and server AES/HMAC keys.

encrypt connection

The connection is encrypted with AES, the message integrity is protected by HMAC(Keyed-Hashing for Message Authentication). The client generate the request as:

    struct {
        Session ID  XOR(Session Id, Obfuscate Key);
        Random[4]   Obfuscate Key;
        AES OBJ     AES(
                        Random[16]    Request Id;
                        URLENCODE     Plain Request;
                        );
    }

Because the server uses session id to identify the client's AES/HMAC key, the same Session ID is prefixed to every request. After apply XOR with a random Obfuscate key, the beginning of every request will looks differently to a third-party observer. The server recover the session id after apply XOR, then use it to look up key block in memcache. After that, decrypt the client request, fetch the content use AppEngine urlfetch service, then encapsulate the result in an AES object and send back to client. A random generate Request ID is inserted into every request, the client will verify this id to prevent replay attack.

About

加密GAppProxy, combine RSA & AES to secure GAppProxy

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages