Can Alice Encrypt With Her Public Key, and Bob Decrypts With His Private Key?

Last we a student took one of our cryptography test and answered a question saying that Alice will use her public key to encrypt for Bob…

Photo by Erik Mclean on Unsplash

Can Alice Encrypt With Her Public Key, and Bob Decrypts With His Private Key? Meet Transform (Proxy-) Encryption in Rust

Last we a student took one of our cryptography test and answered a question saying that Alice will use her public key to encrypt for Bob, and then Bob uses his private key to decrypt. Well, I marked it wrong … and for good reason. But there is a method that does this, and it is named transform (or proxy-)encryption.

Basics

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 (Bpub), and then Bob would use his private key (Bpriv) to decrypt it.

But now let’s say we have two key pairs: (Apriv, Apub) and (Bpriv, Bpub), and who are owned by Alice and Bob, respectively. Could we encrypt with Alice’s public key (Apub) and then for it to be decrypted with Bob’s private key (Bpriv)? This is known as transform encryption, and where we have a special transform key (Apub -> Bpub) using Alice’s private key (Apriv) and Bob’s public key (Bpub). 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 (Bpriv).

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:

  1. Alice uses her public key (Apub) and encrypts the data, and sends it to Trent to store.
  2. Alice then generates a transform key for the group and deposits this with Trent.
  3. Bob then asks Trent for the encrypted data, and Trent uses the transform to convert it into ciphertext.
  4. 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.

Coding

So let’s code using Rust (as it is a highly secure programming environment, with lots of libraries — crates). First, we create the project with:

cargo new transform

We then go into the transform folder and add the following to the cargo.toml file:

[package]
name = "pr"
version = "0.1.0"
authors = ["billbuchanan "]
edition = "2018"
[dependencies]
recrypt = "0.11.0"
hex = "0.4.2"
pad = "0.1"

Next we go into the src folder, and edit the main.rs file with [here]:

use recrypt::prelude::*;
use recrypt::api::Plaintext;
use pad::PadStr;
use std::env;
fn main() {
    fn unsize
(x: &[T]) -> &[T] { x }
// create a new recrypt
let recrypt = Recrypt::new();
    let mut mystr="Hello";

    let args: Vec<String>  = env::args().collect();
    if args.len() >1 { mystr = &args[1];}
    let x=Plaintext::new_from_slice(mystr.pad_to_width_with_char(384,' ').as_bytes());
    let pt = x.unwrap();
    let signing_keypair= recrypt.generate_ed25519_key_pair();
    let (initial_priv_key, initial_pub_key) = recrypt.generate_key_pair().unwrap();
    let encrypted_val = recrypt.encrypt(&pt, &initial_pub_key, &signing_keypair).unwrap();

    let (target_priv_key, target_pub_key) = recrypt.generate_key_pair().unwrap();

    let initial_to_target_transform_key = recrypt.generate_transform_key(
&initial_priv_key,
&target_pub_key,
&signing_keypair).unwrap();

    let transformed_val = recrypt.transform(
encrypted_val,
initial_to_target_transform_key,
&signing_keypair).unwrap();

    let decrypted_val = recrypt.decrypt(transformed_val, &target_priv_key).unwrap();

    println!("\nInput string:\t{} ",mystr);
println!("\nSigning key:\t{} ",hex::encode(unsize(signing_keypair.bytes())));
println!("\nInitial Private key:\t{} ",hex::encode(unsize(initial_priv_key.bytes())));
let (x,y)=initial_pub_key.bytes_x_y();
println!("\nInitial Public key:\t{},{} ",hex::encode(unsize(x)),hex::encode(unsize(y)) );
println!("\nTarget Private key:\t{} ",hex::encode(unsize(target_priv_key.bytes())));
let (x,y)=target_pub_key.bytes_x_y();
println!("\nTarget Public key:\t{},{} ",hex::encode(unsize(x)),hex::encode(unsize(y)) );

    println!("\nDecrypted:\t{} ",String::from_utf8_lossy(decrypted_val.bytes()));
    }

Finally we simply build with:

cargo build

A sample run is [here]:

Input string:	Hello 
Signing key:	c56c504099f144f04a983ae7d2d63371f4dafc8d81692cf495027620a830d36782c92cd95e9b4cbe1f3bcfbd0503d5cc7cec4017c69f7291482e219baac62bb3 
Initial Private key:	142eaf727c19dc3f5739872c58b2497f325e72ecfca595b2b0e522a6686122e5 
Initial Public key:	705c10bc00660834d4158d8e12f3454b40e71842f9005588cfe2b31452e937b7,679bc54986c77f3bae8e8b9a25f076d251474c0657f5a2f9ce5f75a4f3777e96 
Target Private key:	41417931a29d6facc9a8ca912c706d4d02f649fbe4fd1c5e076960981df45b04 
Target Public key:	64269f853892b302f8645ac51a8fda719d464b59a889d104c11e927d6175237f,59dabe12de1f8f347903a0737b83e766fe78fe00f51a832a148647e5a716ba0d 
Decrypted:	Hello

Here is the running code:

Conclusions

It all sounds confusing. Alice encrypts with her public key, and the only key to decrypt this should be her private key, but with transform encryption, Bob can decrypt with his private key. Mind-blowing!

If you want to learn more about Rust and cryptography, try here:

https://asecuritysite.com/rust/

If you want to support the maintenance of Asecuritysite, consider subscribing here: