Back to top

Overview

Supported SDKs

Protect, track & control data with the Virtru SDK in the following languages:

Virtru SDK for Client-side JavaScript

JavaScript SDK Documentation

Quick Start: Client-Side JavaScript

You’re Alice and you have sensitive data to protect. (Don’t we all?) Let’s see the fastest way to protect it client-side with the Virtru JavaScript SDK:

Prerequisites

Note: These steps assume a *nix style command line, as available in macOS and linux

0. Run a basic server

Because the Virtru JavaScript SDK respects strong security practices like CORS, you’ll need to run a basic web server for your first app. Running JavaScript in a local HTML file will not work.

        <html>
            <head>
              <title>Boilerplate - Virtru SDK for JavaScript - Sample Application</title>
              <script src="https://sdk.virtru.com/js/2.1.0/virtru-sdk.min.js"></script>
            </head>
            <body>
              <script type="text/javascript">
                alert("Virtru.Version: " + Virtru.Version);
              </script>
            </body>
          </html>
        
      

Let’s use Parcel for packaging, which also provides a local web server with a self-signed HTTPS certificate for testing.

npm install -g parcel parcel --https index.html

Open your browser of choice to https://localhost:1234, Parcel's default URL.

1. Get an identity

So Alice, who should own your sensitive data? You, obviously!

Authenticate to associate your email address (e.g. alice@example.com) with any data you protect. You cannot protect data without authenticating. If the Virtru Platform doesn’t know who’s protecting data, no one would be able to access it later (when they’re also asked to authenticate).

The fastest way to authenticate is with Virtru’s auth widget.

      <html>
          <head>
            <title>Auth - Virtru SDK for JavaScript - Sample Application</title>
            <link
              href="https://sdk.virtru.com/js/latest/auth-widget/index.css"
              rel="stylesheet"
            />
            <script src="https://sdk.virtru.com/js/latest/auth-widget/index.js"></script>
            <script src="https://sdk.virtru.com/js/2.1.0/virtru-sdk.min.js"></script>
          </head>
          <body>
            <div id="virtru-auth-widget-mount"></div>
            <script src="./main.js"></script>
          </body>
        </html>
      
    
      
         function afterAuth(email) {
          alert(`Hello, ${email}. You're ready to protect with Virtru!`);
        }
        
        // Set up Virtru auth widget
        Virtru.AuthWidget("virtru-auth-widget-mount", { afterAuth });
      
    
2. Ask for sensitive data

Now that we know who will own things, why don’t you enter your first piece of sensitive data? For simplicity’s sake, let’s use a quick string.

      
        function afterAuth(email) {
          // Ask for sensitive data
          const yourString = prompt("Type something to encrypt: ", "sensitive data...");
        }
        
        // Set up Virtru auth widget
        Virtru.AuthWidget("virtru-auth-widget-mount", { afterAuth });
      
    
3. Protect the sensitive data

To protect your sensitive data, we’ll need a Virtru client. We’ll associate anything you encrypt with your email (from the auth widget):

      
        const client = new Virtru.Client({ email });
      
    

Next, decide your encryption options. For now, it’s the string containing your sensitive data. In the future, this could include who else should have access and under what conditions.

    
      const encryptParams = new Virtru.EncryptParamsBuilder()
        .withStringSource(plainText)
        .build();
    
    

Finally, since the encrypt call is asynchronous, we’ll wait for it to finish:

    
      const ciphertextStream = await client.encrypt(encryptParams);
      console.log(await ciphertextStream.toString());
    
    

How do we know it worked? We should see ciphertext when we examine what got returned from encrypt.

      
        async function afterAuth(email) {
          // Ask for sensitive data
          const plainText = prompt("Type something to encrypt: ", "sensitive data...");
        
          // Client will enable all other work
          const client = new Virtru.Client({ email });
        
          // Protect the sensitive data
          const encryptParams = new Virtru.EncryptParamsBuilder()
            .withStringSource(plainText)
            .build();
          const ciphertextStream = await client.encrypt(encryptParams);
          console.log(await ciphertextStream.toString());
        }
        
        // Set up Virtru auth widget
        Virtru.AuthWidget("virtru-auth-widget-mount", { afterAuth });
      
  
4. Access the sensitive data now

Now, let’s say you need to see your sensitive data again immediately. Well, you’re still authenticated as alice@example.com so you can decrypt the ciphertext:

    
      async function afterAuth(email) {
        // Ask for sensitive data
        const plainText = prompt("Type something to encrypt: ", "sensitive data...");
      
        // Client will enable all other work
        const client = new Virtru.Client({ email });
      
        // Protect the sensitive data
        async function encryptToString(plain) {
          const encryptParams = new Virtru.EncryptParamsBuilder()
            .withStringSource(plain)
            .withDisplayFilename("sensitive.txt")
            .build();
          const ciphertextStream = await client.encrypt(encryptParams);
          const ciphertext = await ciphertextStream.toString();
          return ciphertext;
        }
        let ciphertext = await encryptToString(plainText);
      
        // Access the sensitive data now
        async function decryptFromString(ciphertext) {
          const decryptParams = new Virtru.DecryptParamsBuilder()
            .withStringSource(ciphertext)
            .build();
          const plaintextStream = await client.decrypt(decryptParams);
          const plaintext = await plaintextStream.toString();
          return plaintext;
        }
        let decrypted = await decryptFromString(ciphertext);
      
        // Validate that the original value and its decrypted version are the same.
        if (plainText === decrypted) {
          alert("The decrypted string matches your original one!");
        } else {
          alert(
            `ERROR: Output, [${decrypted}], does not match input, [${plainText}]`
          );
        }
      }
      
      // Set up Virtru auth widget
      Virtru.AuthWidget("virtru-auth-widget-mount", { afterAuth });

  

But what if you close this tab or stop your web server? We need to remember the sensitive data we protected to access it later.

5. Access the sensitive data again later

The Virtru SDK lets you save your ciphertext as an HTML file you can open again later. This is also asynchronous.

        
          async function afterAuth(email) {
            // Ask for sensitive data
            const plainText = prompt("Type something to encrypt: ", "sensitive data...");
          
            // Client will enable all other work
            const client = new Virtru.Client({ email });
          
            // Protect the sensitive data
            async function encryptToFile(text, encryptedFilename) {
              let displayFileName = encryptedFilename.replace(".tdf.html", "");
              const encryptParams = new Virtru.EncryptParamsBuilder()
                .withStringSource(text)
                .withDisplayFilename(displayFileName)
                .build();
              const ciphertextStream = await client.encrypt(encryptParams);
              await ciphertextStream.toFile(encryptedFilename);
            }
          
            // Access the sensitive data again later
            let encryptedFilename = "sensitive.txt.tdf.html";
            await encryptToFile(plainText, encryptedFilename);
          }
          
          // Set up Virtru auth widget
          Virtru.AuthWidget("virtru-auth-widget-mount", { afterAuth });
        
    
6. Access the sensitive data anywhere

If you inspect the generated HTML file, you still won’t find your sensitive data. It stays protected. You can send that HTML file to another machine or anywhere you want. Only you will be able to access it. But how do you do that outside of this code?

We could build a whole set of functionality to authenticate, decrypt, and render files. Or we could use Virtru’s Secure Reader, which is built to do exactly that for thousands of security-conscious users every day. In fact, if you open that HTML file from the last step, it will redirect you to Secure Reader.

Secure Reader will ask you to authenticate. (You’re still Alice, aren’t you?)

Authenticating with Virtru Secure Reader

And if you authenticate with the same email address you used to create the HTML file, you should be able to view it in Secure Reader:

Decrypting with Virtru Secure Reader

Congrats Alice! Your sensitive data is safe wherever it goes.

Client-Side JS Authentication

Security starts with identity. You claim you’re Alice, but the Virtru SDK doesn’t know that. We can’t protect or access data without an identity that’s responsible for protecting or accessing that data. Otherwise, no one (or anyone) would be able to do whatever they want with your data. But we all have sensitive data to protect.

So how do you prove your identity to the Virtru SDK? We’re glad you asked, “Alice…”

Here are your options in web browsers and mobile apps:

  1. Drop in the Auth Widget to make SDK calls and show UI
  2. Send and confirm email codes via SDK calls and custom UI
  3. Use Federated Authentication via SDK calls and custom UI

These options are mutually exclusive from server-side Node.js Authentication.

Auth Widget

The Virtru auth widget is the fastest way to add authentication. We recommend it if you’re getting started with the Client-side JavaScript SDK. It includes the other client-side authentication options—email codes and federated authentication.

Virtru provides an auth widget with all client-side authentication calls and standard UI from Virtru’s products. You only have to specify an HTML element to render the widget and a callback for whatever needs to happen after users authenticate.

      <html>
            <head>
              <title>Auth - Virtru SDK for JavaScript - Sample Application</title>
              <link
                href="https://sdk.virtru.com/js/latest/auth-widget/index.css"
                rel="stylesheet"
              />
              <script src="https://sdk.virtru.com/js/latest/auth-widget/index.js"></script>
              <script src="https://sdk.virtru.com/js/2.1.0/virtru-sdk.min.js"></script>
            </head>
            <body>
              <div id="virtru-auth-widget-mount"></div>
              <script>
                function afterAuth(email) {
                  alert(`Hello, ${email}. You're ready to protect with Virtru!`);
                }
          
                // Set up Virtru auth widget
                Virtru.AuthWidget("virtru-auth-widget-mount", { afterAuth });
              </script>
            </body>
          </html>
      
  
Email Codes

Email codes are alphanumeric codes that prove your identity for a short session. Codes expire in 15 minutes.

The Virtru SDK lets you send email codes to alice@example.com:

      
      Virtru.Auth.sendCodeToEmail({ email: "alice@example.com" });
    
    

You would then check alice@example.com’s inbox and copy the code from the Virtru email. And submit that code back to the SDK:

      
        Virtru.Auth.activateEmailCode({
          email: "alice@example.com",
          code: "V-12345678"
        });
      
  

If the code submitted matches the code sent, the Virtru JavaScript SDK remembers your authentication status. You can confirm that by checking:

    
      Virtru.Auth.isLoggedIn();
    
  
Federated Authentication

Federated Authentication is a good option for users to authenticate faster with OAuth providers (e.g. Google, Office 365, or Outlook). You’ll need to whitelist your domain for this option. You can test this option locally with the local.virtru.com domain like so:

    echo "127.0.0.1       local.virtru.com  # Local Virtru SDK testing" >> /etc/hosts

Once your domain is white listed, you can call methods like loginWithGoogle to let Google handle the authentication:

    
      Virtru.Auth.loginWithGoogle({ email: "alice@example.com" });
    
  

This call goes to the Virtru Platform. If your domain is not whitelisted, this call will fail. If your domain is white listed, it will ask you to log in with Google.

Whichever email address you authenticate with Google (e.g. alice@example.com or alice@somewhere.org) will be sent back to the Virtru Platform and authenticated for future Virtru JavaScript SDK calls. The Platform will redirect you back to your app.

Checking authentication status

How can you check if a user authenticated? This should work for any of the authentication methods above.

      
        Virtru.Auth.isLoggedIn();
      
    

Encrypt

Now that the Virtru SDK knows you’re Alice, you can protect your first piece of data.

Client-Side JS Encryption

Before calling encrypt, you need to specify a few simple parameters.

You don’t need to include your email address when encrypting. You will already have access to anything you encrypt because you authenticated. But if you want anyone else to have access (like another one of your emails, alice@nowhere.com), you could include them here:

    
      // specify access controls
      const policy = new Virtru.PolicyBuilder()
        .addUsersWithAccess(["alice@nowhere.com"])
        .build();
      
      // protect & output
      const encryptParams = new Virtru.EncryptParamsBuilder()
        .withStringSource(unprotectedString)
        .withDisplayFilename(unprotectedFile)
        .withPolicy(policy)
        .build();
    
  

Call encrypt and check out the resulting file:

    
      const protectedStream = await client.encrypt(encryptParams);
      const protectedExt = ".tdf.html"; // HTML format
      const protectedFile = unprotectedFile + protectedExt;
      await protectedStream
        .toFile(protectedFile)
        .then(() => console.log(`Encrypted file ${protectedFile}`));
    
  

Here's the complete source code:

    
      // Encryption example - HTML format
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function protect(unprotectedString) {
        const unprotectedFile = "sensitive.txt";
      
        // specify access controls
        const policy = new Virtru.PolicyBuilder()
          .addUsersWithAccess(["alice@nowhere.com"])
          .build();
      
        // protect & output
        const encryptParams = new Virtru.EncryptParamsBuilder()
          .withStringSource(unprotectedString)
          .withDisplayFilename(unprotectedFile)
          .withPolicy(policy)
          .build();
        const protectedStream = await client.encrypt(encryptParams);
        const protectedExt = ".tdf.html"; // HTML format
        const protectedFile = unprotectedFile + protectedExt;
        await protectedStream
          .toFile(protectedFile)
          .then(() => console.log(`Encrypted file ${protectedFile}`));
      }
    
  

Now, your sensitive data is safe. Keep reading to see how or access your data by decrypting.


Encryption Lifecycle

That one little encrypt call did a lot of work behind the scenes to keep your sensitive data safe:

Protecting a file and sending the policy and key materials to Virtru

  • Step 1: Your app authenticates with Virtru's entity service.

    This was when you proved you were alice@example.com.

  • Step 2: Then, an encrypt call protects any given data as ciphertext. This ciphertext is local to where encrypt was called (a browser, end user device, or server). Although encrypt uses the open Trusted Data Format (TDF), you can save the ciphertext in a file format that you can open anywhere—HTML.

    This was when your sensitive data became protected.

  • Step 3: While an encrypt call keeps the protected data as local ciphertext, a secure decryption key travels back to Virtru’s key server for safe-keeping. But this key server doesn’t hand out keys to anyone…

    This is why you don’t have to manage keys yourself.

  • Step 4: While an encrypt call keeps the protected data as local ciphertext, the SDK saves the access controls for the protected data in Virtru’s access server. The access server determines if a particular authenticated user (Step 1) can access protected data (Step 2) using a decryption key (Step 3).

    This is the crucial backend you don’t have to build or host. It never has access to your local data.


Encrypted File Formats

We generated a .tdf.html file above. This is the SDK default, but not the only option.

HTML Format ZIP Format
File Extension .tdf.html .tdf
File Size File sizes less than 100 MB Any file size
Decryption Any Virtru SDK Any Virtru SDK
User Experience Open file anywhere to redirect to Virtru's Secure Reader Drag & drop in Virtru's Secure Reader

If you need a protected ZIP file, add it to the encrypt params and set the file extension:

    
      // Encryption example - ZIP format
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function protect(unprotectedString) {
        const unprotectedFile = "sensitive.txt";
      
        // specify access controls
        const policy = new Virtru.PolicyBuilder()
          .addUsersWithAccess(["alice@nowhere.com"])
          .build();
      
        // protect & output
        const encryptParams = new Virtru.EncryptParamsBuilder()
          .withStringSource(unprotectedString)
          .withDisplayFilename(unprotectedFile)
          .withZipFormat() // ZIP format
          .withPolicy(policy)
          .build();
        const protectedStream = await client.encrypt(encryptParams);
        const protectedExt = ".tdf"; // ZIP format
        const protectedFile = unprotectedFile + protectedExt;
        await protectedStream
          .toFile(protectedFile)
          .then(() => console.log(`Encrypted file ${protectedFile}`));
      }
    
  

And you’ll have a ZIP file with the same level of protection as HTML, but the caveats in the table above.

Drag & Drop Client-side Encryption Example

Here is a complete example with drag & drop uploads that get encrypted. Run the following code with Parcel as in the quick start.

      
        <html>
          <head>
            <title>Protect | Virtru SDK for JavaScript - Sample Application</title>
            <link
              href="https://sdk.virtru.com/js/latest/auth-widget/index.css"
              rel="stylesheet"
            />
            <link href="./protect.css" rel="stylesheet" />
            <script src="https://sdk.virtru.com/js/latest/auth-widget/index.js"></script>
            <script src="https://sdk.virtru.com/js/2.1.0/virtru-sdk.min.js"></script>
          </head>
          <body class="unauthorized">
            <h1>Encrypt a File</h1>
            <div id="auth"></div>
            <div id="input">
              <div id="drop_zone">
                <p>Drag a sensitive file here to encrypt it...</p>
              </div>
            </div>
            <div id="waiting">
              <p>Encrypting file...</p>
            </div>
            <div id="download">
              <a id="download_link" rel="noopener">Save Protected File</a>
            </div>
            <div id="error_box">
              <h3 id="error">An error has occurred</h3>
              <p id="detail"></p>
            </div>
        
            <script src="./protect.js"></script>
          </body>
        </html>
      
    
      
          // Virtru Client. This is set by the auth handler.
          let client;
          
          function dragOverHandler(e) {
            e.preventDefault();
          }
          
          // Set the error message
          function setAlert(error, detail) {
            if (error) {
              document.getElementById("error").textContent = error;
            }
            if (detail) {
              document.getElementById("detail").textContent = detail;
            }
          }
          
          // Encrypt a file, from a passed in File object.
          async function protect(file) {
            const body = document.getElementsByTagName("body")[0];
            try {
              body.className = "working";
              const encryptParams = new Virtru.EncryptParamsBuilder()
                .withArrayBufferSource(await file.arrayBuffer())
                .withDisplayFilename(file.name)
                .withHtmlFormat();
              // To allow other people to access it, add a Policy here using the PolicyBuilder.
              const ciphertextStream = await client.encrypt(encryptParams.build());
              const ciphertextString = await ciphertextStream.toString();
              const a = document.getElementById("download_link");
              a.download = file.name + ".tdf.html";
              a.href =
                "data:text/html;charset=utf-8," + encodeURIComponent(ciphertextString);
              body.className = "done";
            } catch (e) {
              console.warn({ type: "encrypt failure", cause: e });
              if (e && e.message) {
                setAlert("Encrypt service error", `${e.message}`);
              } else {
                setAlert(
                  "Encrypt service error",
                  "Try refreshing credentials or starting over."
                );
              }
              body.className = "error";
              return;
            }
          }
          
          async function dropHandler(e) {
            e.preventDefault();
          
            const edt = e.dataTransfer;
            if (edt.items) {
              // Use DataTransferItemList interface to access the file(s)
              // Not supported on IE or Safari.
              for (const item of edt.items) {
                if (item.kind === "file") {
                  protect(item.getAsFile());
                }
              }
            } else {
              // Use DataTransfer interface to access the file(s)
              for (const file of edt.files) {
                protect(file);
              }
            }
          
            // Pass event to removeDragData for cleanup
            removeDragData(e);
          }
          
          function removeDragData(ev) {
            console.log("Removing drag data");
          
            if (ev.dataTransfer.items) {
              // Use DataTransferItemList interface to remove the drag data
              ev.dataTransfer.items.clear();
            } else {
              // Use DataTransfer interface to remove the drag data
              ev.dataTransfer.clearData();
            }
          }
          
          function afterAuth(email) {
            client = new Virtru.Client({ email });
            const body = document.getElementsByTagName("body")[0];
            body.className = "start";
          }
          
          const dropZone = document.getElementById("drop_zone");
          dropZone.ondrop = dropHandler;
          dropZone.ondragover = dragOverHandler;
          Virtru.AuthWidget("auth", { afterAuth });
        
    
    #input,
      #auth {
        display: none;
      }
      #drop_zone {
        border: 4px dashed salmon;
        margin: 0em;
        padding: 2em;
        width: 200px;
        height: 100px;
      }
      #waiting {
        border: 8px double gray;
        margin: 0em;
        padding: 2em;
        width: 200px;
        height: 100px;
        display: none;
      }
      #download {
        border: 4px solid blue;
        margin: 0em;
        padding: 2em;
        width: 200px;
        height: 100px;
        display: none;
      }
      #error_box {
        background: black;
        border-radius: 4px;
        margin: 0em;
        padding: 2em;
        width: 200px;
        height: 100px;
        display: none;
        color: white;
      }
      .unauthorized #auth,
      .start #input,
      .working #waiting,
      .done #download,
      .error #error_box {
        display: block;
      }
    
  

Client-Side JS Encryption

Well Alice, the good news is, your first encrypted file is so safe, only you can decrypt it. Let’s confirm that with your protected file. Then, we’ll grant access to someone you trust.

Meet Secure Reader, the easiest way to decrypt

Opening a protected HTML file will take you to Virtru’s Secure Reader.

Authenticating with Virtru Secure Reader

Secure Reader will also ask you to authenticate. Again, no one trusts that you’re Alice. But trust us, it’s good for security. If Mallory tries to authenticate, he won’t see your sensitive data.

But if you authenticate, Secure Reader will render your file.

Decrypting with Virtru Secure Reader

If Secure Reader can’t render the file, you will still be able to download it.

Decrypting via SDK

Outside of Secure Reader, you can also decrypt a file via the SDK:

    
      // Decryption example
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      // decrypt from protected file arraybuffer and save as a new file unprotected file
      async function decrypt(protectedFile, unprotectedFile) {
        // prepare
        const decryptParams = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
      
        // access & output
        const plaintextStream = await client.decrypt(decryptParams);
        await plaintextStream
          .toFile(unprotectedFile)
          .then(() => console.log(`Decrypted file ${unprotectedFile}`));
      }
    
  
Allowing others to decrypt

But let’s say you wanted to share your sensitive data with your trusted colleague Bob, whose email is bob@example.com.

For existing files, you would grant access to bob@example.com and save the changes to the Virtru Platform.

    
      const decryptParams = new Virtru.DecryptParamsBuilder()
        .withArrayBufferSource(protectedFile)
        .build();
      const policyId = await client.getPolicyId(decryptParams);
      const policy = await client.fetchPolicy(policyId);
      const newPolicy = policy
        .builder()
        .addUsersWithAccess(["bob@example.com"])
        .build();
      await client.updatePolicy(newPolicy);
    
  

Now, bob@example.com should be able to view your sensitive data in Secure Reader (anywhere) or via the SDK decrypt call (in your apps).

When protecting new files, you can grant access to Bob or any number of users as part of encryption params:

    
      const policy = new Virtru.PolicyBuilder()
        .addUsersWithAccess(["bob@example.com"])
        .build();
      
      const encryptParams = new Virtru.EncryptParamsBuilder()
        .withStringSource("sensitive data")
        .withDisplayFilename("sensitive.txt")
        .withPolicy(policy)
        .build();
      
      const protectedStream = await client.encrypt(encryptParams);
      await protectedStream.toFile("sensitive.txt.tdf.html");
    
  

Client-Side JS Encryption

No one can predict the future. Access controls let you change your mind about who has access and under what conditions.

Grant Access

Let’s say Bob enters your circle of trust. If you grant him access, he can decrypt your sensitive data.

    
      // Grant existing policy
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function grantAccess(protectedFile) {
        // get policy
        const params = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
        const policyId = await client.getPolicyId(params);
        const existingPolicy = await client.fetchPolicy(policyId);
      
        // update users
        const initialUsers = await existingPolicy.getUsersWithAccess();
        console.log("Initial users with access: " + initialUsers);
        const users = ["bob@example.com"];
        const updatedPolicy = existingPolicy
          .builder()
          .addUsersWithAccess(users)
          .build();
        await client.updatePolicy(updatedPolicy);
        console.log(`Granted access to users: ${users} on encrypted file`);
      }
    
  

You can also grant access before you encrypt:

    
      // Grant new policy
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function protectWithAccess(unprotectedString) {
        let unprotectedFile = "sensitive.txt";
      
        // prepare policy
        const users = ["bob@example.com"];
        const policy = new Virtru.PolicyBuilder().addUsersWithAccess(users).build();
        const encryptParams = new Virtru.EncryptParamsBuilder()
          .withStringSource(unprotectedString)
          .withDisplayFilename(unprotectedFile)
          .withPolicy(policy)
          .build();
      
        // encrypt
        const protectedStream = await client.encrypt(encryptParams);
        let protectedExt = ".tdf.html"; // HTML format
        const protectedFile = unprotectedFile + protectedExt;
        await protectedStream.toFile(protectedFile);
        console.log(
          `Encrypted file ${protectedFile} and granted access to users: ${users}`
        );
      }
    
  
Revoke Access

Let’s say Bob leaves your circle of trust. It’d be great if he no longer had access to your sensitive data. Revoke will prevent Bob from decrypting your sensitive data:

    
      // Revoke access
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function revokeAccess(protectedFile) {
        // get policy
        const params = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
        const policyId = await client.getPolicyId(params);
        const existingPolicy = await client.fetchPolicy(policyId);
      
        // revoke access for user(s)
        const users = ["bob@example.com"];
        const updatedPolicy = existingPolicy
          .builder()
          .removeUsersWithAccess(users)
          .build();
        await client.updatePolicy(updatedPolicy);
        console.log(`Revoked access from users: ${users} on encrypted file`);
      }
    
  

You will still have access to your sensitive data.

Revoke All Access

Let’s say you landed a new job, Alice. Well done! But your circle of trust becomes outdated. Rather than removing every Bob from accessing your sensitive data, you can remove everyone with revoke all:

    
      // Revoke all access
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function revokeAll(protectedFile) {
        // get policy
        const decryptParams = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
        const policyId = await client.getPolicyId(decryptParams);
      
        // revoke access for all users
        await client.revokePolicy(policyId);
        console.log(`Revoked access for all users on encrypted file`);
      }
    
  

You will still have access to your sensitive data.

Expire Access

Some things aren’t meant to last. Your landlord, Trent, shouldn’t have access to the sensitive data in your lease forever. Let’s make sure your sensitive data expires in a year when your lease does:

    
      // Expire access with relative datetime
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function expireRelative(protectedFile) {
        // get policy
        const decryptParams = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
        const policyId = await client.getPolicyId(decryptParams);
        const existingPolicy = await client.fetchPolicy(policyId);
      
        // expire access
        const secondsInYear = 60 * 60 * 24 * 365; // min * hour * day * year;
        const updatedPolicy = existingPolicy
          .builder()
          .enableExpirationDeadlineFromNow(secondsInYear)
          .build();
        await client.updatePolicy(updatedPolicy);
        console.log(`Expire access to encrypted file in ${secondsInYear} seconds`);
      }
    
  

You can also expire at a specific date and time:

    
      // Expire access with specific datetime
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function expireSpecific(protectedFile) {
        // get policy
        const decryptParams = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
        const policyId = await client.getPolicyId(decryptParams);
        const existingPolicy = await client.fetchPolicy(policyId);
      
        // expire access
        const expiresOn = "2022-08-12T14:37:26.101Z"; // ISO-8601 Format
        const updatedPolicy = existingPolicy
          .builder()
          .enableExpirationDeadline(expiresOn)
          .build();
        await client.updatePolicy(updatedPolicy);
        console.log(`Expire access to encrypted file on ${expiresOn}`);
      }
    
  

Expiration prevents everyone else on the policy from decrypting after that time. You will still have access.

Make the same expiration calls to update dates or times.

If you’re feeling permissive, you can always remove expiration too:

      
      // Remove access expiration
      let client;
      
      // assumes Virtru auth widget
      function afterAuth(email) {
        client = new Virtru.Client({ email });
      }
      
      async function expireDisable(protectedFile) {
        // get policy
        const decryptParams = new Virtru.DecryptParamsBuilder()
          .withArrayBufferSource(protectedFile)
          .build();
        const policyId = await client.getPolicyId(decryptParams);
        const existingPolicy = await client.fetchPolicy(policyId);
      
        // remove access expiration
        const updatedPolicy = existingPolicy
          .builder()
          .disableExpirationDeadline()
          .build();
        await client.updatePolicy(updatedPolicy);
        console.log(`Removed access expiration on encrypted file`);
      }
    
  
Watermark Access

Trust doesn’t have to be absolute. If you want Bob to access your sensitive data, but discourage him from sharing it, you can enable watermarking:

      
         // Enable access watermark
   let client;
   
   // assumes Virtru auth widget
   function afterAuth(email) {
     client = new Virtru.Client({ email });
   }
   
   async function watermarkEnable(protectedFile) {
     // get policy
     const decryptParams = new Virtru.DecryptParamsBuilder()
       .withArrayBufferSource(protectedFile)
       .build();
     const policyId = await client.getPolicyId(decryptParams);
     const existingPolicy = await client.fetchPolicy(policyId);
   
     // watermark access
     const updatedPolicy = existingPolicy
       .builder()
       .enableWatermarking()
       .build();
     await client.updatePolicy(updatedPolicy);
     console.log(`Enabled watermark when accessing encrypted file`);
   }
 
 

This option only applies in Virtru’s Secure Reader, where Bob’s email address will always overlay the decrypted sensitive data.

To disable watermarking:

      
         // Disable access watermark
   let client;
   
   // assumes Virtru auth widget
   function afterAuth(email) {
     client = new Virtru.Client({ email });
   }
   
   async function watermarkDisable(protectedFile) {
     // get policy
     const decryptParams = new Virtru.DecryptParamsBuilder()
       .withArrayBufferSource(protectedFile)
       .build();
     const policyId = await client.getPolicyId(decryptParams);
     const existingPolicy = await client.fetchPolicy(policyId);
   
     // watermark access
     const updatedPolicy = existingPolicy
       .builder()
       .disableWatermarking()
       .build();
     await client.updatePolicy(updatedPolicy);
     console.log(`Disabled watermark when accessing encrypted file`);
   }
 
 

Virtru SDK for Node.js

JavaScript SDK Documentation

Quick Start: Node.js

You’re Alice and you have sensitive data to protect. (Don’t we all?)

Let’s see the fastest way to protect it server-side with the Virtru SDK.

Prerequisites
  1. Node.js 12 or higher
1. Install the SDK

We recommend installing our node package locally. That way, different projects can experiment with different versions of the Virtru SDK. After installing, you can verify the version you’re using:

Note: These steps assume a *nix style command line, as available in macOS and linux

npm install virtru-sdk@2.1.0 node -e "console.log('Using virtru-sdk: ' + require('virtru-sdk').Version)"
2. Get an identity

So Alice, who should own your sensitive data? You, obviously!

Authenticate to associate your email address (e.g. alice@example.com) with any data you protect. You cannot protect data without authenticating. If the Virtru Platform doesn’t know who’s protecting data, no one would be able to access it later (when they’re also asked to authenticate).

The fastest way to authenticate on the server side is with an appId token. You can generate one from the Virtru Dashboard. If you need help, see detailed steps.

For safekeeping, don’t hard code your appID anywhere. A more secure option is to store it in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
   export VIRTRU_SDK_APP_ID=[paste from Virtru Dashboard]

To protect your sensitive data, we’ll need a Virtru client. We’ll associate anything you encrypt with your email and appId. Let’s make sure your email and appId can create a valid Virtru client to make further SDK calls.

      
         // Quick Start - Step 2 - Get an identity
   const Virtru = require("virtru-sdk");
   
   // Set the environment variables:
   //   VIRTRU_SDK_APP_ID: AppId Token from https://secure.virtru.com/dashboard#/settings
   //   VIRTRU_SDK_EMAIL: Email address used for https://secure.virtru.com/dashboard#/profile
   // Please note, the identity used will be associated with any policies created.
   
   function loadVirtruClient() {
     try {
       const email = process.env.VIRTRU_SDK_EMAIL;
       const appId = process.env.VIRTRU_SDK_APP_ID;
       if (!email || !appId) {
         console.error(
           "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID"
         );
         return;
       }
       const client = new Virtru.Client({ email, appId });
       console.log("Ready to protect!");
       return client;
     } catch (error) {
       console.error(error);
       return;
     }
   }
   
   module.exports.client = loadVirtruClient();
    
  
node 02-identify.js
3. Ask for sensitive data

Now that we know who will own things, why don’t you enter your first piece of sensitive data? For simplicity’s sake, create a file named “sensitive.txt” with your sensitive data.

echo "sensitive data" > ./sensitive.txt
4. Protect the sensitive data

Next, decide your encryption options. For now, it’s the file containing your sensitive data. In the future, this could include who else should have access and under what conditions.

      
         // Quick Start - Step 4 - Protect the Sensitive Data
   const { Client, EncryptParamsBuilder } = require("virtru-sdk");
   
   async function protectToFile(unprotectedFile) {
     //auth
     const email = process.env.VIRTRU_SDK_EMAIL;
     const appId = process.env.VIRTRU_SDK_APP_ID;
     if (!email || !appId) {
       throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
     }
     const client = new Client({ email, appId });
   
     // prepare
     const protectedExt = ".tdf.html"; // HTML format
     const protectedFile = unprotectedFile + protectedExt;
     const encryptParams = new EncryptParamsBuilder()
       .withFileSource(unprotectedFile)
       .withDisplayFilename(unprotectedFile)
       .build();
   
     // protect & output
     const protectedStream = await client.encrypt(encryptParams);
     await protectedStream
       .toFile(protectedFile)
       .then(() => console.log(`Encrypted file ${protectedFile}`));
     return protectedStream;
   }
   
   if (require.main === module) {
     const unprotectedFile = "sensitive.txt";
     protectToFile(unprotectedFile)
       .catch(e => {
         console.error(e);
         process.exit(1);
       })
       .then(() => console.log(`Done`));
   }
   
   module.exports.protectToFile = protectToFile;
    
  

Then, invoke the code using:

node 04-protect.js
5. Access the sensitive data

Now, let’s say you need to see your sensitive data again. Authenticate as alice@example.com again and you can decrypt the protected file.

      
         // Quick Start - Step 5 - Access the Sensitive Data
   const { Client, DecryptParamsBuilder } = require("virtru-sdk");
   
   async function accessToFile(protectedFile, unprotectedFile) {
     //auth
     const email = process.env.VIRTRU_SDK_EMAIL;
     const appId = process.env.VIRTRU_SDK_APP_ID;
     if (!email || !appId) {
       throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
     }
     const client = new Client({ email, appId });
   
     // prepare
     const decryptParams = new DecryptParamsBuilder()
       .withFileSource(protectedFile)
       .build();
   
     // access & output
     const plaintextStream = await client.decrypt(decryptParams);
     await plaintextStream
       .toFile(unprotectedFile)
       .then(() => console.log(`Decrypted file ${unprotectedFile}`));
     return plaintextStream;
   }
   
   if (require.main === module) {
     const protectedFile = "sensitive.txt.tdf.html";
     const unprotectedFile = "sensitive_decrypted.txt";
   
     accessToFile(protectedFile, unprotectedFile)
       .catch(e => {
         console.error(e);
         process.exit(1);
       })
       .then(() => console.log(`Done`));
   }
   
   module.exports.accessToFile = accessToFile;
    
  

The decrypted file should match your original one with the sensitive data:

node 05-access.js
   diff sensitive.txt sensitive_decrypted.txt
6. Access the sensitive data anywhere

If you inspect the generated HTML file, you still won’t find your sensitive data. It stays protected. You can send that HTML file to another machine or anywhere you want. Only you will be able to access it. But how do you do that outside of this code?

We could build a whole set of functionality to authenticate, decrypt, and render files. Or we could use Virtru’s Secure Reader, which is built to do exactly that for thousands of security-conscious users every day. In fact, if you open that HTML file from the last step, it will redirect you to Secure Reader.

Secure Reader will ask you to authenticate. (You’re still Alice, aren’t you?)

Authenticating with Virtru Secure Reader

And if you authenticate with the same email address you used to create the HTML file, you should be able to view it in Secure Reader:

Decrypting with Virtru Secure Reader

Congrats Alice! Your sensitive data is safe wherever it goes.

Node.js Authentication

Security starts with identity. You claim you’re Alice, but the Virtru SDK doesn’t know that. We can’t protect or access data without an identity that’s responsible for protecting or accessing that data. Otherwise, no one (or anyone) would be able to do whatever they want with your data. But we all have sensitive data to protect.

So how do you prove your identity to the Virtru SDK? We’re glad you asked, “Alice…”

Here are your options on the server-side:

  • Use an appId Token from the Virtru Dashboard
  • Provision HMAC Token & Secret Pairs

appId Token

Generate an appId from the Virtru Dashboard. If you need help, see detailed steps.

Key points about appId authentication:

  • appIds expire in 120 days
  • appIds are tied to your email address (i.e. your login to Virtru Dashboard)
  • appIds cannot be used to encrypt or decrypt data on behalf of your app’s end users

For safekeeping, don’t hard code your appID anywhere. A more secure option is to store it in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
   export VIRTRU_SDK_APP_ID=[paste from Virtru Dashboard]

A combination of email & appId can be used to create a Virtru client and make all other SDK calls:

      
         // Authentication by AppId Token
   const Virtru = require("virtru-sdk");
   
   // Set the environment variables:
   //   VIRTRU_SDK_APP_ID: AppId Token from https://secure.virtru.com/dashboard#/settings
   //   VIRTRU_SDK_EMAIL: Email address used for https://secure.virtru.com/dashboard#/profile
   // Please note, the identity used will be associated with any policies created.
   
   try {
     const email = process.env.VIRTRU_SDK_EMAIL;
     const appId = process.env.VIRTRU_SDK_APP_ID;
     if (!email || !appId) {
       console.error(
         "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID"
       );
       return;
     }
     const client = new Virtru.Client({ email, appId });
     console.log("Ready to protect!");
   } catch (error) {
     console.error(error);
     process.exit(1);
   }
    
  

HMAC Token & Secret Pairs

HMAC authentication is a long-lived alternative to appIds.

Key points about HMAC authentication:

  • HMAC does not expire
  • HMAC is tied to your domain
  • HMAC can only be used to encrypt or decrypt data on behalf of your domain’s users

Thus, Virtru must provision an HMAC token & secret pair. Contact Virtru for HMAC provisioning.

If you provision an HMAC token & secret pair for example.com, bob@example.com can use your server-side app to encrypt his data and control who has access. A different domain, such as bob@elsewhere.com will not be able to encrypt or decrypt data with your server-side app. Emails in other domains would need to use a client-side app or Secure Reader to access the same data.

For safekeeping, don’t hard code your HMAC token & secret pair anywhere. A more secure option would be to store them in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
   export VIRTRU_SDK_HMAC_TOKEN=[paste from Virtru provisioning email]
   export VIRTRU_SDK_HMAC_APP_SECRET=[paste from Virtru provisioning email]

The HMAC token & secret pair can be used to create a Virtru client and make all other SDK calls:

      
         // Authentication by HMAC Token & Secret
   const Virtru = require("virtru-sdk");
   
   // Set the environment variables:
   //   VIRTRU_SDK_HMAC_TOKEN:
   //       A generated ID for your organization's applications and services
   //   VIRTRU_SDK_HMAC_APP_SECRET:
   //       The corresponding secret
   //   VIRTRU_SDK_EMAIL:
   //       Email address to be associated with any policies. User must be a
   //       member of the organization associated with the above token pair.
   
   const email = process.env.VIRTRU_SDK_EMAIL;
   const hmacToken = process.env.VIRTRU_SDK_HMAC_TOKEN;
   const hmacSecret = process.env.VIRTRU_SDK_HMAC_APP_SECRET;
   
   if (!email || !hmacToken || !hmacSecret) {
     console.error(
       "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_HMAC_TOKEN\n- VIRTRU_SDK_HMAC_APP_SECRET"
     );
     process.exit(1);
   }
   
   const client = new Virtru.Client({ email, hmacToken, hmacSecret });
   if (!client) {
     console.error("Virtru client failed to initialize");
     process.exit(1);
   }
   
   console.log("Ready to protect!");
    
  

Node.js Encryption

Now that the Virtru SDK knows you’re Alice, you can protect your first piece of data.

Encryption Basics

Before calling encrypt, you need to specify a few simple parameters.

You don’t need to include your email address when encrypting. You will already have access to anything you encrypt because you authenticated. But if you want anyone else to have access (like another one of your emails, alice@nowhere.com), you could include them here:

      
         // specify access controls
   const policy = new Virtru.PolicyBuilder()
     .addUsersWithAccess(["alice@nowhere.com"])
     .build();
   
   // protect & output
   const encryptParams = new Virtru.EncryptParamsBuilder()
     .withFileSource(unprotectedFile)
     .withDisplayFilename(unprotectedFile)
     .withPolicy(policy)
     .build();
    
  

Call encrypt and check out the resulting file:

      
         const protectedStream = await client.encrypt(encryptParams);
   let protectedExt = ".tdf.html"; // HTML format
   const protectedFile = unprotectedFile + protectedExt;
   await protectedStream
     .toFile(protectedFile)
     .then(() => console.log(`Encrypted file ${protectedFile}`));
    
  

Here's the complete source code:

      
         // Encryption example - HTML format
   const Virtru = require("virtru-sdk");
   
   function loadVirtruClient() {
     const email = process.env.VIRTRU_SDK_EMAIL;
     const appId = process.env.VIRTRU_SDK_APP_ID;
     if (!email || !appId) {
       throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
     }
     return new Virtru.Client({ email, appId });
   }
   
   async function protect(unprotectedFile) {
     const client = loadVirtruClient();
   
     // specify access controls
     const policy = new Virtru.PolicyBuilder()
       .addUsersWithAccess(["alice@nowhere.com"])
       .build();
   
     // protect & output
     const encryptParams = new Virtru.EncryptParamsBuilder()
       .withFileSource(unprotectedFile)
       .withDisplayFilename(unprotectedFile)
       .withPolicy(policy)
       .build();
     const protectedStream = await client.encrypt(encryptParams);
     let protectedExt = ".tdf.html"; // HTML format
     const protectedFile = unprotectedFile + protectedExt;
     await protectedStream
       .toFile(protectedFile)
       .then(() => console.log(`Encrypted file ${protectedFile}`));
   }
   
   // optionally execute from command line
   if (require.main === module) {
     const unprotectedFile = "sensitive.txt";
     protect(unprotectedFile);
   }
    
  
node protect-html.js

Now, your sensitive data is safe. Keep reading to see how or access your data by decrypting.


Encryption Lifecycle

That one little encrypt call did a lot of work behind the scenes to keep your sensitive data safe:

Protecting a file and sending the policy and key materials to Virtru

  • Step 1: Your app authenticates with Virtru's entity service.

    This was when you proved you were alice@example.com.

  • Step 2: Then, an encrypt call protects any given data as ciphertext. This ciphertext is local to where encrypt was called (a browser, end user device, or server). Although encrypt uses the open Trusted Data Format (TDF), you can save the ciphertext in a file format that you can open anywhere—HTML.

    This was when your sensitive data became protected.

  • Step 3: While an encrypt call keeps the protected data as local ciphertext, a secure decryption key travels back to Virtru’s key server for safe-keeping. But this key server doesn’t hand out keys to anyone…

    This is why you don’t have to manage keys yourself.

  • Step 4: While an encrypt call keeps the protected data as local ciphertext, the SDK saves the access controls for the protected data in Virtru’s access server. The access server determines if a particular authenticated user (Step 1) can access protected data (Step 2) using a decryption key (Step 3).

    This is the crucial backend you don’t have to build or host. It never has access to your local data.


Encrypted File Formats

We generated a .tdf.html file above. This is the SDK default, but not the only option.

HTML Format ZIP Format
File Extension .tdf.html .tdf
File Size File sizes less than 100 MB Any file size
Decryption Any Virtru SDK Any Virtru SDK
User Experience Open file anywhere to redirect to Virtru's Secure Reader Drag & drop in Virtru's Secure Reader

If you need a protected ZIP file, add it to the encrypt params and set the file extension:

      
         // Encryption example - ZIP format
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function protect(unprotectedFile) {
            const client = loadVirtruClient();
          
            // specify access controls
            const policy = new Virtru.PolicyBuilder()
              .addUsersWithAccess(["alice@nowhere.com"])
              .build();
          
            // protect & output
            const encryptParams = new Virtru.EncryptParamsBuilder()
              .withFileSource(unprotectedFile)
              .withZipFormat() // ZIP format
              .withDisplayFilename(unprotectedFile)
              .withPolicy(policy)
              .build();
            const protectedStream = await client.encrypt(encryptParams);
            let protectedExt = ".tdf"; // ZIP format
            const protectedFile = unprotectedFile + protectedExt;
            await protectedStream
              .toFile(protectedFile)
              .then(() => console.log(`Encrypted file ${protectedFile}`));
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const unprotectedFile = "sensitive.txt";
            protect(unprotectedFile);
          }
    
  
node protect-zip.js

And you’ll have a ZIP file with the same level of protection as HTML, but the caveats in the table above.

Node.js Decryption

Well Alice, the good news is, your first encrypted file is so safe, only you can decrypt it. Let’s confirm that with your protected file. Then, we’ll grant access to someone you trust.

Meet Secure Reader, the easiest way to decrypt

Opening a protected HTML file will take you to Virtru’s Secure Reader.

Authenticating with Virtru Secure Reader

Secure Reader will also ask you to authenticate. Again, no one trusts that you’re Alice. But trust us, it’s good for security. If Mallory tries to authenticate, he won’t see your sensitive data.

But if you authenticate, Secure Reader will render your file.

Decrypting with Virtru Secure Reader

If Secure Reader can’t render the file, you will still be able to download it.

Decrypting via SDK

Outside of Secure Reader, you can also decrypt a file via the SDK:

      
         // Decryption example
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function decrypt(protectedFile, unprotectedFile) {
            const client = loadVirtruClient();
          
            // prepare
            const decryptParams = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
          
            // access & output
            const plaintextStream = await client.decrypt(decryptParams);
            await plaintextStream
              .toFile(unprotectedFile)
              .then(() => console.log(`Decrypted file ${unprotectedFile}`));
            return plaintextStream;
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            const unprotectedFile = "sensitive_decrypted.txt";
            decrypt(protectedFile, unprotectedFile);
          }
    
  
node decrypt.js
Allowing others to decrypt

But let’s say you wanted to share your sensitive data with your trusted colleague Bob, whose email is bob@example.com.

For existing files, you would grant access to bob@example.com and save the changes to the Virtru Platform.

      
         const decryptParams = new Virtru.DecryptParamsBuilder()
            .withFileSource("sensitive.txt.tdf.html")
            .build();
          const policyId = await client.getPolicyId(decryptParams);
          const policy = await client.fetchPolicy(policyId);
          const newPolicy = policy
            .builder()
            .addUsersWithAccess(["bob@example.com"])
            .build();
          await client.updatePolicy(newPolicy);
    
  

Now, bob@example.com should be able to view your sensitive data in Secure Reader (anywhere) or via the SDK decrypt call (in your apps).

When protecting new files, you can grant access to Bob or any number of users as part of encryption params:

      
         const policy = new Virtru.PolicyBuilder()
          .addUsersWithAccess(["bob@example.com"])
          .build();
        
        const encryptParams = new Virtru.EncryptParamsBuilder()
          .withFileSource("sensitive.txt")
          .withDisplayFilename("sensitive.txt")
          .withPolicy(policy)
          .build();
        
        const protectedStream = await client.encrypt(encryptParams);
        await protectedStream.toFile("sensitive.txt.tdf.html");
    
  

Node.js Access Controls

No one can predict the future. Access controls let you change your mind about who has access and under what conditions.

Grant Access

Let’s say Bob enters your circle of trust. If you grant him access, he can decrypt your sensitive data.

      
         // Grant existing policy
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function grantAccess(protectedFile) {
            const client = loadVirtruClient();
          
            // get policy
            const params = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
            const policyId = await client.getPolicyId(params);
            const existingPolicy = await client.fetchPolicy(policyId);
          
            // update users
            const initialUsers = await existingPolicy.getUsersWithAccess();
            console.log("Initial users with access: " + initialUsers);
            const users = ["bob@example.com"];
            const updatedPolicy = existingPolicy
              .builder()
              .addUsersWithAccess(users)
              .build();
            await client.updatePolicy(updatedPolicy);
            console.log(
              `Granted access to users: ${users} on encrypted file ${protectedFile}`
            );
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            grantAccess(protectedFile);
          }
    
  

You can also grant access before you encrypt:

      
         // Grant new policy
        const Virtru = require("virtru-sdk");
        
        function loadVirtruClient() {
          const email = process.env.VIRTRU_SDK_EMAIL;
          const appId = process.env.VIRTRU_SDK_APP_ID;
          if (!email || !appId) {
            throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
          }
          return new Virtru.Client({ email, appId });
        }
        
        async function protectWithAccess(unprotectedFile) {
          const client = loadVirtruClient();
        
          // prepare policy
          const users = ["bob@example.com"];
          const policy = new Virtru.PolicyBuilder().addUsersWithAccess(users).build();
          const encryptParams = new Virtru.EncryptParamsBuilder()
            .withFileSource(unprotectedFile)
            .withDisplayFilename(unprotectedFile)
            .withPolicy(policy)
            .build();
        
          // encrypt
          const protectedStream = await client.encrypt(encryptParams);
          let protectedExt = ".tdf.html"; // HTML format
          const protectedFile = unprotectedFile + protectedExt;
          await protectedStream.toFile(protectedFile);
          console.log(
            `Encrypted file ${protectedFile} and granted access to users: ${users}`
          );
        }
        
        // optionally execute from command line
        if (require.main === module) {
          const unprotectedFile = "sensitive.txt";
          protectWithAccess(unprotectedFile);
        }
    
  
Revoke Access

Let’s say Bob leaves your circle of trust. It’d be great if he no longer had access to your sensitive data. Revoke will prevent Bob from decrypting your sensitive data:

      
         // Revoke access
        const Virtru = require("virtru-sdk");
        
        function loadVirtruClient() {
          const email = process.env.VIRTRU_SDK_EMAIL;
          const appId = process.env.VIRTRU_SDK_APP_ID;
          if (!email || !appId) {
            throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
          }
          return new Virtru.Client({ email, appId });
        }
        
        async function revokeAccess(protectedFile) {
          const client = loadVirtruClient();
        
          // get policy
          const params = new Virtru.DecryptParamsBuilder()
            .withFileSource(protectedFile)
            .build();
          const policyId = await client.getPolicyId(params);
          const existingPolicy = await client.fetchPolicy(policyId);
        
          // revoke access for user(s)
          const users = ["bob@example.com"];
          const updatedPolicy = existingPolicy
            .builder()
            .removeUsersWithAccess(users)
            .build();
          await client.updatePolicy(updatedPolicy);
          console.log(
            `Revoked access from users: ${users} on encrypted file ${protectedFile}`
          );
        }
        
        // optionally execute from command line
        if (require.main === module) {
          const protectedFile = "sensitive.txt.tdf.html";
          revokeAccess(protectedFile);
        }
    
  

You will still have access to your sensitive data.

Revoke All Access

Let’s say you landed a new job Alice. Well done! But your circle of trust becomes outdated. Rather than removing every Bob from accessing your sensitive data, you can remove everyone with revoke all:

      
         // Revoke all access
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function revokeAll(protectedFile) {
            const client = loadVirtruClient();
          
            // get policy
            const decryptParams = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
            const policyId = await client.getPolicyId(decryptParams);
          
            // revoke access for all users
            await client.revokePolicy(policyId);
            console.log(
              `Revoked access for all users on encrypted file ${protectedFile}`
            );
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            revokeAll(protectedFile);
          }
    
  

You will still have access to your sensitive data.

Expire Access

Some things aren’t meant to last. Your landlord, Trent, shouldn’t have access to the sensitive data in your lease forever. Let’s make sure your sensitive data expires in a year when your lease does:

      
         // Expire access with relative datetime
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function expireRelative(protectedFile) {
            const client = loadVirtruClient();
          
            // get policy
            const decryptParams = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
            const policyId = await client.getPolicyId(decryptParams);
            const existingPolicy = await client.fetchPolicy(policyId);
          
            // expire access
            let secondsInYear = 60 * 60 * 24 * 365; // min * hour * day * year;
            const updatedPolicy = existingPolicy
              .builder()
              .enableExpirationDeadlineFromNow(secondsInYear)
              .build();
            await client.updatePolicy(updatedPolicy);
            console.log(
              `Expire access to encrypted file ${protectedFile} in ${secondsInYear} seconds`
            );
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            expireRelative(protectedFile);
          }
    
  

You can also expire at a specific date and time:

      
         // Expire access with specific datetime
        const Virtru = require("virtru-sdk");
        
        function loadVirtruClient() {
          const email = process.env.VIRTRU_SDK_EMAIL;
          const appId = process.env.VIRTRU_SDK_APP_ID;
          if (!email || !appId) {
            throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
          }
          return new Virtru.Client({ email, appId });
        }
        
        async function expireSpecific(protectedFile) {
          const client = loadVirtruClient();
        
          // get policy
          const decryptParams = new Virtru.DecryptParamsBuilder()
            .withFileSource(protectedFile)
            .build();
          const policyId = await client.getPolicyId(decryptParams);
          const existingPolicy = await client.fetchPolicy(policyId);
        
          // expire access
          let expiresOn = "2022-08-12T14:37:26.101Z"; // ISO-8601 Format
          const updatedPolicy = existingPolicy
            .builder()
            .enableExpirationDeadline(expiresOn)
            .build();
          await client.updatePolicy(updatedPolicy);
          console.log(
            `Expire access to encrypted file ${protectedFile} on ${expiresOn}`
          );
        }
        
        // optionally execute from command line
        if (require.main === module) {
          const protectedFile = "sensitive.txt.tdf.html";
          expireSpecific(protectedFile);
        }
    
  

Expiration prevents everyone else on the policy from decrypting after that time. You will still have access.

Make the same expiration calls to update dates or times.

If you’re feeling permissive, you can always remove expiration too:

      
         // Remove access expiration
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function expireDisable(protectedFile) {
            const client = loadVirtruClient();
          
            // get policy
            const decryptParams = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
            const policyId = await client.getPolicyId(decryptParams);
            const existingPolicy = await client.fetchPolicy(policyId);
          
            // remove access expiration
            const updatedPolicy = existingPolicy
              .builder()
              .disableExpirationDeadline()
              .build();
            await client.updatePolicy(updatedPolicy);
            console.log(`Removed access expiration on encrypted file ${protectedFile}`);
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            expireDisable(protectedFile);
          }
    
  
Watermark Access

Trust doesn’t have to be absolute. If you want Bob to access your sensitive data, but discourage him from sharing it, you can enable watermarking:

      
         // Enable access watermark
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function watermarkEnable(protectedFile) {
            const client = loadVirtruClient();
          
            // get policy
            const decryptParams = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
            const policyId = await client.getPolicyId(decryptParams);
            const existingPolicy = await client.fetchPolicy(policyId);
          
            // watermark access
            const updatedPolicy = existingPolicy
              .builder()
              .enableWatermarking()
              .build();
            await client.updatePolicy(updatedPolicy);
            console.log(
              `Enabled watermark when accessing encrypted file ${protectedFile}`
            );
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            watermarkEnable(protectedFile);
          }
    
  

This option only applies in Virtru’s Secure Reader, where Bob’s email address will always overlay the decrypted sensitive data.

To disable watermarking:

      
         // Disable access watermark
          const Virtru = require("virtru-sdk");
          
          function loadVirtruClient() {
            const email = process.env.VIRTRU_SDK_EMAIL;
            const appId = process.env.VIRTRU_SDK_APP_ID;
            if (!email || !appId) {
              throw "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID";
            }
            return new Virtru.Client({ email, appId });
          }
          
          async function watermarkDisable(protectedFile) {
            const client = loadVirtruClient();
          
            // get policy
            const decryptParams = new Virtru.DecryptParamsBuilder()
              .withFileSource(protectedFile)
              .build();
            const policyId = await client.getPolicyId(decryptParams);
            const existingPolicy = await client.fetchPolicy(policyId);
          
            // watermark access
            const updatedPolicy = existingPolicy
              .builder()
              .disableWatermarking()
              .build();
            await client.updatePolicy(updatedPolicy);
            console.log(
              `Disabled watermark when accessing encrypted file ${protectedFile}`
            );
          }
          
          // optionally execute from command line
          if (require.main === module) {
            const protectedFile = "sensitive.txt.tdf.html";
            watermarkDisable(protectedFile);
          }
    
  

Virtru SDK for Python

Python SDK Documentation

Minimum Requirements
Virtru Python SDK requires Python 3.6 or higher.

Quick Start: Python

You’re Alice and you have sensitive data to protect. (Don’t we all?)

Let’s see the fastest way to protect it server-side with the Virtru SDK.

Prerequisites
  1. Linux - Python 3.6, 3.7, 3.8
  2. macOS - Python 3.7, 3.8
  3. Windows - Python 3.7, 3.8
1. Install the SDK

The Virtru Python SDK is available on PyPI.

pip3 install virtru-sdk
2. Get an identity

So Alice, who should own your sensitive data? You, obviously!

Authenticate to associate your email address (e.g. alice@example.com) with any data you protect. You cannot protect data without authenticating. If the Virtru Platform doesn’t know who’s protecting data, no one would be able to access it later (when they’re also asked to authenticate).

The fastest way to authenticate on the server side is with an appId token. You can generate one from the Virtru Dashboard. If you need help, see detailed steps.

For safekeeping, don’t hard code your appID anywhere. A more secure option is to store it in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
 export VIRTRU_SDK_APP_ID=[paste from Virtru Dashboard]

To protect your sensitive data, we’ll need a Virtru client. We’ll associate anything you encrypt with your email and appId. Let’s make sure your email and appId can create a valid Virtru client to make further SDK calls:

      
        import os
        from virtru_sdk import Client, EncryptFileParams
        
        #### Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        #### Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        print("Ready to protect!")
      
 
3. Ask for sensitive data

Now that we know who will own things, why don’t you enter your first piece of sensitive data? For simplicity’s sake, create a file named “sensitive.txt” with your sensitive data.

touch ./sensitive.txt
 echo "sensitive data" >> ./sensitive.txt
4. Protect the sensitive data

Next, decide your encryption options. For now, it’s the file containing your sensitive data. In the future, this could include who else should have access and under what conditions.

       
        unprotected_file = "sensitive.txt"
        protected_file = unprotected_file + ".tdf.html"
        param = EncryptFileParams(in_file_path=unprotected_file,
                                  out_file_path=protected_file)
      
    

Finally, encrypt the data:

       
        client.encrypt_file(encrypt_file_params=param)
        
        print(f"Encrypted file {protected_file}")
      
 

Here is the complete source code:

       
        import os
        from virtru_sdk import Client, EncryptFileParams
        
        #### Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        #### Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        #### Specify a file to encrypt and the file name to use for the encrypted output
        unprotected_file = "sensitive.txt"
        protected_file = unprotected_file + ".tdf.html"
        param = EncryptFileParams(in_file_path=unprotected_file,
                                  out_file_path=protected_file)
        
        client.encrypt_file(encrypt_file_params=param)
        
        print(f"Encrypted file {protected_file}")
 
 
5. Access the sensitive data

Now, let’s say you need to see your sensitive data again. Authenticate as alice@example.com again and you can decrypt the protected file:

       
        import os
          from virtru_sdk import Client
          
          #### Load email and appId from environment variables
          VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
          VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
          if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
              raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
          
          #### Authenticate
          client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
          
          protected_file = "sensitive.txt.tdf.html"
          unprotected_file = "sensitive_decrypted.txt"
          client.decrypt_file(in_file_path=protected_file,
                              out_file_path=unprotected_file)
          
          print(f"Decrypted file {unprotected_file}")
 
 

The decrypted file should match your original one with the sensitive data:

diff sensitive.txt sensitive_decrypted.txt
6. Access the sensitive data anywhere

If you inspect the generated HTML file, you still won’t find your sensitive data. It stays protected. You can send that HTML file to another machine or anywhere you want. Only you will be able to access it. But how do you do that outside of this code?

We could build a whole set of functionality to authenticate, decrypt, and render files. Or we could use Virtru’s Secure Reader, which is built to do exactly that for thousands of security-conscious users every day. In fact, if you open that HTML file from the last step, it will redirect you to Secure Reader.

Secure Reader will ask you to authenticate. (You’re still Alice, aren’t you?)

Authenticating with Virtru Secure Reader

And if you authenticate with the same email address you used to create the HTML file, you should be able to view it in Secure Reader:

Decrypting with Virtru Secure Reader

Congrats Alice! Your sensitive data is safe wherever it goes.

Python Authentication

Security starts with identity. You claim you’re Alice, but the Virtru SDK doesn’t know that. We can’t protect or access data without an identity that’s responsible for protecting or accessing that data. Otherwise, no one (or anyone) would be able to do whatever they want with your data. But we all have sensitive data to protect.

So how do you prove your identity to the Virtru SDK? We’re glad you asked, “Alice…”

Here are your options on the server-side:

  • Use an appId Token from the Virtru Dashboard
  • Provision HMAC Token & Secret Pairs

appId Token

Generate an appId from the Virtru Dashboard. If you need help, see detailed steps.

Key points about appId authentication:

  • appIds expire in 120 days
  • appIds are tied to your email address (i.e. your login to Virtru Dashboard)
  • appIds cannot be used to encrypt or decrypt data on behalf of your app’s end users

For safekeeping, don’t hard code your appID anywhere. A more secure option is to store it in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
 export VIRTRU_SDK_APP_ID=[paste from Virtru Dashboard]

A combination of email & appId can be used to create a Virtru client and make all other SDK calls:

       
         #### Authentication by AppId Token
          import os
          from virtru_sdk import Client
          
          #### You don't want your credentials exposed in code.
          #### In this example, we load credentials from environment variables
          VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
          VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
          if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
              raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
          
          #### Authenticate
          client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
          
          #### the `client` can now be used to encrypt/decrypt data.
          print("Ready to protect!")
 
 

HMAC Token & Secret Pairs

HMAC authentication is a long-lived alternative to appIds.

Key points about HMAC authentication:

  • HMAC does not expire
  • HMAC is tied to your domain
  • HMAC can only be used to encrypt or decrypt data on behalf of your domain’s users

Thus, Virtru must provision an HMAC token & secret pair. Contact Virtru for HMAC provisioning.

If you provision an HMAC token & secret pair for example.com, bob@example.com can use your server-side app to encrypt his data and control who has access. A different domain, such as bob@elsewhere.com will not be able to encrypt or decrypt data with your server-side app. Emails in other domains would need to use a client-side app or Secure Reader to access the same data.

For safekeeping, don’t hard code your HMAC token & secret pair anywhere. A more secure option would be to store them in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
 export VIRTRU_SDK_HMAC_TOKEN=[paste from Virtru provisioning email]
 export VIRTRU_SDK_HMAC_APP_SECRET=[paste from Virtru provisioning email]

The HMAC token & secret pair can be used to create a Virtru client and make all other SDK calls:

       
         #### Authentication by HMAC Token & Secret
          import os
          from virtru_sdk import Client
          
          #### You don't want your credentials exposed in code.
          #### In this example, we load credentials from environment variables
          VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
          VIRTRU_SDK_HMAC_TOKEN = os.getenv("VIRTRU_SDK_HMAC_TOKEN")
          VIRTRU_SDK_HMAC_APP_SECRET = os.getenv("VIRTRU_SDK_HMAC_APP_SECRET")
          if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_HMAC_TOKEN and VIRTRU_SDK_HMAC_APP_SECRET):
              raise EnvironmentError('''An environment variable is not set:
          - VIRTRU_SDK_EMAIL
          - VIRTRU_SDK_HMAC_TOKEN
          - VIRTRU_SDK_HMAC_APP_SECRET''')
          
          #### Authenticate
          client = Client(owner=VIRTRU_SDK_EMAIL,
                          api_key=VIRTRU_SDK_HMAC_TOKEN,
                          secret=VIRTRU_SDK_HMAC_APP_SECRET)
          
          #### the `client` can now be used to encrypt/decrypt data.
          print("Ready to protect!")
 
 

Python Encryption

Now that the Virtru SDK knows you’re Alice, you can protect your first piece of data.

Encryption Basics

Before calling encrypt, you need to specify a few simple parameters.

You don’t need to include your email address when encrypting. You will already have access to anything you encrypt because you authenticated. But if you want anyone else to have access (like another one of your emails, alice@nowhere.com), you could include them here:

       
         policy = Policy()
          policy.share_with_users(["alice@nowhere.com"])
          unprotected_file = "sensitive.txt"
          protected_file = unprotected_file + ".tdf.html"
          param = EncryptFileParams(in_file_path=unprotected_file,
                                    out_file_path=protected_file)
          param.set_policy(policy)
      
 

Call encrypt and check out the resulting file:

       
        client.encrypt_file(encrypt_file_params=param)
        print(f"Encrypted file {protected_file}")
      
    

Here's the complete source code:

       
         #### Encryption example - HTML format
          import os
          from virtru_sdk import Client, Policy, EncryptFileParams
          
          #### Load email and appId from environment variables
          VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
          VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
          if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
              raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
          
          #### Authenticate
          client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
          
          #### Create a default policy and share
          policy = Policy()
          policy.share_with_users(["alice@nowhere.com"])
          unprotected_file = "sensitive.txt"
          protected_file = unprotected_file + ".tdf.html"
          param = EncryptFileParams(in_file_path=unprotected_file,
                                    out_file_path=protected_file)
          param.set_policy(policy)
          
          #### Encrypt
          client.encrypt_file(encrypt_file_params=param)
          print(f"Encrypted file {protected_file}")
      
    

Now, your sensitive data is safe. Keep reading to see how or access your data by decrypting.


Encryption Lifecycle

That one little encrypt call did a lot of work behind the scenes to keep your sensitive data safe:

Protecting a file and sending the policy and key materials to Virtru

  • Step 1: Your app authenticates with Virtru's entity service.

    This was when you proved you were alice@example.com.

  • Step 2: Then, an encrypt call protects any given data as ciphertext. This ciphertext is local to where encrypt was called (a browser, end user device, or server). Although encrypt uses the open Trusted Data Format (TDF), you can save the ciphertext in a file format that you can open anywhere—HTML.

    This was when your sensitive data became protected.

  • Step 3: While an encrypt call keeps the protected data as local ciphertext, a secure decryption key travels back to Virtru’s key server for safe-keeping. But this key server doesn’t hand out keys to anyone…

    This is why you don’t have to manage keys yourself.

  • Step 4: While an encrypt call keeps the protected data as local ciphertext, the SDK saves the access controls for the protected data in Virtru’s access server. The access server determines if a particular authenticated user (Step 1) can access protected data (Step 2) using a decryption key (Step 3).

    This is the crucial backend you don’t have to build or host. It never has access to your local data.


Encrypted File Formats

We generated a .tdf.html file above. This is the SDK default, but not the only option.

HTML Format ZIP Format
File Extension .tdf.html .tdf
File Size File sizes less than 100 MB Any file size
Decryption Any Virtru SDK Any Virtru SDK
User Experience Open file anywhere to redirect to Virtru's Secure Reader Drag & drop in Virtru's Secure Reader

If you need a protected ZIP file, add it to the encrypt params:

       
         from virtru_sdk import Protocol
          
          #### …
          
          client.set_protocol(Protocol.Zip)  # generates ZIP instead of HTML
      
   

Here's the complete source code:

       
        #### Encryption example - ZIP format
        import os
        from virtru_sdk import Client, Policy, EncryptFileParams, Protocol
        
        #### Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        #### Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        #### Create a default policy and share
        policy = Policy()
        policy.share_with_users(["alice@nowhere.com"])
        unprotected_file = "sensitive.txt"
        protected_file = unprotected_file + ".tdf"
        param = EncryptFileParams(in_file_path=unprotected_file,
                                  out_file_path=protected_file)
        param.set_policy(policy)
        
        #### Encrypt
        client.set_protocol(Protocol.Zip)  # generates ZIP instead of HTML
        client.encrypt_file(encrypt_file_params=param)
        print(f"Encrypted file {protected_file}")
      
  

And you’ll have a ZIP file with the same level of protection as HTML, but the caveats in the table above.

Python Decryption

Well Alice, the good news is, your first encrypted file is so safe, only you can decrypt it. Let’s confirm that with your protected file. Then, we’ll grant access to someone you trust.

Meet Secure Reader, the easiest way to decrypt

Opening a protected HTML file will take you to Virtru’s Secure Reader.

Authenticating with Virtru Secure Reader

Secure Reader will also ask you to authenticate. Again, no one trusts that you’re Alice. But trust us, it’s good for security. If Mallory tries to authenticate, he won’t see your sensitive data.

But if you authenticate, Secure Reader will render your file.

Decrypting with Virtru Secure Reader

If Secure Reader can’t render the file, you will still be able to download it.

Decrypting via SDK

Outside of Secure Reader, you can also decrypt a file via the SDK:

       
        #### Decryption example
        import os
        from virtru_sdk import Client
        
        #### Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        #### Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        #### Decrypt
        protected_file = "sensitive.txt.tdf.html"
        unprotected_file = "sensitive_decrypted.txt"
        client.decrypt_file(in_file_path=protected_file,
                            out_file_path=unprotected_file)
        
        print(f"Decrypted file {unprotected_file}")
      
    
Allowing others to decrypt

But let’s say you wanted to share your sensitive data with your trusted colleague Bob, whose email is bob@example.com.

For existing files, you would grant access to bob@example.com and save the changes to the Virtru Platform.

       
        policy = Policy()
        policy.share_with_users(["bob@example.com"])
        
        client.update_policy_for_file(policy, "sensitive.txt.tdf.html")
      
  

Now, bob@example.com should be able to view your sensitive data in Secure Reader (anywhere) or via the SDK decrypt call (in your apps).

When protecting new files, you can grant access to Bob or any number of users as part of encryption params:

       
        policy = Policy()
        policy.share_with_users(["bob@example.com"])
        
        #### encrypt the file with the new policy
        param = EncryptFileParams(in_file_path="sensitive.txt",
                                 out_file_path="sensitive.txt.tdf.html")
        param.set_policy(policy)
        client.encrypt_file(encrypt_file_params=param)
      
    

Python Access Controls

No one can predict the future. Access controls let you change your mind about who has access and under what conditions.

Grant Access

Let’s say Bob enters your circle of trust. If you grant him access, he can decrypt your sensitive data.

       
        # Python Access Controls - Grant for existing policy
        import os
        from virtru_sdk import Client, Policy
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Update policy to grant access to a user
        policy = Policy()
        policy.share_with_users(["bob@example.com"])  # can also decrypt
        client.update_policy_for_file(policy, "sensitive.txt.tdf.html")
      
    

You can also grant access before you encrypt:

       
        # Python Access Controls - Grant with new policy
        import os
        from virtru_sdk import Client, Policy, EncryptFileParams
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Create a policy to grant access to a user
        policy = Policy()
        policy.share_with_users(["bob@example.com"])
        unprotected_file = "sensitive.txt"
        protected_file = unprotected_file + ".tdf.html"
        param = EncryptFileParams(in_file_path=unprotected_file,
                                  out_file_path=protected_file)
        param.set_policy(policy)
        
        # Encrypt
        client.encrypt_file(encrypt_file_params=param)
        print(f"Encrypted file {protected_file}")
      
    
Revoke Access

Let’s say Bob leaves your circle of trust. It’d be great if he no longer had access to your sensitive data. Revoke will prevent Bob from decrypting your sensitive data:

       
        # Python Access Controls - Revoke
        import os
        from virtru_sdk import Client, Policy
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Update policy to revoke access
        policy = Policy()
        policy.remove_users(['bob@example.com'])  # can no longer decrypt, but you still can
        client.update_policy_for_file(policy, "sensitive.txt.tdf.html")
      
    

You will still have access to your sensitive data.

Revoke All Access

Let’s say you landed a new job Alice. Well done! But your circle of trust becomes outdated. Rather than removing every Bob from accessing your sensitive data, you can remove everyone with revoke all:

       
        # Python Access Controls - Revoke all
        import os
        from virtru_sdk import Client
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Revoke access for everyone else, only you can decrypt
        client.revoke_file("sensitive.txt.tdf.html")
      
    

You will still have access to your sensitive data.

Expire Access

Some things aren’t meant to last. Your landlord, Trent, shouldn’t have access to the sensitive data in your lease forever. Let’s make sure your sensitive data expires in a year when your lease does:

       
        # Python Access Controls - Expire relative to now
        import os
        from virtru_sdk import Client, Policy, EncryptFileParams
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Create policy with expiration
        policy = Policy()
        policy.expire_in_days(days=365)
        
        # Encrypt with policy
        unprotected_file = "lease.docx"
        protected_file = unprotected_file + ".tdf.html"
        param = EncryptFileParams(in_file_path=unprotected_file,
                                  out_file_path=protected_file)
        param.set_policy(policy)
        client.encrypt_file(encrypt_file_params=param)
        print(f"Encrypted file {protected_file}")
      
    

You can also expire at a specific date and time:

       
         # Python Access Controls - Expire at specific time
          import os
          from virtru_sdk import Client, Policy, EncryptFileParams 
          
          # Load email and appId from environment variables
          VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
          VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
          if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
              raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
          
          # Authenticate
          client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
          
          # Create policy with expiration
          policy = Policy()
          policy.add_expiration("2022-08-12T14:37:26.101Z")  # ISO-8601 Format
          
          # Encrypt with policy
          unprotected_file = "lease.docx"
          protected_file = unprotected_file + ".tdf.html"
          param = EncryptFileParams(in_file_path=unprotected_file,
                                    out_file_path=protected_file)
          param.set_policy(policy)
          client.encrypt_file(encrypt_file_params=param)
          print(f"Encrypted file {protected_file}")
        
    

Expiration prevents everyone else on the policy from decrypting after that time. You will still have access.

Make the same expiration calls to update dates or times.

If you’re feeling permissive, you can always remove expiration too:

       
        # Python Access Controls - Remove expiration
        import os
        from virtru_sdk import Client, Policy
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Update policy expiration
        policy = Policy()
        policy.remove_expiration()
        client.update_policy_for_file(policy, "lease.docx.tdf.html")
      
    
Watermark Access

Trust doesn’t have to be absolute. If you want Bob to access your sensitive data, but discourage him from sharing it, you can enable watermarking:

       
        # Python Access Controls - Watermark
        import os
        from virtru_sdk import Client, Policy
        
        # Load email and appId from environment variables
        VIRTRU_SDK_EMAIL = os.getenv("VIRTRU_SDK_EMAIL")
        VIRTRU_SDK_APP_ID = os.getenv("VIRTRU_SDK_APP_ID")
        if not (VIRTRU_SDK_EMAIL and VIRTRU_SDK_APP_ID):
            raise EnvironmentError("An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID")
        
        # Authenticate
        client = Client(owner=VIRTRU_SDK_EMAIL, app_id=VIRTRU_SDK_APP_ID)
        
        # Update policy watermark
        policy = Policy()
        policy.enable_watermarking()  # or policy.disable_watermarking()
        client.update_policy_for_file(policy, "sensitive.txt.tdf.html")
      
    

This option only applies in Virtru’s Secure Reader, where Bob’s email address will always overlay the decrypted sensitive data.

To disable watermarking:

       
        policy = Policy()
 policy.disable_watermarking()
 client.update_policy_for_file(policy, "sensitive.txt.tdf.html")
 
 

Virtru SDK for C++

C++ SDK Documentation

Quick Start: C++

You’re Alice and you have sensitive data to protect. (Don’t we all?)

Let’s see the fastest way to protect it server-side with the Virtru SDK.

Prerequisites
  • Compiler compatible with C++17 or newer:
    • Linux: gcc 7.40
    • macOS: XCode 11.3
    • Windows: Microsoft Visual Studio 2017
  • CMake (Linux, macOS, Windows)
1. Install the SDK
Linux
  1. Download the C++ archive for Linux.
  2. Unpack the archive.
  3. Move the unpacked folder into your project.
  4. Generate project files:
cd ./sample # from downloaded archive
 cmake -G "Eclipse CDT4 - Unix Makefiles"
 make # compile, link, and create an executable
macOS
  1. Download the C++ archive for macOS.
  2. Unpack the archive.
  3. Move the unpacked folder into your project.
  4. Generate project files:
cd ./sample # from downloaded archive
 cmake .
 make # compile, link, and create an executable
Windows
  1. Download the C++ archive for Windows.
  2. Unpack the archive.
  3. Move the unpacked folder into your project.
  4. Install Visual Studio 2017 or newer.
  5. Generate Visual Studio project files using CMake. Run this in the Developer PowerShell for Visual Studio:
Set-Location .\sample\
 cmake -G "Visual Studio 15 2017 Win64"
 
 
  1. Open the virtru_tdf3_sensitive.sln file with Visual Studio.
  2. Select Release in configuration.
  3. Select Build > Build solution to compile, link and create an executable.
2. Get an identity

So Alice, who should own your sensitive data? You, obviously!

Authenticate to associate your email address (e.g. alice@example.com) with any data you protect. You cannot protect data without authenticating. If the Virtru Platform doesn’t know who’s protecting data, no one would be able to access it later (when they’re also asked to authenticate).

The fastest way to authenticate on the server side is with an appId token. You can generate one from the Virtru Dashboard. If you need help, see detailed steps.

For safekeeping, don’t hard code your appID anywhere. A more secure option is to store it in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
 export VIRTRU_SDK_APP_ID=[paste from Virtru Dashboard]

To protect your sensitive data, we’ll need a Virtru client. We’ll associate anything you encrypt with your email and appId. Let’s make sure your email and appId can create a valid Virtru client to make further SDK calls:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     std::cout << "Ready to protect!" << std::endl;
     return EXIT_SUCCESS;
 }
3. Ask for sensitive data

Now that we know who will own things, why don’t you enter your first piece of sensitive data? For simplicity’s sake, create a file named “sensitive.txt” with your sensitive data.

touch ./sensitive.txt
 echo "sensitive data" >> ./sensitive.txt
4. Protect the sensitive data

Next, decide your encryption options. For now, it’s the file containing your sensitive data. In the future, this could include who else should have access and under what conditions.

std::string unprotectedFile = "sensitive.txt";
 std::string protectedFile = unprotectedFile + ".tdf.html";
 EncryptFileParams params {unprotectedFile, protectedFile};

Finally, encrypt the data:

client.encryptFile(params);

Here is the complete source code:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     std::string unprotectedFile = "sensitive.txt";
     std::string protectedFile = unprotectedFile + ".tdf.html";
     EncryptFileParams params {unprotectedFile, protectedFile};
 
     client.encryptFile(params);
     std::cout << "Encrypted file " << protectedFile << std::endl;
     return EXIT_SUCCESS;
 }
5. Access the sensitive data

Now, let’s say you need to see your sensitive data again. Authenticate as alice@example.com again and you can decrypt the protected file:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     std::string protectedFile = "sensitive.txt.tdf.html";
     std::string unprotectedFile = "sensitive_decrypted.txt";
     client.decryptFile(protectedFile, unprotectedFile);
 
     std::cout << "Decrypted file " << unprotectedFile << std::endl;
     return EXIT_SUCCESS;
 }

The decrypted file should match your original one with the sensitive data:

diff sensitive.txt sensitive_decrypted.txt
6. Access the sensitive data anywhere

If you inspect the generated HTML file, you still won’t find your sensitive data. It stays protected. You can send that HTML file to another machine or anywhere you want. Only you will be able to access it. But how do you do that outside of this code?

We could build a whole set of functionality to authenticate, decrypt, and render files. Or we could use Virtru’s Secure Reader, which is built to do exactly that for thousands of security-conscious users every day. In fact, if you open that HTML file from the last step, it will redirect you to Secure Reader.

Secure Reader will ask you to authenticate. (You’re still Alice, aren’t you?)

Authenticating with Virtru Secure Reader

And if you authenticate with the same email address you used to create the HTML file, you should be able to view it in Secure Reader:

Decrypting with Virtru Secure Reader

Congrats Alice! Your sensitive data is safe wherever it goes.

C++ Authentication

Security starts with identity. You claim you’re Alice, but the Virtru SDK doesn’t know that. We can’t protect or access data without an identity that’s responsible for protecting or accessing that data. Otherwise, no one (or anyone) would be able to do whatever they want with your data. But we all have sensitive data to protect.

So how do you prove your identity to the Virtru SDK? We’re glad you asked, “Alice…”

Here are your options on the server-side:

  • Use an appId Token from the Virtru Dashboard
  • Provision HMAC Token & Secret Pairs

appId Token

Generate an appId from the Virtru Dashboard. If you need help, see detailed steps.

Key points about appId authentication:

  • appIds expire in 120 days
  • appIds are tied to your email address (i.e. your login to Virtru Dashboard)
  • appIds cannot be used to encrypt or decrypt data on behalf of your app’s end users

For safekeeping, don’t hard code your appID anywhere. A more secure option is to store it in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
 export VIRTRU_SDK_APP_ID=[paste from Virtru Dashboard]

A combination of email & appId can be used to create a Virtru client and make all other SDK calls:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     std::cout << "Ready to protect!" << std::endl;
     return EXIT_SUCCESS;
 }

HMAC Token & Secret Pairs

HMAC authentication is a long-lived alternative to appIds.

Key points about HMAC authentication:

  • HMAC does not expire
  • HMAC is tied to your domain
  • HMAC can only be used to encrypt or decrypt data on behalf of your domain’s users

Thus, Virtru must provision an HMAC token & secret pair. Contact Virtru for HMAC provisioning.

If you provision an HMAC token & secret pair for example.com, bob@example.com can use your server-side app to encrypt his data and control who has access. A different domain, such as bob@elsewhere.com will not be able to encrypt or decrypt data with your server-side app. Emails in other domains would need to use a client-side app or Secure Reader to access the same data.

For safekeeping, don’t hard code your HMAC token & secret pair anywhere. A more secure option would be to store them in your local environment:

export VIRTRU_SDK_EMAIL=[paste from Virtru Dashboard]
 export VIRTRU_SDK_HMAC_TOKEN=[paste from Virtru provisioning email]
 export VIRTRU_SDK_HMAC_APP_SECRET=[paste from Virtru provisioning email]

The HMAC token & secret pair can be used to create a Virtru client and make all other SDK calls:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto hmacToken = std::getenv("VIRTRU_SDK_HMAC_TOKEN");
     auto hmacSecret = std::getenv("VIRTRU_SDK_HMAC_APP_SECRET");
     if (email == nullptr || hmacToken == nullptr || hmacSecret == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_HMAC_TOKEN\n- VIRTRU_SDK_HMAC_APP_SECRET" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, hmacToken, hmacSecret};
 
     std::cout << "Ready to protect!" << std::endl;
     return EXIT_SUCCESS;
 }

C++ Encryption

Now that the Virtru SDK knows you’re Alice, you can protect your first piece of data.

Encryption Basics

Before calling encrypt, you need to specify a few simple parameters.

You don’t need to include your email address when encrypting. You will already have access to anything you encrypt because you authenticated. But if you want anyone else to have access (like another one of your emails, alice@nowhere.com), you could include them here:

Policy policy;
 policy.shareWithUsers({"alice@nowhere.com"});
 std::string unprotectedFile = "sensitive.docx";
 std::string protectedFile = unprotectedFile + ".tdf.html";
 EncryptFileParams params {unprotectedFile, protectedFile};
 params.setPolicy(policy);

Call encrypt and check out the resulting file:

client.encryptFile(params);
 std::cout << "Encrypted file " << protectedFile << std::endl;

Here's the complete source code:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.shareWithUsers({"alice@nowhere.com"});
     std::string unprotectedFile = "sensitive.docx";
     std::string protectedFile = unprotectedFile + ".tdf.html";
     EncryptFileParams params {unprotectedFile, protectedFile};
     params.setPolicy(policy);
 
     client.encryptFile(params);
     std::cout << "Encrypted file " << protectedFile << std::endl;
     return EXIT_SUCCESS;
 }

Now, your sensitive data is safe. Keep reading to see how to access your data by decrypting.


Encryption Lifecycle

That one little encrypt call did a lot of work behind the scenes to keep your sensitive data safe:

Protecting a file and sending the policy and key materials to Virtru

  • Step 1: Your app authenticates with Virtru's entity service.

    This was when you proved you were alice@example.com.

  • Step 2: Then, an encrypt call protects any given data as ciphertext. This ciphertext is local to where encrypt was called (a browser, end user device, or server). Although encrypt uses the open Trusted Data Format (TDF), you can save the ciphertext in a file format that you can open anywhere—HTML.

    This was when your sensitive data became protected.

  • Step 3: While an encrypt call keeps the protected data as local ciphertext, a secure decryption key travels back to Virtru’s key server for safe-keeping. But this key server doesn’t hand out keys to anyone…

    This is why you don’t have to manage keys yourself.

  • Step 4: While an encrypt call keeps the protected data as local ciphertext, the SDK saves the access controls for the protected data in Virtru’s access server. The access server determines if a particular authenticated user (Step 1) can access protected data (Step 2) using a decryption key (Step 3).

    This is the crucial backend you don’t have to build or host. It never has access to your local data.


Encrypted File Formats

We generated a .tdf.html file above. This is the SDK default, but not the only option.

HTML Format ZIP Format
File Extension .tdf.html .tdf
File Size File sizes less than 100 MB Any file size
Decryption Any Virtru SDK Any Virtru SDK
User Experience Open file anywhere to redirect to Virtru's Secure Reader Drag & drop in Virtru's Secure Reader

If you need a protected ZIP file, add it to the encrypt params:

client.setProtocol(Protocol::Zip); // generates ZIP instead of HTML

Here's the complete source code:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.shareWithUsers({"alice@nowhere.com"});
     std::string unprotectedFile = "sensitive.docx";
     std::string protectedFile = unprotectedFile + ".tdf";
     EncryptFileParams params {unprotectedFile, protectedFile};
     params.setPolicy(policy);
 
     client.setProtocol(Protocol::Zip); // generates ZIP instead of HTML
     client.encryptFile(params);
     std::cout << "Encrypted file " << protectedFile << std::endl;
     return EXIT_SUCCESS;
 }

And you’ll have a ZIP file with the same level of protection as HTML, but the caveats in the table above.

C++ Decryption

Well Alice, the good news is, your first encrypted file is so safe, only you can decrypt it. Let’s confirm that with your protected file. Then, we’ll grant access to someone you trust.

Meet Secure Reader, the easiest way to decrypt

Opening a protected HTML file will take you to Virtru’s Secure Reader.

Authenticating with Virtru Secure Reader

Secure Reader will also ask you to authenticate. Again, no one trusts that you’re Alice. But trust us, it’s good for security. If Mallory tries to authenticate, he won’t see your sensitive data.

But if you authenticate, Secure Reader will render your file.

Decrypting with Virtru Secure Reader

If Secure Reader can’t render the file, you will still be able to download it.

Decrypting via SDK

Outside of Secure Reader, you can also decrypt a file via the SDK:

#include <virtru_client.h>
 #include <cstdlib>
 #include <iostream>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     std::string protectedFile = "sensitive.docx.tdf.html";
     std::string unprotectedFile = "sensitive_decrypted.docx";
     client.decryptFile(protectedFile, unprotectedFile);
 
     std::cout << "Decrypted file " << unprotectedFile << std::endl;
     return EXIT_SUCCESS;
 }
Allowing others to decrypt

But let’s say you wanted to share your sensitive data with your trusted colleague Bob, whose email is bob@example.com.

For existing files, you would grant access to bob@example.com and save the changes to the Virtru Platform.

Policy policy;
 policy.shareWithUsers({"bob@example.com"});
 
 client.updatePolicyForFile(policy, "sensitive.docx.tdf.html");

Now, bob@example.com should be able to view your sensitive data in Secure Reader (anywhere) or via the SDK decrypt call (in your apps).

When protecting new files, you can grant access to Bob or any number of users as part of encryption params:

Policy policy;
 policy.shareWithUsers({"bob@example.com"});
 EncryptFileParams params {"sensitive.docx", "sensitive.docx.tdf.html"};
 params.setPolicy(policy);
 
 client.encryptFile(params);

C++ Access Controls

No one can predict the future. Access controls let you change your mind about who has access and under what conditions.

Grant Access

Let’s say Bob enters your circle of trust. If you grant him access, he can decrypt your sensitive data.

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.shareWithUsers({"bob@example.com"});
 
     client.updatePolicyForFile(policy, "sensitive.docx.tdf.html");
     return EXIT_SUCCESS;
 }

You can also grant access before you encrypt:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.shareWithUsers({"bob@example.com"});
     EncryptFileParams params {"sensitive.docx", "sensitive.docx.tdf.html"};
     params.setPolicy(policy);
 
     client.encryptFile(params);
     return EXIT_SUCCESS;
 }
Revoke Access

Let’s say Bob leaves your circle of trust. It’d be great if he no longer had access to your sensitive data. Revoke will prevent Bob from decrypting your sensitive data:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.removeUsers({"bob@example.com"});
 
     client.updatePolicyForFile(policy, "sensitive.docx.tdf.html");
     return EXIT_SUCCESS;
 }

You will still have access to your sensitive data.

Revoke All Access

Let’s say you landed a new job Alice. Well done! But your circle of trust becomes outdated. Rather than removing every Bob from accessing your sensitive data, you can remove everyone with revoke all:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
     client.revokeFile("sensitive.docx.tdf.html");
     return EXIT_SUCCESS;
 }

You will still have access to your sensitive data.

Expire Access

Some things aren’t meant to last. Your landlord, Trent, shouldn’t have access to the sensitive data in your lease forever. Let’s make sure your sensitive data expires in a year when your lease does:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.expireInDays(365);
 
     client.updatePolicyForFile(policy, "lease.docx.tdf.html");
     return EXIT_SUCCESS;
 }

You can also expire at a specific date and time:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.addExpiration("2020-05-24T16:12:41Z"); // ISO-8601 Format
 
     client.updatePolicyForFile(policy, "lease.docx.tdf.html");
     return EXIT_SUCCESS;
 }

Expiration prevents everyone else on the policy from decrypting after that time. You will still have access.

Make the same expiration calls to update dates or times.

If you’re feeling permissive, you can always remove expiration too:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.removeExpiration();
 
     client.updatePolicyForFile(policy, "lease.docx.tdf.html");
     return EXIT_SUCCESS;
 }
Watermark Access

Trust doesn’t have to be absolute. If you want Bob to access your sensitive data, but discourage him from sharing it, you can enable watermarking:

#include <virtru_client.h>
 #include <cstdlib>
 
 using namespace virtru;
 
 int main()
 {
     auto email = std::getenv("VIRTRU_SDK_EMAIL");
     auto appId = std::getenv("VIRTRU_SDK_APP_ID");
     if (email == nullptr || appId == nullptr) {
         std::cerr << "An environment variable is not set:\n- VIRTRU_SDK_EMAIL\n- VIRTRU_SDK_APP_ID" << std::endl;
         return EXIT_FAILURE;
     }
     Client client {email, appId};
 
     Policy policy;
     policy.enableWatermarking();
 
     client.updatePolicyForFile(policy, "sensitive.docx.tdf.html");
     return EXIT_SUCCESS;
 }

This option only applies in Virtru’s Secure Reader, where Bob’s email address will always overlay the decrypted sensitive data.

To disable watermarking:

Policy policy;
 policy.disableWatermarking();
 
 client.updatePolicyForFile(policy, "sensitive.docx.tdf.html");

Sample Apps

We have built a few sample applications to get you up and running quickly. You may use these as starter projects, or look at their source code to learn about the SDK's features.

Protect & Track App

Try Sample App

View on GitHub

Encrypt & Decrypt App

Try Sample App

View on GitHub

Encrypt & Upload a File to S3

encrypt-and-upload-s3.js

      
         const Virtru = require('virtru-sdk');
          const AWS = require('aws-sdk');
          
          /**
           * Example showing how to encrypt and write a file to S3.
           * 
           * This example assumes you've installed the aws-sdk module and set up your AWS
           * credentials file. For more information, see: https://github.com/aws-samples/aws-nodejs-sample
           *
           * Example usage: 
           *   node sample.js your@email.com $(cat ~/.virtru/appId) hello.txt my-s3-bucket
           *
           * If your bucket is configured for static website hosting you'll be able to 
           * open up Secure Reader directly from the object link.
           * (e.g., http://my-s3-bucket.s3-website-us-west-2.amazonaws.com/hello.txt.html)
           */
          const email = process.argv[2];
          const appId = process.argv[3];
          const localFilename = process.argv[4];
          const bucketName = process.argv[5];
          
          // Initialize the Virtru and S3 clients.
          const client = new Virtru.Client({email, appId});
          const s3 = new AWS.S3();
          // Derive the object key to use by appending .html for easy browser support.
          const key = `${localFilename}.html`;
          const encryptParams = new Virtru.EncryptParamsBuilder()
              .withFileSource(localFilename)
              .withDisplayFilename(localFilename)
              .build();
          // The returned stream can be passed directly to s3.upload().
          client.encrypt(encryptParams).then(ct =>
           s3.upload({Body: ct, Bucket: bucketName, Key: key, ContentType: 'html/text'}, onComplete));
          
          function onComplete(err, data) {
            console.log(`${localFilename} encrypted and uploaded to S3 as ${key}`);
          }
        
    

Encrypt All Files in a Directory

encrypt-dir.js

      
         const Virtru = require('virtru-sdk');
          var fs = require('fs');
          
          /**
           * Example showing how to encrypt a directory asynchronously.
           * 
           * For this example we will use .zip format, which is more efficient 
           * and suitable for programmatic operations. Files with this format must
           * be decrypted with the SDK.
           *
           * Example usage: 
           *   node sample.js your@email.com $(cat ~/.virtru/appId) toEncrypt/ encrypted/
           */
          const email = process.argv[2];
          const appId = process.argv[3];
          const sourceDir = process.argv[4];
          const destDir = process.argv[5];
          
          // Initialize the client and destination directory.
          const client = new Virtru.Client({email, appId});
          fs.mkdirSync(destDir);
          // For each file in the directory, encrypt using the helper function.
          promises = fs.readdirSync(sourceDir).map(filename => encryptOne(filename));
          // Wait for all operations to finish, then write a completion message.
          Promise.all(promises).then(() => 
            console.log(`All files in ${sourceDir} have been encrypted and written to ${destDir}!`));
          
          async function encryptOne(filename) {
            const encryptParams = new Virtru.EncryptParamsBuilder()
              .withFileSource(`${sourceDir}/${filename}`)
              .withZipFormat() // Use the zip format.
              .build();
            ct = await client.encrypt(encryptParams);
            // Return the file write completion promise.
            return ct.toFile(`${destDir}/${filename}.tdf`);
          }
        
    

Architecture

Virtru Data Protection Platform

With the Virtru Data Protection Platform, you can quickly integrate security and privacy for any data type—such as files, emails, structured or unstructured data—produced or consumed by your applications and connected devices. Whether you are building web or mobile applications, IoT or ML projects, sensitive data can be encrypted and protected even when disseminated into untrusted environments.

Virtru Platform Workflow. The Virtru Key Management services maintain key data and control access. Your App, the Client, stores per object keys and their access policys with it. Alice, here representing either a user or automated system, can use your application to take plaintext payloads, and use the Virtru SDK to produce TDF Ciphertext Objects that are held by the user with an access policy the user or the service can author. These can also be shared to the customer directly or with untrusted third party datastores. Bob may then use another app, or the same app, can then request those keys and policies from the Virtr key management service, and use it to decrypt the TDF ciphertext objects with the virtru SDK to extract the original plain text.

Creating TDFs with the Virtru SDK

The Trusted Data Format (TDF) serves as the foundation for the Virtru Data Protection Platform, which simplifies data-level protection across systems and data types. Importantly, data owners maintain the ability to revoke, audit, and track the data even after it leaves their system. The Virtru SDK makes it easy to create TDFs and is interoperable across environments—including multi-cloud environments—so there are no vendor lock-in or infrastructure constraints.

Step 1: Protect

In a few lines of code, developers can use the Virtru SDK to encrypt any data using the TDF format within an application or as it leaves their application. TDF cryptographically binds together:

  • The payload (data to be encrypted)
  • Encryption keys (per object)
  • Access control policy

Importantly, TDF and the Virtru SDK allow developers to configure the access policy on the data as they wish. This can be based on any range of criteria, such as users, group membership, time, etc.

Step 2: Send Protected Data and Persist Protections

The data is now “self protecting” so you can send it anywhere. With the TDF protective wrapper traveling with the data, the data basically self protects by persisting encryption with the data wherever it goes.

Step 3: Audit Data Access

Authenticated systems / individuals will be requesting access over time. With each access request, new entries appear on the audit log. For instance, if you allowed re-sharing, this will appear in the audit logs and Control Center. If unauthorized access is attempted, the audit logs will show that as well. The audit log provides persistent insights into who accesses, or attempts to access, the data - where, when, and over time.

Step 4: Evolve Access Policies over Time

TDF and Virtru allow access policy changes over time, including by individuals, devices, or by geography, as your requirements change. Revocation is the most dramatic and impactful control, and visually demonstrates your full data control capabilities.

How It Fits Together: Architecture Diagram

The architecture diagram below details how the SDKs, Key Management Infrastructure, Policy Management via Control Center and the Trusted Data Format (TDF) combine to help you customize security and privacy into your applications.

Virtru SDKs provide an application interface on top of our Digital Policy Management framework, which allows a service to set, enforce and report on enterprise policies and rules. The Management Dashboard is the front end to that service. This builds on top of three key blocks: Identity Federation, Key Access Server (KAS), and the Entity Attribute Server (EAS), which are building blocks of the Virtru Key Management Infrastructure. These all build on the Trusted Data Format (TDF), an Open Standard for Self-Protecting Data.

The Trusted Data Format

As mentioned above, TDF provides the foundation for the entire Virtru Data Protection Platform. Created by Virtru Co-Founder and CTO, Will Ackerly, TDF is an open data format that provides a protective wrapper that travels with data. When invoked, Virtru SDKs ensure that all your objects (files, emails, etc) are encrypted, policy bound and persist as Trusted Data Format files. Once your objects are in TDF format, they can be shared or stored freely by your application. See our TDF overview to dive deeper into how it works.

Virtru SDKs

The Virtru SDK helps developers create TDFs within existing systems so organizations can reap the benefits of data protection and secure sharing. The Virtru SDK facilitates key management and access policies, including multiple access policies within specific files and retrieving user entitlements through streamlined communication with the policy server. Policy management is no longer the enemy but becomes simplified and evolves as access privileges evolve over time. Users can apply multiple classifications and access policies within a specific file, ensuring recipients can only view the portions that adhere to their access privileges.

Virtru's client SDKs are embedded into your applications and do all the heavy lifting. They expose simple encryption and decryption interfaces to integrate security and privacy into your applications. The Virtru SDK is currently available in Javascript, C++, and Python, with additional languages coming soon. With minimal memory footprint, Virtru's SDKs are extremely scalable and won’t slow you down.

Digital Policy Management via Control Center

Virtru Control Center is an administrative dashboard that allows admins to set, enforce, audit and revoke all key access requests, and thus all data requests. Admins also use Control Center to define policies, manage users and revoke access.

Virtru Key Management Infrastructure

Virtru SDKs use Virtru's Key Management Infrastructure by default. Virtru's Key Management Infrastructure is based on Attribute-Based Access Controls (ABAC) and contains services necessary to host, secure, and control the access of the encryption keys. The Virtru Key and Policy Management Infrastructure stores and retrieves keys as well as the policies associated with the keys. This highly scalable and secure infrastructure acts as a backend for KAS.

Key Access Server (KAS) and Management Infrastructure

The KAS acts as a Policy Decision Point (PDP). KAS decides whether an entity has the privilege to decrypt an object—like a file or email—or not. KAS makes this decision based on both an object’s access requirements as well as user privileges. If the user meets the access requirements, the decryption key is returned to the client. If not, access is denied.

Entity Attribute Server (EAS)

EAS provides Identity Management services and returns the attributes associated with an authenticated user. These attributes are used by KAS to make key access decisions. EAS supports Federated Identities, thus ensuring that customers can apply their pre-existing identities (and attributes).

Identity Federation

Virtru SDKs integrate existing identity standards such as OpenId, OAuth, and SAML, for user authentication. There is no need to recreate identity standards, expediting authentication and allowing you to work within your preferred identity standard. Our federated identity management simplifies authentication while maintaining the granular access controls to optimize security and privacy and prevent unauthorized data access.

Security Model

By creating a security model focused on the data, the Virtru Data Protection Platform disrupts the decades-old network security paradigm to give data owners greater control. A combination of crypto, policy, and access management features provide robust protection that travels with data regardless of platform or system.

Data as the New Perimeter

Done right, you’ll no longer need to trust the systems storing your data. With the Trusted Data Format (TDF) as the open format for data-level security protections, Virtru and TDF together enable a fundamental shift in security models. Instead of placing the numerous control requirements on any system storing your data, these same requirements are placed on the data so you can securely create or share data with specific access policies. Fundamentally, Virtru and the TDF together allow you to:

  • Encrypt data to enforce policy.
  • Let your data go anywhere.
  • Grant or deny access inside and outside your environment.
  • Audit access over time.
  • Change policy as needed after dissemination.

Data remains protected not only within corporate sanctioned applications, but also as it travels across the range of platforms and services, including cloud-based apps and external partners.

Corporate Sanction Applications can use data in TDF form. This allows data to remain protected whereever it is shared; object-level protections enable persistent access control and monitoring. Thus they can flow out of the application to dropbox, then through services to other users, or through slack, email with exhange, or document services such as Office 365.

Data in and out of an organization

Descriptive, Crypto Agile, and Quantum-Ready

Every object explicitly declares HOW it was encrypted, with what algorithms, key sizes, and modes. This enables maximum interoperability and future-proofing, to allow the application of the strongest crypto standards at any given time. As crypto standards evolve, it is easy to update and replace them without disrupting the underlying security model.

Payload Encryption

To protect confidentiality and integrity of data wherever it goes, TDF supports encryption of any size and type of payload (see TDF Overview for links to how the schema supports all scenarios) with support and use of the strongest encryption standards available.

Symmetric Key Payload Encryption

Virtru apps and SDKs today implement the following symmetric algorithm and modes:

  • AES-256-GCM (256-bit key Advanced Encryption Standard in Galois Counter Mode) (default)
  • AES-256-CBC (256-bit key Advanced Encryption Standard in Cipher Block Chain) (deprecated)

Note: CBC is recommended for use only to read previously encrypted TDF objects.

Asymmetric Wrapping of Data Encryption Keys

Virtru apps and SDK universally implement RSA 2048 by default for maximum interoperability. Elliptic Curve Cryptography has been implemented, but deployed today in a limited fashion. If you have an interest in ECC-enabled TDF please reach out to our devs at developers@virtru.com. We’d love to work with you.

Payload Integrity for Any Object Size

The latest TDF allows for the inclusion of explicit data integrity metadata. This is designed in particular to support:

  • Very large file encryption and decryption: segmentInfo can contain encryption information for parts of files, enabling large files to be encrypted in smaller chunks, with encryption metadata (including integrity) of each chunk being stored in this element. A parent hash strategy against the whole ensures that no segment can be removed or re-ordered.
  • Streaming data integrity: similar to large files, per segment validation allows only some of a given file to be downloaded and still be able to validate its integrity. This is crucial for performant viewing of streamed and/or large content where integrity is required.

Let Your Data Go Anywhere

Track and evolve policies over time with granular access privileges and audit features, even after data dissemination.

Access Control Policy & Object-Level Assertions

Access control policy can be either embedded within a TDF as a cryptographically-bound object independent of payload or remotely managed. This can take the form of a TDF Assertion, with or without payload encryption. For encrypted payloads, policy can be cryptographically bond to the payload key via HMAC (see TDF spec for details).

Policies can be created in almost any fashion via a flexible Attribute-Based Access Control model. This can include the use of data attributes like classification or authorities, or basic access control lists like email addresses. Please see our SDK documentation for more details.

Audit Access Over Time

TDF protocol and infrastructure enables logging every key request for reliable auditing and tracking of access requests. This provides an unprecedented ability to track who accesses what data, at what time, and where. The data audit can not only track by person, but also by location and device. Data can be bound to groups and individuals as well as to devices and locations.

Change Policy as Needed After Dissemination

The capabilities above can be composed, in particular when using Virtru SAAS key management, to give you the ultimate ability to evolve policy over time in sync with changing needs or based on observed threats in particular as surfaced by audit.

Glossary

ACM

See “Access Control Manager.”

Access Control Manager

Central component of SaaS key management infrastructure that hosts and manages keys, enforces policies for access controls, and brokers access to protected data via authentication and authorization. Also see “Entity Attribute Service” and “Key Access Server.”

Active Policy

Any protected data interaction over a 30-day period via operations like encrypt, decrypt, access, or updates to protected data. Also see “Policy.”

appId Token

An authentication token and associated email address that identify an entity to the Virtru Platform. Subject to expiration every 120 days. How do I get an appId?

Domain Whitelisting

A process by which Virtru verifies a domain as a valid endpoint for use with the Virtru JavaScript SDK. How do I whitelist my domain?

EAS

See “Entity Attribute Service”

Entity

A user trying to protect or access data. Not necessarily human (e.g. bots or devices). Identified by email address.

Entity Attribute Service

Provides identity management services and asserts attributes owned by an entity.

HMAC Token & Secret

An authentication method that identifies a set of entities under one organization to the Virtru Platform. Not subject to expiration. Also see “appId Token.”

KAS

See “Key Access Server.”

Key Access Server

Determines whether an entity has access to request decryption key or not.

Owner

See “Policy Owner.”

Policy

A way to control access to protected data throughout its lifecycle. Also see “Active Policy” and “Policy Owner.”

Policy Owner

The entity that owns the policy. Commonly the same entity that created the policy by protecting sensitive data. Also see “Policy.”

.tdf File Extension

Data encrypted with a Virtru SDK in ZIP format. Also see “.tdf.html File Extension” and “Trusted Data Format.”

.tdf.html File Extension

Data encrypted with a Virtru SDK in HTML format. Also see “.tdf File Extension” and “Trusted Data Format.”

TDF

See “Trusted Data Format.”

Trusted Data Format

An open format for data-centric protection that binds encrypted data to policies and metadata ensuring that only the owner and authorized entities have access. Read the TDF3 spec.

Virtru Control Center

A web-based administrative console for managing, tracking, and controlling data protection policies.

Virtru Secure Reader

A web-based Virtru product that allows users to authenticate, decrypt, and view protected data.

FAQs

How to Open a TDF

Let's say someone you added to the policy got a .html or .tdf file. This is how they can open the file:

Open a .html file

  1. Drag and drop the .html file into a browser window.
  2. The file is automatically redirected to Virtru Secure Reader and file will be decrypted.
  3. If the redirect does not automatically take place, click on View File in Virtru Secure Reader.

Open a .tdf file

  1. Visit Virtru Secure Reader.
  2. Follow instructions to authenticate.
  3. Drag and drop the .tdf file into the browser tab and file will be decrypted.

Alternatively, the authorized user can always decrypt the file using the SDK.

How to Download an AppID Token

Remember Please be sure to protect all credentials and secrets. Follow best practices.

You can copy your AppId from Virtru Control Center by following these instructions:

  1. Login to Virtru Control Center using one of the supported authentication schemes.

  2. Under "Personal" section, click on "Settings"

  3. Toggle the switch to turn on the Developer Mode.

  4. Copy the AppId displayed.

Screen shot of the Developer Settings tab within the Virtru Organization Administion Dashboard

How to disable your AppID? Simply toggle the Developer Mode to OFF.

How to Allowlist Your Site with Virtru

In order authenticate outside of your local environment or to use Federated Authentication schemes on your site, you need to list your domain with Virtru. This will allow our team to verify your domain as a valid endpoint for Virtru SDKs.

  1. Login to the Virtru Control Center.

  2. Under the "Personal" section, click on "Settings".

  3. Turn on "Developer Mode" if it's not on already.

  4. In "Verify Domains" section, enter the domain you'd like to register.

  5. The Virtru Support team will receive the request and get back to you on the email address corresponding to your login in Step 1.

Screen shot of the Settings page within the Virtru Organization Administion Dashboard

Problems onboarding your domain? Please reach out to developers@virtru.com if you need help getting your domain enabled with the Virtru SDK.

Community

Contact Us

At Virtru, we believe security and privacy applications should be community driven.

Have a suggestion or need help?

Open a support ticket

Join our Slack community

Get your questions answered with Virtru's Developer Hub on Slack

Join Virtru on Slack

Code of Conduct

Introduction

Our goal for the Virtru Developer Hub Community is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).

This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.

We invite all those who participate in the Virtru Developer Hub Community to help us create safe and positive experiences for everyone.

Expected Behavior

We expect all community members to:

Unacceptable Behavior

The following behaviors are considered harassment and are unacceptable within our community:

Consequences of Unacceptable Behavior

Unacceptable behavior from any community member will not be tolerated. Anyone asked to stop unacceptable behavior is expected to comply immediately.

If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning.

Reporting Guidelines

If you are the subject of, or witness to any violations of this Code of Conduct, please notify us by email at developers at virtru dot com.

If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify developers at virtru dot com for review.

License and attribution

This code of conduct is derived from the Citizen Code of Conduct and the Django Code of Conduct under a Creative Commons Attribution-ShareAlike license.

Responsible Disclosure

Virtru Responsible Disclosure Policy

Virtru considers trust and the protection of our customers' data as a highest priority. Therefore, Virtru takes the security of our systems extremely seriously.

We acknowledge the valuable role that independent security researchers play in security and, as a result, we encourage responsible reporting of any vulnerabilities that may be found in our site or applications. Virtru is committed to working with security researchers to verify and address any potential vulnerabilities that are reported to us in accordance with this responsible disclosure policy.

Reporting a Potential Security Vulnerability

For the security of our users and service, we ask that you do not share details of the suspected vulnerability publicly or with any third party.

Please report the details of any suspected or detected vulnerabilities with Virtru by emailing developers@virtru.com, including the following information:

Prohibited Actions

While we encourage you to discover and report to us any vulnerabilities you find in a responsible manner, the following conduct is prohibited:

Our Commitment to Researchers

If you responsibly report a vulnerability in accordance with this policy, we will:

Contributor Hall of Fame

Virtru greatly appreciates anyone who has contributed to the security of our users by responsibly disclosing vulnerabilities to us. Thank you for your efforts!

About Virtru

Virtru was founded on the core belief that privacy-preserving data protection is both a fundamental right and a force multiplier for organizations. Building an open, collaborative community is core to making this vision a reality.

The Virtru Developer Hub aims to make privacy-preserving data protection accessible and impactful by providing developers with turn-key, easy-to-integrate SDK, APIs, and key management.

Operating at the Intersection of Security and Privacy

Security compromises are increasingly privacy compromises, with a growing overlap in the area of unauthorized data access. At Virtru, we operate at this nexus of security and privacy to ensure our customers can reap the benefits of protecting against unauthorized data access while fostering data sharing and collaboration.

Virtru: at the intersection of Privacy and Security

Data protection strategies traditionally focus on locking down data, which comes at a significant cost; organizations fail to reap the benefits of collaboration and data sharing. Modern data protection requires protecting against unauthorized data access - including through compromise, unauthorized third-party sharing, or misconfigured servers and databases - while simultaneously securely sharing and collaborating internally and externally to achieve mission objectives.

By focusing on the intersection of privacy and security, organizations can gain a competitive advantage and garner new insights and innovations through data sharing while advancing both security and privacy. The Virtru Data Protection Platform helps organizations succeed at this intersection of security and privacy by providing flexible and persistent data protection that travels with the data to promote secure data sharing and collaboration.

Read our “Succeeding at the Intersection of Security and Privacy” white paper at IAPP:

Read Our Whitepaper

The Virtru Difference

With an open data protection ecosystem including the Trusted Data Format, SDK, and APIs, and a focus on ease of use for both developers and end users, Virtru helps organizations protect and share data across environments, applications, and devices.

Secure Collaboration Across Environments

Gain confidence sharing and disseminating data, even in untrusted environments, thanks to TDF protections that travel with the data.

Highly Scalable Security Model

Key management with Attribute-Based Access Controls helps developers build complex applications with fine-grained security settings while maintaining the flexibility to evolve key management policies over time.

Provable Security and Privacy

Audit features provide demonstrable validation that security safeguards were implemented, helping adhere to current and future regulatory requirements.

Open and Customizable Development

Avoid proprietary black boxes and customize data protection solutions with Virtru SDK and APIs.

Learn More about the Virtru Ecosystem

Virtru already helps thousands of organizations protect their most sensitive data. The Virtru SDK helps integrate Virtru protections into customizable applications. The Virtru Data Protection Platform offers additional enterprise benefits. Built-in integrations into GSuite, Office365, and many SaaS applications are available to scale your solutions in any environment through Virtru Hosted, Hybrid, and On-Prem deployment models.

Learn more about the flexible deployment models and key management hosting options by contacting us.

Contact Us to Deploy & Host