Leveraging Encrypted Data with InnoVault

Tozny’s new InnoVault product makes it easy for developers to request personally-identifying information (PII) in contact forms without risking the leak of that information. This is because InnoVault uses strong encryption on the client side (in the browser) to prevent ever sending this data in a readable format. Even Tozny can’t read your data!

The developer, however, can use their private credentials to request the data from Tozny’s e3db platform. They can then decrypt the data securely on their end, again using private decryption keys that no one else can access.

The fully end-to-end encrypted nature of data in housed in InnoVault (and the backing e3db datastore) enables end users to trust their information is secure and protected. The data is only ever exposed in plaintext when it’s being used to produce a report or conduct some sort of analysis. Even then, it’s only ever available to a party authorized to retrieve it and empowered to decrypt it.

We wanted to take a moment to highlight the entire process, from the creation of a protected contact form to extracting the data to run a report.

InnoVault Client

The very first step is to register with and create an InnoVault account. The InnoVault Admin Console requires a password, but this password is never stored on Tozny’s server. Instead, it’s used to derive an authentication key used locally to sign a login challenge. Tozny never sees your password and can never expose it to third parties.

InnoVault Admin Console Client Management

The client management screen allows managers to create new clients (and retrieve backed-up keys and credentials in an emergency).

Once logged in, you will need to create a “client.” This is a set of credentials that you will use later to interact with the e3db data storage system. Creating a client requires you to confirm your password, then enter a unique name you can use to differentiate between various clients. The admin console will securely create a set of encryption keys for you and register the client with Tozny.

InnoVault Admin Console Client Management

Client credentials are presented both in traditional input fields (for easy reference) and in a handy JSON format for use with the e3db CLI utility.

Tozny only ever sees your new client’s public key – the private key never leaves the browser. Take some time to make note of the credentials displayed after the client is registered because Tozny has no way to recover them for you if they’re lost.

Finally, you need to use the InnoVault Admin Console to create a “form” that will manage incoming customer data submissions. Add the form on the “Manage Forms” screen by giving it a unique name (to differentiate multiple forms), specifying a unique name for the type of data this form will contain (for this example, call it “vote”), and selecting the client created in the previous step.

InnoVault Form Creation

InnoVault forms require a unique name, a record type, and a client with which they will be associated.

Once the form has been created, click “Retrieve Token” to generate a unique token for the form. This token is used with the InnoVault SDK and identifies the client for which the form will write its data. Unlike the client credentials you retrieved above, the form token is not meant to be private – we’ll be adding it directly to the HTML of our voting form.

The Form

For this example, we’ll build a simple voting form that can be used by community groups to poll for and surface opinions. The impetus behind such a form is to keep voting private while still keeping track of who has or hasn’t voted and collating any free-form comments submitted independently. We will keep the names of voters and their votes together in the form, but don’t want anyone to see that association publicly by mistake.

The form as such is relatively simple:

<html>
<head>
  <script type="text/javascript" src="https://js.innovault.io/1.0.2/innovault-web.min.js" integrity="sha384-7Fnanu/5+Mu87uh9hZfwbp00SSCA8y5u1F/DUQe2u9wrrCxTVI/aaCAD5qS68RKE" crossorigin="anonymous"></script>
</head>
<body>
  <h1>Community Poll
  <form name="poll" method="post">
    <p>
      <label for="fullname">Full Name</label>
      <input name="fullname" />
    </p>

    <p>
      <label>Should we have speed bumps on Main St.?</label>
      <input type="radio" name="vote" value="yes" checked />
    </p>

    <p>
      <label>Should we cancel the summer BBQ?</label>
      <input type="radio" name="bbq" value="yes" /><label for="yes">Yes</label>
      <input type="radio" name="bbq" value="no" checked /><label for="no">No</label>
    </p>

    <p>
      <label for="comments">Other Comments</label>
      <textarea name="comments"></textarea>
    </p>

    <p>
      <button type="button" onclick="submitVote()">Vote!</button>
    </p>
  </form>
  <script type="text/javascript">
    function submitVote() {
      var token = '...';
      var vote = {
        fullname: document.forms.poll.fullname.value,
        vote: document.forms.poll.vote.value,
        bbq: document.forms.poll.bbq.value,
        comments: document.forms.poll.comments.value
      };

      window.innovault.web.sdk.submit(token, vote)
        .then(function(data) {
          // Clear out old values in the form to prevent duplicate submissions
          document.forms.poll.vote.value = 'yes';
          document.forms.poll.bbq.value = 'no';
          document.forms.poll.fullname.value = document.forms.poll.comments.value = '';
          alert('Thanks for voting!');
        });

      return false;
    }
  </script>
</body>
</html>

The community members are voting on two potentially controversial issues: installing speed bumps on the town’s main street and canceling a beloved community event. Some might be interested in leaving further comments that should be collected and collated.

This example is using the web variant of the InnoVault SDK that permits programmatic control over the form submission. This is due to the fact that radio buttons (used in the vote) are not supported via InnoVault’s easy SDK variant. If the form were a simple text entry (i.e. no voting), this HTML could be drastically simplified. Please take some time to review the documentation of the Easy SDK variant to see how it differs (and makes forms simple to encrypt).

When our community members submit this form, the data will be collected into a JSON blob, encrypted in the browser, then submitted to InnoVault for storage until you’re ready to use it.

Extracting Data

Retrieving the data can take one of two forms. On the one hand, a developer could use the client credentials created earlier with the e3db CLI to read the data directly. This would help a developer quickly audit that data is flowing from the form to the database as expected, but runs the risk of exposing that data to the developer as well.

e3db CLI

While not an ideal data retrieval route, privileged developers can use the e3db CLI to query for and inspect records written by InnoVault forms.

As the point of this voting form is to keep this data private, we want to produce a script that can read the data, separate it into the different components we want, and produce a static report for us easily. To that end, we’ll break things down into three different scripts: one each for retrieving a list of those who’ve voted, summarizing the yes/no votes on our two questions, and collecting the freeform comments for later analysis.

The e3db SDK

At the time of this writing, there are 4 different SDKs available for use with e3db – Go, Ruby, PHP, and Java. All four SDKs are fairly similar in structure, so following these examples in your language of preference will be relatively straight-forward. For the sake of this example, we will use the Ruby SDK.

Voter Names

Every voter has specified their names in a field called fullname. The e3db SDK will return all fields, but our script can ignore the rest of the data and only collate the field we care about.

This script will fetch all votes, collect the voters’ names into a list, randomize the list, then print the list out to the console:

require 'e3db'

config = E3DB::Config.load_profile('ex')
config.logging = false
client = E3DB::Client.new(config)

voters = Array.new
  client.query(type: 'vote').each do |record|
  voters.push(record.data[:fullname])
end

puts voters.shuffle

Vote Tallies

Along a similar vein, we want to know how many people voted yes or no to our two questions. What we don’t want to know is who voted for which option.

This script will again fetch all votes, but it will only collect the votes themselves into specific counters. Once all votes are tabulated, they’re printed to the console:

require 'e3db'

config = E3DB::Config.load_profile('ex')
config.logging = false
client = E3DB::Client.new(config)

votes = 0
speedbumps = 0
bbq = 0
client.query(type: 'vote').each do |record|
  votes += 1

  if record.data[:vote] == 'yes'
    speedbumps += 1
  end

  if record.data[:bbq] == 'yes'
    bbq += 1
  end
end

puts('Total Votes:                    ' + votes.to_s)
puts('In favor of speed bumps:        ' + speedbumps.to_s)
puts('In favor of cancelling the BBQ: ' + bbq.to_s)

Assuming a total of 8 community members have voted, the results of this vote (and the script to tabulate them) could look something like:

Tabulated Vote Results

The script counts “yes” votes and keeps track of the total number of voters, making it easy to determine which option “won.”

Comment Collation

Finally, we want to keep track of any freeform comments left by our voters. As with the previous two examples, while the data is important, we don’t want to keep track of who commented what in the event that it’s sensitive information. Instead, our script will gather all of the votes, collect the various comments into an array, randomize it, then print the array to the console:

require 'e3db'

config = E3DB::Config.load_profile('ex')
config.logging = false
client = E3DB::Client.new(config)

comments = Array.new
  client.query(type: 'vote').each do |record|
  comments.push(record.data[:comments])
end

puts comments.shuffle

This script is almost identical to the one that collected voter names (as both fullname and comments are simple text fields, that’s to be expected). In a more sophisticated example, this data could be exported as a comma-delimited list and piped to a CSV file for import into a spreadsheet application.

Next Steps

The point of these examples is to illustrate how InnoVault data can be securely extracted from the encrypted e3db datastore using simple scripts. While the examples above used Ruby, they would look very similar written in any of the other supported SDK languages.

A next step could be to use a hosted system like Amazon Lambda with the Java SDK to build a system that automatically collates reports without a human ever having access to the raw data. A similar operation would be to collate the data and produce new records, also stored in e3db, that present the summaries. These new entries would also be safely encrypted but could be easily shared with less-privileged parties who need to understand the outcomes of such a vote without having access to the underlying raw data.

A next step for anyone just getting started, though, would be to create an InnoVault account and give the platform a try. It’s free for the first 2,000 records stored to give developers a chance to get hands-on experience before making a commitment.