Proxy Encryption - Encrypting With Public Key, And Decrypt with Private Key[Node.js Home][Home]
With proxy re-encryption, we can convert a key encrypted with Alice's private to into one that Bob can decrypt with his private key. In the first part, we will perform the basic operation of encrypting a message with Alice's public key, and then decrypting with her private key.
|
Outline
Let's say that Alice has stored an encrypted file, which uses a given key (\(K_A\)). Alice can then protect her key by encrypting the key with her public key. She can then decrypt this encrypted key with her private key (\(E_pk(K_A)\)):
But let's say that Alice now wants to share the encrypted document with Bob, and where we want to convert the key encrypted with Alice's public key, into one that can be decrypted by Bob's private key. For this, we can use transform (or proxy) re-encryption. At the core of this is a transform key, which is the key which can decrypt the protected key to Bob's private one. This is done by Trent, who is trusted to take Alice's private key and Bob's public key, and create a transform key (\(T_{AB}\)). This can then be given to Bob when required, along with Alice's protected encryption key:
In this case, Trent can become the proxy and trust create the transformation key, and receive Bob's public key, and Alice's private key. So let's code using Rust (as it is a highly secure programming environment, with lots of libraries - crates).
Method
Now you should know that in public-key encryption, that you can have a public key and a private key. Normally if Alice sends encrypted data to Bob, he will use his public key to encrypt the data (\(B_{pub}\)), and then Bob would use his private key (\(B_{priv}\)) to decrypt it. But now let’s say we have two key pairs: (\(A_{priv}, A_{pub}\)) and (\(B_{priv}, B_{pub}\)), and who are owned by Alice and Bob, respectively. Could we encrypt with Alice’s public key (\(A_{pub}\)) and then for it to be decrypted with Bob’s private key (\(B_{priv}\))? This is known as transform encryption, and where we have a special transform key (\(A_{pub}\) -> \(B_{pub}\)) using Alice’s private key (\(A_{priv}\)) and Bob’s public key (\(B_{pub}\)). We then could pass the encrypted data, encrypted with Alice’s public key (Apub) to Trent, and then to also send Trent the transformation key. Trent can then create the required ciphertext for Bob, and which he can only decrypt with his private key (\(B_{priv}\)).
Now, let’s say that Alice wants to send a secret message to a group (Bob, Carol and Dave), and where the group has its own public key, and where each of the group has the required private key for the group. Now Alice can use Trent as a trusted proxy:
- Alice uses her public key (Apub) and encrypts the data, and sends it to Trent to store.
- Alice then generates a transform key for the group and deposits this with Trent.
- Bob then asks Trent for the encrypted data, and Trent uses the transform to convert it into ciphertext.
- Bob then takes the ciphertext from Trent and then decrypts it with the group’s private key.
In this way, Trent is the proxy for the encrypted data, but Trent cannot read the secret message that Alice is sending, and Alice cannot see who is requesting the encrypted data. We thus preserve the privacy of the request from Bob, but where Trent cannot read the message.
Outline
In this case, we will use the Ironcorelabs Node.js integration [here] (and which binds to the Rust binary code). The code is:
const assert = require("assert"); const Recrypt = require("@ironcorelabs/recrypt-node-binding"); var msg = "Hello"; var args = process.argv; if (args.length>2) msg=args[2]; const Api256 = new Recrypt.Api256(); const aliceKeys = Api256.generateKeyPair(); const aliceSigningKeys = Api256.generateEd25519KeyPair(); const plaintext = Buffer.alloc(384,null) plaintext.write(msg,'ascii') // Encrypt with public key, and decrypt with the private key const ciphertext = Api256.encrypt(plaintext, aliceKeys.publicKey, aliceSigningKeys.privateKey); const bobKeys = Api256.generateKeyPair(); //Use Alice's private key, and Bob's public key to transform const userToDeviceTransformKey = Api256.generateTransformKey(aliceKeys.privateKey, bobKeys.publicKey, aliceSigningKeys.privateKey); // Re-encrypt for Bob and sign with Alice's private key const transformedEncryptedValue = Api256.transform(ciphertext, userToDeviceTransformKey, aliceSigningKeys.privateKey); //Decrypt with Bob's private key var plain = Api256.decrypt(transformedEncryptedValue, bobKeys.privateKey); pl= plain.toString(); pl=pl.substr(0,pl.indexOf('\0')); // Remove nulls console.log("\nAlice Private key: ",aliceKeys.privateKey.toString('hex')); console.log("Alice Public key: ",aliceKeys.publicKey.x.toString('hex'),aliceKeys.publicKey.y.toString('hex')); console.log("Bob Private key: ",bobKeys.privateKey.toString('hex')); console.log("Bob Public key: ",bobKeys.publicKey.x.toString('hex'),bobKeys.publicKey.y.toString('hex')); console.log("\nPlaintext value: ",msg) console.log("Ciphertext value: ",ciphertext.encryptedMessage.toString('hex')) console.log("Decrypted value: ",pl)
A sample run:
Alice Private key: 5bdf9f88504fb66fcc846af577b0ffad36f77edf53c71b98a9d5e468ec46531a Alice Public key: 8000b346bc394e9c9095f3a6dbcc239686d5106da38dd560ff195c7c91c59242 6c5de78e8532366a7fba0b19a73435dfda9bda0d73700b4e36ca9c577cde19cc Bob Private key: 7d605a9a341033b75fc434318829585c9d0db6e0d9fba0a3890598254ea0c7fb Bob Public key: 64213bd29e9ec5f3a19dc0e2e09cbf074f4e7244eef8127e6ab8970f09ce0a92 668b2ecc4824482053a994cde9976961fcdfca023a44693901a357ef14e7d1f1 Plaintext value: Hello Ciphertext value: 2edbd6836a1aef3048990cc230dbd55133448b04537452e4daee7d6fbfe2d05b404bd38f5eb7083b3f157a6339d69e51e1c7bcde67042fde27c020f9ff40dcdf130d7f981f98ab959073afbac54df66cabad4823a9d0005c199cdc8e755ddd3672cbf61203e97491df829e517d3a3c9464ac97a4a3db2dd703a2012524a4f05c45ead4c58ddbf88a1f3afc04b942f4fef7e4144283713301ac99d4660ae4a115618d39ca0c1d96755548aeae0f472e3bbecbbc12ddac32093e43518e7893f6e041f251840447f86d1aa6505e071fa49806b8a7e0969f559869b45963dcd2c09f407d896bcf0540704960bb547e03236131240aeb75b25e7c5a61248e785c7144503b76eb4b1845607264dd635754e981fc3aecb92d2ed28488d10437c405a44454a2eced87888a7d5fce2367c05e08f42c279977b9e47a25c84cfc5b5e1241e26c391486ba85f5f35c812b68bdf0400320e5a9714f5958dabe676abf40b204bc02e912ffa030fe3a9ef9b4fe4571b4b2ea493f433baec369d1d90389b6ec9365 Decrypted value: Hello