Getting Started

IronCore is a data privacy SDK and cloud service. The getting-started-react repo is a sample React application that uses IronCore to grant, monitor and revoke access to sensitive data.

Clone, install, start

git clone https://github.com/IronCoreLabs/getting-started-react.git
cd getting-started-react
npm install

This sample React application can be run in two different modes to showcase how to layer in application level encrytion to your app. At first we will run the application where none of the data is enrypted to get an idea for how the application functions. Then you can run the application with IronCore's IronWeb JavaScript SDK to show how data can be end-to-end encrypted and decrypted directly within a React client application.

To start up the app in its initial state, run

npm run insecure

This will automatically open up a new tab on your browser and point to the demo application running on localhost:3000.

Our mission

Our mission is to develop an application for Captain James T. Kirk of the Starship Enterprise. When the Enterprise explores a new planet, Captain Kirk selects crewmembers to visit the planet surface. These crewmembers make up the away-team. Kirk needs to be able to send the away-team orders without having the commands be seen by adversaries.

As the captain of the Starship Enterprise,
I want a way to securely share commands with my away team,
So that Romulans and Klingons do not intercept my commands and kill us.

When you load the application for the first time, you will be logged in as Captain Kirk and an away-team group with Captain Kirk as a member is created behind the scenes. We'll start first by creating our first order.

Creating Our First Order

Encrypt an order with these three steps:

  1. Enter an order title
  2. Enter an order message
  3. Click Encrypt your order

NOTE: As mentioned above, for the purposes of this part of the demo, our first orders will not be end-to-end encrypted in our sample application.

Once a new plaintext order is added it will appear in the list of orders below the creation form. Now that we have our first order, let's experiement with what other members of the Starship Enterprise can see. Click on the "Acting as: Kirk" in the top right of the screen to simulate logging in as another member of the Starship Enterprise. For now, none of these other users are part of the away-team group.

Pick another user from this list to log in as them. From this users perspective they'll see the order Kirk created and are able to see the contents of the order. Because this order wasn't encrypted, any other user in the system can see it, whether they should be able to or not.

In the majority of todays applications restricting who has access to see what data is implemented via access control logic. In many applications this logic can be complex, brittle, and easy to introduce bugs which can lead to data breaches. Encrypting this data provides a much better layer of security.

Enabling IronCore Encryption

Now that we understand the core concepts of how our sample application works, let's seamlessly add in the IronWeb JavaScript SDK to end-to-end encrypt our secret orders. From the terminal run:

npm run secure

This will open the application again and everything will look the same, but now all the orders that are created will be end-to-end encrypted and only viewable by those we allow. While logged in as Kirk, create a new order and encrypt it. The new order will show up in the list. At this point the order content is fully encrypted and viewable only by Kirk. You can click the order title to see a decryption happen directly in the browser to reveal the encrypted content.

Unauthorized Decrypt

Now change the actively logged in user to Spock. When logged in as a different user, you'll see that they are not able to see the encrypted order that we created.

Let's see what happens when Captain Kirk adds Spock to the away-team group.

Adding Users to the Away Team

  1. Click Acting as: Spock to drop down the list of crew members.
  2. Select Kirk

Now add Spock to the away-team group with the following steps:

  1. Click the Manage Away Team button in the upper right header.
  2. Click the + sign next to Spock.
  3. While we are here, add Redshirt as well by clicking the + sign next to his avatar.

Now switch back to login as Spock. You will see that this time, Spock is able to see the decrypted order:

Fascinating.

Without touching the underlying data (order), Spock is granted access to the encrypted command. Behind the scenes, IronCore is using transform encryption. Transform encryption allows ciphertext encrypted to a group (e.g., the away team) to be transformed into ciphertext encrypted to a group member (e.g., Spock). The group member then locally decrypts data using their private key.

Transform encryption is referred to as proxy-encryption (PRE) in the academic literature. IronCore is the first commercialization of proxy-encryption (PRE). You can read more about transform encryption in the ACM paper Cryptographically Enforced Orthogonal Access Control at Scale

Revoke access

Now to continue our voyage.

Unfortunately, Ensign Redshirt did not return from the latest away team mission. Captain Kirk has to, ahem, offboard him. Remove Redshirt from the away team with the following steps:

  1. Make sure you are Acting as: Kirk
  2. Click on Manage Away Team to open the Team Management side drawer.
  3. Remove Redshirt from the away-team.
  4. Switch Acting as: Kirk to Acting as: Redshirt.

You will see that Ensign Redshirt is unable to decrypt the command.

Again, without touching the underlying data, you are able to revoke access to it. If you have heard about the GDPR privacy right to forget, this is an effective way to implement it.

Implementation Details

Now let's dig into the details about how this React application implements end-to-end encryption. Our React application uses the popular Redux library to handle state management. Changing from a plaintext order version to one that is fully end-to-end encrypted involves adding Redux Middleware to handle encrypting and decrypting orders as actions are triggered in our application.

We have two separate middleware methods for encrypting and decrypting content as it passes through our Redux flow.

Encryption Middleware

export const encryptionMiddleware = (store) => (next) => (action) => {
    if (action.type === "ADD_ORDER") {
        return encryptNewOrder(next, action, store.getState().awayTeam.id);
    }
    next(action);
};

Our encryption middleware filters the actions to just the ADD_ORDER action. This allows other non encryption related actions to be ignored by our middleware. When we do have an ADD_ORDER Redux action, the following method handles it:

function encryptNewOrder(next, action, awayTeamID) {
  return IronWeb.document
    .encrypt(IronWeb.codec.utf8.toBytes(action.payload.body), {accessList: {groups: [{id: awayTeamID}]}})
    .then((encryptedDoc) => {
      next({
        ...action,
        payload: {...action.payload, body: IronWeb.codec.base64.fromBytes(encryptedDoc.document), id: encryptedDoc.documentID, encrypted: true},
      });
    })
    .catch((e) => {...});
}

Our encryption middleware takes the ADD_ORDER action and encrypts the action's payload.body while at the same time granting access to the document to our away-team. Upon success, it replaces the actions payload with the resulting encrypted content and augments the data to denote that it has been encrypted. This action is then passed along in its normal Redux flow which, for most applications, ends up making a request to the backend service to store the data.

Decryption Middleware

export const decryptionMiddleware = (state) => (next) => (action) => {
    if (action.type === "GET_ORDER") {
        //When we get an action for a new order we need to conditionally decrypt it if the data is encrypted. If this
        //order was created prior to encryption, we just want to pass it along. Otherwise we want to decrypt it and pass
        //along an action with the decrypted data.
        if (action.payload.encrypted) {
            //Data is encrypted, decrypt, and then modify the action content with the decrypted content before dispatching
            return decryptOrder(next, action);
        }
        return next(action);
    }
    next(action);
};

Our decryption middleware is similar to encryption where it will first filter the actions that it cares about to only the GET_ORDER action. This also has a check to make sure the data is encrypted before attempting to decrypt the data. When we get an encrypted GET_ORDER Redux action, the following method handles it:

function decryptOrder(next, action) {
  IronWeb.document
    .decrypt(action.payload.id, IronWeb.codec.base64.toBytes(action.payload.body))
    .then((decryptedDoc) => {
      next({
        ...action,
        payload: {...action.payload, body: IronWeb.codec.utf8.fromBytes(decryptedDoc.data)},
      });
    })
    .catch((e) => {...});
}

Upon decrypt, we use the IronWeb SDK to decrypt the action's payload.body at which point we replace that data with our decrypted content before sending it along to the next step in the Redux action flow.

By implementing this encryption/decryption workflow with a Redux middleware we were able to seamlessly add end-to-end encryption to our application without having to re-architect any major parts. This can be seen by the fact that the only difference between running npm run insecure and npm run secure is whether this Redux middleware is applied to our applictaion or not.

The Final Frontier

That completes your first mission. By adding a new Redux middleware you've built an application that has better privacy and security than most web applications on Earth.

Now it's time to explore integrating IronCore into your application. To do so, sign up for your account at https://admin.ironcorelabs.com/.

Live long and prosper.