The Evervault Encryption Engine.
E3 is built on AWS Nitro Enclaves. Nitro Enclaves are isolated, hardened, and highly constrained virtual machines (EC2 instances).
Using enclaves means that Evervault cannot access your data. Enclaves have no persistent storage, no interactive access, and no external networking. Root users and admin users on the parent EC2 instance cannot access or SSH into the enclave. The only way to communicate with the enclave is through the secure local channel from the parent EC2 instance attached to the enclave.
Enclaves have attestation for verifying that only authorized code is running in the enclave, and to verify the enclave’s identity.
The current Evervault Encryption Scheme (EES) comprises two sets of keys: the Team Master Key, and a public/private asymmetric key pair.
- Team Master Key (TMK)
- Asymmetric Key Pair
When an Evervault Team is created, a Team Master Key (TMK) is provisioned for that team.
It is generated for AES-256 symmetric encryption, and we use Shamir’s Secret Sharing to split it into three shares with a quorum of three. Of these three shares, two are stored in Evervault’s databases encrypted using a key that is only accessible by E3’s AWS Nitro Enclave. Your API key is generated by taking the third share and offsetting it by XORing each byte of the share with randomly generated “offset bytes”, which are stored on Evervault. Evervault stores the API key encrypted in its database using AWS KMS to allow you to retrieve it using the Dashboard. Each access request is tracked and there is a full audit log of each API key decrypt operation.
Encrypting data using our SDKs
The team ECDH public key is loaded in the Evervault SDK, which generates an ephemeral ECDH keypair per encryption. The SDK then derives a 32-byte (256 bit) shared secret using the team ECDH public key and the ephemeral ECDH private key.
The data is then encrypted using AES-256-GCM with a 12 byte initialization vector (IV) and 16 byte auth tag. A string is generated containing the ephemeral ECDH public key, AES-encrypted data and the key IV.
The plaintext AES key and the ephemeral ECDH private key are discarded.
The encrypted data returned by the Evervault SDK is then stored in your database. Evervault does not store the data in any form—neither in plaintext, nor encrypted.
Evervault-encrypted data is encoded using the following structure:
|Used so that you can easily identify Evervault-encrypted strings.|
|Allows you to easily identify the type of data that was encrypted.|
|Randomly-generated Base64-encoded Initialization Vector used for AES|
|Base64-encoded representation of the ephemeral ECDH session public key that was used to derive the shared secret AES key for the particular string.|
|The original data that has been encrypted by AES-256-GCM using the randomly generated key.|
Our data structure is designed so that you don’t need to change your database configuration. You can store Evervault-encrypted data in your database as you would the plaintext data.
Encrypting data using Relay
Plaintext data is sent to a Relay URL over HTTPS. Relay searches the payload for fields matching the patterns specified in "fields to encrypt" in the Dashboard.
- Relay sends the fields to encrypt to E3.
- E3 generates an ephemeral keypair for each field, encrypts the field with the keypair using the mechanism described above and replaces the original value with the encrypted value.
- E3 returns the encrypted data to Relay and Relay passes the original request to its destination, with plaintext data replaced with encrypted data.
Processing data with Cages
Encrypted data is sent to a Cage by calling
evervault.run() in one of our SDKs. It can also be sent directly over HTTPS by sending a request to
A Cage consists of two components: the Evervault Runtime, and the serverless function you deploy to it.
- The Evervault Runtime exposes an instance of the Evervault Node.js SDK globally (accessible through the evervault global variable), which means that you don't need to include the SDK in the serverless function.
- The Evervault Runtime decrypts the team private ECDH key with the TMK by offsetting the API key provided with the stored offset bytes and then combining that with the remaining two shares to reconstruct the TMK.
- The decrypted ECDH private key is automatically cached in the Runtime.
- The decrypted ECDH private key decrypts the Evervault-encrypted data as the data is passed through the Runtime to your serverless function.
- The result of the Cage is returned and, optionally, encrypted within the Cage using the Node.js SDK. The encrypted value can be stored in your database.
- The Cage is ejected, and garbage collection (of keys, data and result) occurs, i.e. Cages are stateless.
Processing data with Relay
When you initialize the Evervault SDK in your backend, your app authenticates with Evervault using your API key. The SDK will intercept outbound network requests and route them through Evervault, where the payload is scanned for data matching Evervault-encrypted strings. The encrypted strings are then removed from the payload and sent to E3 along with your API key. E3 offsets your API key using the offset bytes to compute the share, and combines it with the remaining two shares to derive your TMK and decrypt your team’s ECDH private key.
- Relay does not manage any key material. All cryptographic operations occur within E3.
- At present, Relay does handle the resulting decrypted data (temporarily) before passing it to its destination. Decrypted data is only stored for the milliseconds required to establish a connection.
- In future, E3 will support TLS-termination within the enclave itself. This would mean Relay never handles plaintext data or key material and would be end-to-end encrypted.
- Responses from your API that pass through Relay will also be decrypted in a similar fashion, meaning that your API can receive and return Evervault-encrypted data with no noticeable difference to your users.