Recreating Keys In An Oblivious Way In : Breakglass and Transform Encryption

In a new paper, the authors focus on creating a break glass approach to the recovery of user identities and credentials within a…

Recreating Keys In An Oblivious Way In The Cloud: Breakglass and Transform Encryption

In a new paper, the authors focus on creating a break-glass approach to the recovery of user identities and credentials within a Cloud-based infrastructure and where the Cloud cannot determine the original key (which Alice has lost) and a newly generated secret key [here][2]:

It proposes a method where Alice keeps her secret in the Cloud, and where she can lose all of her credentials and secrets but still be able to recover them. It bases its work on the Breakglass Encryption method as defined by Scafuro [1].

The method defines a way for Alice to recover her secret but not for the Cloud to discover the secret (s). Usually, Alice would have a recovery key (Rk), and use this to encrypt the secret, and then store it in the Cloud. But what happens when Alice forgets (or loses) this key, too? She would then not be able to recover the secret.

The solution in the paper is to use a trusted execution environment (TEE), and which is a private space on an untrusted cloud host. This TEE is then isolated from the Cloud it runs in. The TEE then stores the recovery key (Rk), and will be used in an emergency to decrypt the secret (s), and then re-encrypt with a new key that Alice defines (pk). The Cloud never gets a chance to see the transformation for Rk into pk.

Overall, the cloud cannot see any of the details of this operation. For this, the oblivious transfer of the new key (pk) is the most challenging part of the research paper, and how does the TEE stop another party from spoofing Alice? For this, the paper uses a credentialless cryptographically secured permission method to allow Alice to authenticate herself — even when she loses all her credentials. Alice then asks for the certificate for access; and where this is only granted in exceptional circumstances.

Transform encryption

Another method of recreating a key is to use transform encryption. Let’s say that Alice has stored an encrypted file which uses a given key (KA). 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 (Epk(KA)):

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 (TAB). 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).

Now you should know that in public-key encryption, 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 will 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 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.

First we create with:

cargo new transform

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

[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="Hello123";

let args: Vec = 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 (alice_priv_key, alice_pub_key) = recrypt.generate_key_pair().unwrap();
let encrypted_val = recrypt.encrypt(&pt, &alice_pub_key, &signing_keypair).unwrap();


let (bob_priv_key, bob_pub_key) = recrypt.generate_key_pair().unwrap();

let alice_to_bob_transform_key = recrypt.generate_transform_key(
&alice_priv_key,
&bob_pub_key,
&signing_keypair).unwrap();

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

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

println!("\nInput string:\t{} ",mystr);
println!("\nSigning key:\t{} ",hex::encode(unsize(signing_keypair.bytes())));
println!("\nalice Private key:\t{} ",hex::encode(unsize(alice_priv_key.bytes())));
let (x,y)=alice_pub_key.bytes_x_y();
println!("\nalice Public key:\t{},{} ",hex::encode(unsize(x)),hex::encode(unsize(y)) );
println!("\nbob Private key:\t{} ",hex::encode(unsize(bob_priv_key.bytes())));
let (x,y)=bob_pub_key.bytes_x_y();
println!("\nbob 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 [here]:

cargo build

A sample run is [here]:

Signing key:    3b8c142e3ce8b4ed2f86d1fcc8d0eb65cd0f53bc379f5320201414053b2917601a66d2a14003c7b6484b1a42cfd5b958ee68999882c4e04f60708d32dd12a113 
alice Private key: 14b08e8bf6d732d42a00de1cd7e40116cfdaea01e95d7db5a1a0af1e4c8b6aa4
alice Public key: 19a8a55d65bfbc1c92f90d977dd4f3ec6c27be60391628c1b8cfc6db415383d1,5404ffda817c57158c4e675381df07b99630f28b458d8a61ad69ea9293f52cf0
bob Private key: 58e8a2ae6af497b7f5315eb7f1d3d1034ab590ffce1635979833b3cc86a12611
bob Public key: 51a202aafb4bfd0b94737cc659dc8ad83a6aa46a22651b975d77c6880c7310c4,3ec0d6e0ce78dd3825740b5605ff2f2cfd6fa39d5d1fe683889d0b6bd5bb4a83
Decrypted: Hello123

An outline is here:

Conclusions

Alice needs to regenerate her core secret but needs to hide it from others. The break glass and transform encryption approach allows this to happen.

Reference

[1] Scafuro, A. (2019). Break-glass encryption. In Public-Key Cryptography–PKC 2019: 22nd IACR International Conference on Practice and Theory of Public-Key Cryptography, Beijing, China, April 14–17, 2019, Proceedings, Part II 22 (pp. 34–62). Springer International Publishing.

[2] Chris Orsini and Alessandra Scafuro and Tanner Verber (2023), How to Recover a Cryptographic Secret From the Cloud, https://eprint.iacr.org/2023/1308.