Proxy re-encryption

What is proxy re-encryption?

Proxy re-encryption lets Alice send Bob a message (M) via a semi-trusted proxy, without revealing Alice’s private key to either the proxy or Bob, and without revealing the secret message to the proxy. As Wikipedia puts it:

Proxy reencryption schemes are cryptosystems which allow third parties (proxies) to alter a ciphertext which has been encrypted for one party, so that it may be decrypted by another.”

Why should I care?

A proxy is in essence any provider – including a cloud service provider. As shown in the figure above, the proxy or cloud provider never sees the actual secret message. It only ever sees encrypted messages and public keys (elements marked in green above). Private keys remain private to the individual parties, and the secret message only every gets decrypted by the intended recipient, not the proxy. So, the cloud provider never sees the information. Let’s give this a more concrete spin:

For security reasons, I don’t trust my cloud provider so I encrypt all my data (with my public key of course) and store my encrypted data into the cloud. My data is safe and (theoretically) only I can access it since only I have my private key. A few weeks later, along comes Bob and it turns out, he needs to see my data. I now have two choices:

  • Get Bob’s public key, decrypt my data, re-encrypt it with Bob’s public key, and send it to him.

    This is a bit clunky. I need to decrypt my data and then re-encrypt. It may work for one person… what if I have many Bobs? It would be better to leave this work to my cloud provider if at all possible…

  • Use proxy re-encryption!
    In this case, I retrieve Bob’s public key, and issue a “re-encryption” key. This key represents the trusted relationship I would like to build with Bob. I send this key to my cloud provider and they proceed to re-encrypt the already encrypted data they have stored with the key. Bob can now download this re-encrypted data and decrypt it at will

In the second scenario, note how the decryption / re-encryption process is sidestepped and I dont need to perform this operation on my own devices. Instead all I need to do is generate a key which should be quick, and pass the buck to my provider, which at no point can decrypt the original message, making this system very scalable and enables data-sharing apps in a cloud environment.

Implementing this in practice…..

Turns out the folks at ZeroDB have implemented a python wrapper around some Java libraries for this here:

https://github.com/zero-db/zerodb-afgh-pre

The above python code is a very good wrapper around some java JAR files:

https://github.com/zero-db/zerodb-afgh-pre/tree/21315d5f724b7033e7afa7863dfcadae8f6f28b6/src/zerodb/afgh/crypto/jars

The most important of which is the NICS’s Cryptography Library which implements the paper entitled Improved Proxy Re-Encryption Schemes with Applications to
Secure Distributed Storage, or AFGH in short.

  1. Download the ZeroDB -AFGH-PRE zip file: https://github.com/zero-db/zerodb-afgh-pre/archive/master.zip
  2. Extract it and run sudo python setup.py install. If running ubuntu, you may get some zope errors which were resolved using: pip install –upgrade zope.interface

We can now use the library. Let’s run through the above scenario using the library:

  • Import required libraries:

from zerodb.afgh import crypto

  • Create Bob and my public/private key pairs:

me = crypto.Key.from_passphrase(“my passphrase)
bob = crypto.Key.from_passphrase(“bob passphrase)
bob_public_key = bob.dump_pub()

  • I encrypt my data and put the result into the cloud

my_data = “Hello World”
encrypted_data = me.encrypt(my_data)

  • Bob contacts me and asks for permission to look at “my_data”
  • I grab Bob’s public key and issue a re-encryption key to my cloud provider:

re_key = me.re_key(bob.dump_pub())

  • My cloud provider then grabs my already encrypted data and re-encrypts it, sending it to Bob. At no point does my cloud provider see my decrypted data:

rencrypted_msg = re_key.reencrypt(encrypted_data)

  • Bob decrypts the re-encrypted message and gets the secret message:

assert bob.decrypt_re(rencrypted_msg) == my_data

All through the magic of Bilinear Maps 🙂