In a previous blog post we explored how to sign messages using the Estonian eID card. In this video, we demonstrate how a receiver who got a signed email message would be able to verify that the email really did come from the advertised sender.
I have uploaded the revised code to github, please feel free to have a browse – but the plugin is linux only, and not ready for production (mainly due to lack of error handling, not cleaning up the tmp folder after operations, and hardcoding the eID PIN)
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 re–encryption 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:
The above python code is a very good wrapper around some java JAR files:
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.
- Download the ZeroDB -AFGH-PRE zip file: https://github.com/zero-db/zerodb-afgh-pre/archive/master.zip
- 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🙂