TozStore makes application-level, end-to-end cryptography easy for developers. Most devs aren’t trained in cryptography, so TozStore provides devs with familiar, easy to master tools that run complex, powerful cryptographic operations under the hood. TozStore handles those areas of cryptography that are easy to get wrong (e.g. key generation, algorithms, modes). Whether you are new to cryptography or already highly experienced in implementing crypto, this guide will quickly have you comfortable using TozStore to drastically improve the security of your applications and establish a trustworthy way to write, read, and share data.
Strength of Application-Level Encryption
TozStore provides application-level encryption. Systems that take advantage of encryption to strengthen security typically use infrastructure-level encryption and not application-level encryption. Application-level encryption provides greater application security than infrastructure-level encryption.
With infrastructure-level encryption, networking or database infrastructure is encrypted, so data is encrypted when it is in this infrastructure and not encrypted when it is outside this infrastructure. Infrastructure-level encryption approaches like Virtual Private Networks (VPNs) protect data in transit and can control access to a network. Anyone with access to the network, has access to the services and all data within those services. With infrastructure-level encryption, data will no longer be secure if data leaks outside of the network infrastructure or an attacker bypasses standard access control mechanisms.
TozStore provides application-level security that secures data for its entire life-cycle. Data gets encrypted where it is generated (written) and decrypted where it is consumed (read), providing end-to-end encryption. TozStore encrypts data records individually, providing powerful and fine-grained access control for sharing and revoking access to records. As result, data carries its own security. No matter what infrastructure it crosses, data remains encrypted and secure. Even if data leaks outside of the network infrastructure, gets backed up to an insecure location, or is hacked by an online adversary, the encrypted data remains secure.
For Devs New To Crypto
You do not need to study cryptography in order to integrate strong cryptography in your applications. TozStore will allow you to properly implement strong cryptography with developer-friendly tools that provide a layer of higher-level abstraction over complex cryptographic operations. Devs who are not familiar with cryptography will likely want to know first and foremost how they can trust both TozStore and their own use of TozStore tools to properly implement cryptography in their applications.
Getting Started
Endpoints as TozStore Clients
As a developer using TozStore, you first need to determine what constitutes an end-point in your system. You can install the necessary TozStore SDKs (software development kits) to gain access to TozStore tools. TozStore currently provides SDKs for the following languages: JavaScript for the browser, back-end JavaScript (Node), Python, Ruby, Go, plain Java, Java for Android, Swift,and PHP.
TozStore understands endpoints as clients. Every TozStore client needs a unique set of client credentials that must be generated and provided securely as parameters to instantiate a client instance using an SDK. The client instance possesses read, write, share, revoke, and other methods.
A client's credentials are integrally involved when they perform cryptographic operations, prime examples being when client writes (encrypts), reads (decrypts), and shares access to data records. Because of this, compromised private keys pose a great security risk, and using TozStore properly requires strong key management.
Client Credentials And Key Management
Key management is a foundational security concern while using TozStore. Most significantly, client credentials include a private key that is critical for security. Making a private key public compromises the security provided by TozStore the same way leaving a key in a lock would undermine the security provided by the lock. Losing access to keys also poses the risk of losing access to data, as data encrypted with a client's credentials cannot be decrypted without the relevant client credentials.
The security of data stored using TozStore depends upon the key management practices used surrounding TozStore tools. The section on Key Management in this guide offers advice on making a key management plan. In this section, the team at Tozny who created the TozStore system will share some of our concerns, best practices, and decisions regarding key management. Hopefully, this will help you confidently and quickly decided on the key management plan that is right for your system.
Once you have decided on a way to manage your client credentials, TozStore provides a few ways to generate client credentials. Clients have the option of whether to store an encrypted back-up of their credentials on the server. In choosing a workflow for registering clients, consider the balance between concerns over the security of private keys and the ability to recover lost private keys.
Generating Client Credentials
Regardless of how you choose to generate client credentials and register clients, you will need to use the Tozny Dashboard, a collection of Tozny tools. Create a free account with Tozny. Save this link for easy, future use.
The first way to generate client credentials is go to the Dashboard then Clients tab and click the action button to create a new client, then gather the client's credentials presented as a JSON. In this one action, the Dashboard will generate the needed keys, register the client with TozStore and receive the resulting TozStore client ID and credentials needed to authenticate with the Tozny API. Additionally an encrypted back-up of the client's credentials in TozStore. To avoid having a backup created read on for how to create clients programatically below.
This same workflow can be implemented using a TozStore SDK to dynamically generate client credentials, register, and back-up clients. However, you may be less concerned with being able to retrieve lost private keys and more concerned with stronger security. In this case, you may want a client's private key to only ever be available locally, so you will not want to back-up client credentials in TozStore. In this case, you can dynamically generate client credentials and register clients without backing up client credentials in TozStore.
Dynamically generating client credentials using a TozStore SDK requires first generating a client registration token using the Dashboard. When you generate client credentials and register clients with the Dashboard, your Tozny account username and password enable access to the Tozny API. A client registration token stands in for this layer of authentication.
Overview of Client Credentials
A developer does not need to understand the role client credentials play in allowing a TozStore client to encrypt, decrypt, and share data securely to use TozStore. However, a basic understanding client credentials and the way they are generated may be useful for some developers who want to understand how TozStore works and what they are trying to achieve. Beyond generating a full set of client credentials and passing those client credentials in a secure way to an client instance using a TozStore SDK, you will not need to directly interact with client credentials except for TozStore client IDs.
A full set of client credentials will include: a human-readable name, a unique TozStore client ID, a public and private key-pair used to encrypt and decrypt data, a public and private key-pair used to sign data and validate a signature, an api url, and a pair of api credentials used to authenticate calls made to the TozStore API.
An example of a json containing a full set of TozStore client credentials looks like this:
{
"version": 1, --> version 1 or 2 (1 is only for early TozStore users)
"api_url": "https://dev.e3db.com", --> api url the client will use for requests
"api_key_id": , --> enables authentication to make TozStore API calls
"api_secret": , --> enables authentication to make TozStore API calls
"client_id": client's unique TozStore client ID
"client_email": , --> not currently used
"public_key": , --> client's public data encryption key
"private_key": , --> client's private data encryption key KEEP SECURE
"public_sign_key": , --> client's public signing key
"private_sign_key": --> client's private signing key KEEP SECURE
}
The underlying workflow for generating a full set of client credentials includes three stages:
1) A client name and api url are provided as strings, and TozStore SDK methods are used to generate a public key and private key-pair and a public signing key and private signing key-pair.
2) A TozStore SDK client.register method sends the above, partial client credentials to TozStore, and TozStore sends back a unique a client ID, an API key, and an API secret.
3) If desired, the now full set of client credentials are encrypted and backed up in TozStore.
Once a full set of client credentials is generated and a client is registered in TozStore, a client instance can be instantiated using a TozStore SDK to give access to TozStore tools, including methods to write, read, and share data.
Front-End TozStore Clients & Public TozStore Forms
Data Record Structures
Next, you need to determine what structure would be best for your data records. Data records consist of plain-text metadata, plain-text keys, and encrypted values. Plain-text metadata allows querying encrypted data sets.
Records also have a type. By default, data is only accessible by the client that wrote the record. The share method grants other clients access to data of a given type. Shared access to a data type can also be revoked. A record's type provides a way to batch records for granting access between clients.
TozStore
Install and Import Tozny SDK
// Run the following command in your terminal. $npminstall--savee3db// `npm` will update your `package.json`.// Alternatively: // Add `e3db` as a dependency in your package.json."dependencies":{"e3db":"^1.2"}// Then run the install command in your terminal. $npminstall
# With Pip, in terminal:$pipinstalle3db
# Add this line to your application's Gemfile:gem'e3db'# And then execute:$bundle# Or install it yourself as:$geminstalle3db# At runtime, you will need the libsodium cryptography library.# Libsodium is required by the native RbNaCl Ruby library.# On most platforms a package is available by default:# (Mac OS X)$brewinstalllibsodium# (Ubuntu)$apt-getinstalllibsodium-dev#For libsodium installation instructions for Windows, see the libsodium web site.# Windows Users: Make sure to download a recent "MSVC" build. # Once downloaded, find the most recent libsodium.dll inside the ZIP file.# Rename it to sodium.dll and copy it to C:\usr\local\lib. # You can also copy it to your \Windows\System32 directory.
// ANDROID// The E3DB SDK targets Android API 16 and higher. // To use the SDK in your app, add it as a dependency to your build. // In Gradle, use:repositories{maven{url"https://maven.tozny.com/repo"}maven{url"https://dl.bintray.com/terl/lazysodium-maven"}}implementation('com.tozny.e3db:e3db-client-android:4.0.0-RC2@aar'){transitive=true}// The SDK contacts Tozny's E3DB service.// Your application also needs request INTERNET permissions.// PLAIN JAVA // For use with Maven, declare the following repository and dependencies:<repositories><repository><id>tozny-repo</id><name>ToznyRepository</name><url>https://maven.tozny.com/repo</url></repository></repositories><dependencies><dependency><groupId>com.tozny.e3db</groupId><artifactId>e3db-client-plain</artifactId><version>4.0.0-RC2</version></dependency></dependencies>
// To install with composer add the following to your composer.json file:
"require": {
"tozny/e3db": "1.1.0"
}
// Then run:
$ php composer.phar install
// If your project uses Glide for managing dependencies and reproducible builds: // Add the E3DB client library to your glide.yaml by running:$glidegetgithub.com/tozny/e3db-go// If you do not use Glide and want to depend on the latest version of E3DB:// check out the repository to the correct location within $GOPATH // Then install dependencies using Glide.gitclonehttps://github.com/tozny/e3db-go $GOPATH/src/github.com/tozny/e3db-gocd$GOPATH/src/github.com/tozny/e3db-goglideinstall
// E3db is available through CocoaPods. // To install it, simply add the following line to your Podfile:pod"E3db",:git=>'https://github.com/tozny/e3db-swift'
TozStore currently provides SDKs for the following languages: JavaScript (Node), Python, Ruby, Go, Java, Swift,and PHP. Our libraries are open source and available here:
You can create clients directly in the Tozny Dashboard. You can simply grab the client credentials from the console. Clients registered from within the console will automatically back their credentials up to your account. You can also create clients dynamically using a Tozny SDK and optionally back-up client credentials.
Register Client With Back-Up (SDK)
conste3db=require('e3db')lettoken='...'letclientName='...'asyncfunctionmain(){letcryptoKeys=awaite3db.Client.generateKeypair();letsigningKeys=awaite3db.Client.generateSigningKeypair();letclientInfo=awaite3db.Client.register(token,clientName,cryptoKeys,signingKeys,true)// ... Run operations with the client's details here}main()
importe3dbtoken='...'client_name='...'public_key,private_key=e3db.Client.generate_keypair()client_info=e3db.Client.register(token,client_name,public_key,private_key=private_key,backup=True)# Now run operations with the client's details in client_info
Use the Tozny Dashboard to create a client registration token. With this token, you can dynamically create clients with with any of our SDK's. (To generate clients without backing up credentials, see the next section.)
The private key must be passed to the registration handler when backing up credentials as it is used to cryptographically sign the encrypted backup file stored on the server. The private key never leaves the system, and the stored credentials will only be accessible to the newly-registered client itself or the account with which it is registered.
Register Client Without Back-Up (SDK)
conste3db=require('e3db')lettoken='...'letclientName='...'asyncfunctionmain(){letcryptoKeys=awaite3db.Client.generateKeypair();letsigningKeys=awaite3db.Client.generateSigningKeypair();letclientInfo=awaite3db.Client.register(token,clientName,cryptoKeys,signingKeys,false)// ... Run operations with the client's details here}main()
importe3dbtoken='...'client_name='...'public_key,private_key=e3db.Client.generate_keypair()client_info=e3db.Client.register(token,client_name,public_key)# Now run operations with the client's details in client_info
importE3db// This is the main client performing E3db operations// (for the remaining examples, we'll assume a non-optional client instance)vare3db:Client?Client.register(token:e3dbToken,clientName:"ExampleApp"){resultinswitchresult{// The operation was successful, here's the configurationcase.success(letconfig):// create main E3db client with configself.e3db=Client(config:config)case.failure(leterror):print("An error occurred attempting registration: \(error).")}}}
Use the Tozny Dashboard to create a client registration token. With this token, you can dynamically create clients with with any of our SDK's. (To generate clients backing up credentials, see the previous section.)
The object returned from the server contains the client's UUID, API key, and API secret (as well as echos back the public key passed during registration). It's your responsibility to store this information locally as it will not be recoverable without credential backup.
Load Client Credentials (Configuration) and Create Client Instance
/* Configuration is managed at runtime by instantiating an e3db.Config object with your client's credentials. */conste3db=require('e3db')/**
* Assuming your credentials are stored as defined constants in the
* application, pass them each into the configuration constructor as
* follows:
*/letconfig=newe3db.Config(process.env.CLIENT_ID,process.env.API_KEY_ID,process.env.API_SECRET,process.env.PUBLIC_KEY,process.env.PRIVATE_KEY,process.env.API_URL)/**
* Pass the configuration when building a new client instance.
*/letclient=newe3db.Client(config)
importe3dbimportos# Assuming your credentials are stored as defined constants in the# application, pass them each into the configuration constructor as# follows:config=e3db.Config(os.environ["client_id"],os.environ["api_key_id"],os.environ["api_secret"],os.environ["public_key"],os.environ["private_key"])# Pass the configuration when building a new client instance.client=e3db.Client(config())
require'e3db'config=E3DB::Config.defaultclient=E3DB::Client.new(config)# The E3DB Command-Line Interface allows you to register # and manage multiple keys and credentials using profiles.# To register a new client under a different profile:$e3dbregister--profile=developmentdevelopers@mycompany.com# You can then load a specific profile inside your Ruby application:config=E3DB::Config.load_profile('development')client=E3DB::Client.new(config)
/**
* Assuming your credentials are stored as defined constants in the
* application, pass them each into the configuration constructor as
* follows:
*/
$config = new \Tozny\E3DB\Config(
CLIENT_ID,
API_KEY_ID,
API_SECRET,
PUBLIC_KEY,
PRIVATE_KEY,
API_URL
);
/**
* Pass the configuration to the default coonection handler, which
* uses Guzzle for requests. If you need a different library for
* requests, subclass `\Tozny\E3DB\Connection` and pass an instance
* of your custom implementation to the client instead.
*/
$connection = new \Tozny\E3DB\Connection\GuzzleConnection($config);
/**
* Pass both the configuration and connection handler when building
* a new client instance.
*/
$client = new \Tozny\E3DB\Client($config, $connection);
// Here is some simple example code to connect and list records:packagemainimport("context""fmt""log""os""github.com/tozny/e3db-go")funcmain(){client,err:=e3db.GetDefaultClient()iferr!=nil{fmt.Fprint(os.Stderr,err)return}cursor:=client.Query(context.Background(),e3db.Q{})for{record,err:=cursor.Next()iferr==e3db.Done{break}elseiferr!=nil{log.Fatal(err)}fmt.Println(record.Meta.RecordID)}}
Configuration is managed at runtime by instantiating an e3db.Config object with your client's credentials.
Write (Encrypt) New Data Record
record=client.write('contact',{:first_name=>'Jon',:last_name=>'Snow',:phone=>'555-555-1212'})printf("Wrote record %s\n",record.meta.record_id)
Clientclient=...;// Get a client instanceMap<String,String>lyric=newHashMap<>();lyric.put("line","Say I'm the only bee in your bonnet");lyric.put("song","Birdhouse in Your Soul");lyric.put("artist","They Might Be Giants");StringrecordType="lyric";client.write(recordType,newRecordData(lyric),null,newResultHandler<Record>(){@Overridepublicvoidhandle(Result<Record>r){if(!r.isError()){// record written successfullyRecordrecord=r.asValue();// Log or print record ID, e.g.:System.out.println("Record ID: "+record.meta().recordId());}else{// an error occurredthrownewRuntimeException(r.asError().other());}}});
// Create data for a recordvarrecordDatamap[string]stringrecordType:="contact"recordData["first_name"]="Jon"recordData["last_name"]="Snow"recordData["phone"]="555-555-1212"// Create optional metadata for the record//(metadata can be used for searching)varmetadatamap[string]stringmatadata["realm"]="The North"metadata["pet"]="Ghost"// Encrypt and save the recordrecordID,err:=client.Write(context.Background(),recordType,recordData,metadata)iferr!=nil{//Error handling omitted}fmt.Println("Wrote record: "+recordID)
// Wrap message in RecordData type to designate// it as sensitive information for encryptionletrecordData=RecordData(cleartext:["SSN":"123-45-6789"])// Can optionally include arbitrary metadata as `plain`// where neither keys nor values are encryptede3db.write(type:"UserInfo",data:recordData,plain:["Sent from":"my iPhone"]){resultinswitchresult{// The operation was successful, here's the recordcase.success(letrecord):// `record.meta` holds metadata associated// with the record, such as type.print("Wrote record! \(record.meta.recordId)")case.failure(leterror):print("An error occurred attempting to write the data: \(error)")}}}
importe3dbclient=e3db.Client(# config)record_type='contact'data={'first_name':'Jon','last_name':'Snow','phone':'555-555-1212'}metadata={'house':'Stark'}record=client.write(record_type,data,metadata)print'Wrote record {0}'.format(record.meta.record_id)
conste3db=require('e3db')letclient=newe3db.Client(/* config */)asyncfunctionmain(){letdata={'first_name':'Jon','last_name':'Snow','phone':'555-555-1212',}letmetadata={'house':'Stark'}letrecord=awaitclient.write('contact',data,metadata)console.log('Wrote record '+record.meta.recordId)}main()
<?php$data=['name'=>'Jon Snow','what_he_knows'=>'Nothing',];$metadata=['house'=>'Stark'];// 'test-contact' represents our data type
$record=$client->write('test-contact',$data,$metadata);//record contains the newly created value
$record_id=$record->meta->record_id;?>
The above command returns a Record ID:
2c1b256e-8449-423a-955f-e2c508almnop
When a client creates data, its encrypted and signed locally and transmitted
to E 3 DB for storage. Developers don’t have to manage the cryptography, only the form
and structure of their data. Data can be queried using unencrypted metadata.
Parameters
Parameter
Required
Description
recordType
true
A string representing the type of record you are storing
data
true
An object of key value pairs representing data you want to store encrypted
metadata
false
An object of plain text meta about the data. Used to query
e3db.read(recordId:recordId){resultinswitchresult{// The operation was successful, here's the recordcase.success(letrecord):// The record returned contains the same dictionary// supplied to the `RecordData` struct during the writeprint("Record data: \(record.data)")case.failure(leterror):print("An error occurred attempting to read the record: \(error)")}}
<?php$data=['name'=>'Jon Snow','what_he_knows'=>'Nothing',];// 'test-contact' represents our data type
$record=$client->read($recordId);?>
The above command returns JSON structured like this:
Clients can read records by fetching records with their ID.
Clients can read data written by themselves or other clients (with
permission). When reading data, it’s transmitted encrypted to the client and decrypted
with the client’s private key, and its signature is verified.
Parameters
Parameter
Required
Description
recordId
true
The record you want to retrieve from TozStore
Update Data Record
letrecordId='abc'letrecord=awaitclient.write(recordId)record.data.name='Mr. Jon Snow'letnewRecord=await.client.update(record)
original_record=client.read(record_id)original_record.data['name']='Mr. Jon Snow'updated_record=client.update(original_record)print"Record: {0} {1}".format(updated_record.data['name'])
record=client.read(recordId)record.data.name="Mr. Jon Snow"newRecord=client.update(record)printf("Wrote record %s\n",newRecord.data.name)
<?php$newData=['name'=>'Jon Snow','what_he_knows'=>'Something',];// 'test-contact' represents our data type
$record=$client->read($recordId);$record->data=$newData;$updatedRecord=$client->update($record);$updatedRecord->data['name']='Mr. Jon Snow';$updatedRecord=$client->update($updatedRecord);?>
originalRecord,err:=client.Read(context.Background(),recordID)iferr!=nil{//Error handling omitted}originalRecord.Data.name="Mr. Jon Snow"newRecord,err:=client.Update(context.Background(),originalRecord)iferr!=nil{//Error handling omitted}fmt.Println(newRecord.Data["name"])
The update function lets clients easily download, decrypt, verify, modify,
encrypt, sign, and re-upload data in one step. Changes to data are versioned to prevent
potential conflicts between multiple clients updating data simultaneously.
To update a record you must first download the record and update its properties as needed.
You then pass the updated Record object to the update function.
Parameter
Required
Description
record
true
The updated record object
Delete Data Record
conste3db=require('e3db')lettoken='...'letclientName='...'letrecordId='...'//your record id to deleteasyncfunctionmain(){awaite3db.Client.delete(recordId)// ... Run operations with the client's details here}main()
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------require'e3db'# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.config=E3DB::Config.default# Now create a client using that configuration.client=E3DB::Client.new(config)client.delete(record_id)
importcom.tozny.e3db.*;StringstoredCredentials=...;// Read from secure storageClientclient=newClientBuilder().fromConfig(Config.fromJson(storedCredentials)).build();client.delete(recordId)
<?php/**
* Assuming your credentials are stored as defined constants in the
* application, pass them each into the configuration constructor as
* follows:
*/$config=new\Tozny\E3DB\Config(CLIENT_ID,API_KEY_ID,API_SECRET,PUBLIC_KEY,PRIVATE_KEY,API_URL);/**
* Pass the configuration to the default coonection handler, which
* uses Guzzle for requests. If you need a different library for
* requests, subclass `\Tozny\E3DB\Connection` and pass an instance
* of your custom implementation to the client instead.
*/$connection=new\Tozny\E3DB\Connection\GuzzleConnection($config);/**
* Pass both the configuration and connection handler when building
* a new client instance.
*/$client=new\Tozny\E3DB\Client($config,$connection);$client->delete('record_id');?>
QueryParamsparams=newQueryParamsBuilder().setTypes("lyric").setIncludeData(true).setCount(50).build();Clientclient=...;// Get a client instanceclient.query(params,newResultHandler<QueryResponse>(){@Overridepublicvoidhandle(Result<QueryResponse>r){if(!r.isError()){// print list of recordsfor(Recordr:r.asValue().records()){System.out.println("Record ID: "+r.meta().recordId());System.out.println("Song: "+r.data().get("song"));}}}});
// Keep track of queried batchesvarlastRead:Double?// Construct query, filtering to:// - return only 5 records at a time,// - only "UserInfo" type records,// - including records written by others// that have been shared with this clientletq1=QueryParams(count:5,types:["UserInfo"],includeAllWriters:true)e3db.query(params:q1){resultinswitchresult{// The operation was successful, here's the `QueryResponse`,// which has the resulting records and an index for last recordcase.success(letresp):print("Records: \(resp.records)")lastRead=resp.lastcase.failure(leterror):print("An error occurred attempting to query records: \(error)")}}// Query for next batch using `next`letq2=q1.next(after:lastRead!)e3db.query(params:q2){resultin// ...}
Query E3DB records according to a set of selection criteria.
The default behavior is to return all records written by the
current authenticated client.
To restrict the results to a particular type, pass a type or
list of types as the type argument.
To restrict the results to a set of clients, pass a single or
list of client IDs as the writer argument. To list records
written by any client that has shared with the current client,
pass the special string 'all' as the writer argument.
Parameter
Required
Type
Description
data
false
Bool
Flag to include data in records returned
writer
false
String or Array
Records written by a single writer or list of writers
record
false
String or Array
Select single record or list of records
type
false
String or Array
Select records of a type or types
metadata
false
Array
Associative array of plaintext meta to use as filter
pageSize
false
Number
Page size returned by response
Share Data Records
/**
* ---------------------------------------------------------
* Initialization
* ---------------------------------------------------------
*/// Configuration values must be set in an immutable configuration object.// You can use whatever "profiles" or client credentials you want.letconfig=newe3db.Config(process.env.CLIENT_ID,process.env.API_KEY_ID,process.env.API_SECRET,process.env.PUBLIC_KEY,process.env.PRIVATE_KEY,process.env.API_URL,process.env.PUBLIC_SIGN_KEY,process.env.PRIVATE_SIGN_KEY)// Now create a client using that configurationletclient=newe3db.Client(config)/**
* ---------------------------------------------------------
* Simple sharing by record type
* ---------------------------------------------------------
*/// Share all of the records of type 'test-contact' with another client ID:letanotherClientId='db1sdfb9-3fb6-4458-a291-0bc673437dba08b'awaitclient.share('test-contact',anotherClientId)
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------importe3db# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.# Load ~/.tozny/dev/e3db.json profile# conf = e3db.Config.load('dev')# Load default config in ~/.tozny/e3db.jsonconf=e3db.Config.load()# Now create a client using that configuration.client=e3db.Client(conf)# ---------------------------------------------------------# Simple sharing by record type# ---------------------------------------------------------# Share all of the records of type 'People' with another client ID:another_client_id='sd2329-3fb6-4458-a291-0bsdf23a08b'client.share('people',another_client_id)
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------require'e3db'# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.config=E3DB::Config.default# Now create a client using that configuration.client=E3DB::Client.new(config)# ---------------------------------------------------------# Simple sharing by record type# ---------------------------------------------------------# Share all of the records of type 'test-contact' with another client ID:another_client_id='db1744b9-3fb6-4458-a291-sdf29008fj'client.share('test-contact',another_client_id)
Clientclient=...;// Get a client instanceUUIDreaderId=...;// Get the ID of the reader with whom we shareclient.share("lyric",readerId,newResultHandler<Void>(){@Overridepublicvoidhandle(Result<Void>r){if(!r.isError()){// record shared}}});
<?php// Configuration values must be set in an immutable configuration object.
// You can use whatever "profiles" or client credentials you want.
$config=newConfig(\getenv('CLIENT_ID'),\getenv('API_KEY_ID'),\getenv('API_SECRET'),\getenv('PUBLIC_KEY'),\getenv('PRIVATE_KEY'),\getenv('API_URL'));// Now create a client using that configuration and a Guzzle-powered connection
$connection=newGuzzleConnection($config);$client=newClient($config,$connection);/**
* ---------------------------------------------------------
* Simple sharing by record type
* ---------------------------------------------------------
*/// Share all of the records of type 'test-contact' with another client ID:
$another_client_id='db1744b9-3fb6-4458-a291-sdf2231';$client->share('test-contact',$another_client_id);?>
import(..."github.com/tozny/e3db-go/v2"...)// Share all "feedback" records with that user ID.client,err:=e3db.GetDefaultClient()chk(err)err=client.Share(context.Background(),"feedback",feedbackClient.ClientID)chk(err)
// Get the recipient client ID externallyletotherClient:UUID=???// Share records of type "UserInfo" with another cliente3db.share(type:"UserInfo",readerId:otherClient){resultinguardcase.success=resultelse{returnprint("An error occurred attempting to grant access to records: \(result.error)")}// Sharing was successful!}
These functions change access control and add or remove an
encryption key so that a new party can read or write data. It can be run by any client with
permission to this data. It does not require downloading or re-encrypting the data, since
TozStore utilizes a key wrapping approach for efficiency. As a result, a very large amount of
data can be shared with multiple parties using a fast, constant-time operation.
Parameter
Required
Type
Description
record_type
true
String
The 'type' of records that should be shared with a client
client_id
true
String
The recipient who will get access to the records
Unshare Data Records
/**
* ---------------------------------------------------------
* Initialization
* ---------------------------------------------------------
*/// Configuration values must be set in an immutable configuration object.// You can use whatever "profiles" or client credentials you want.letconfig=newe3db.Config(process.env.CLIENT_ID,process.env.API_KEY_ID,process.env.API_SECRET,process.env.PUBLIC_KEY,process.env.PRIVATE_KEY,process.env.API_URL,process.env.PUBLIC_SIGN_KEY,process.env.PRIVATE_SIGN_KEY)// Now create a client using that configurationletclient=newe3db.Client(config)/**
* ---------------------------------------------------------
* Simple sharing by record type
* ---------------------------------------------------------
*/// Revoke all of the records of type 'test-contact' with another client ID:letanotherClientId='db1sdfb9-3fb6-4458-a291-0bc673437dba08b'awaitclient.revoke('test-contact',anotherClientId)
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------importe3db# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.# Load ~/.tozny/dev/e3db.json profile# conf = e3db.Config.load('dev')# Load default config in ~/.tozny/e3db.jsonconf=e3db.Config.load()# Now create a client using that configuration.client=e3db.Client(conf)# ---------------------------------------------------------# Simple sharing by record type# ---------------------------------------------------------# Revoke all of the records of type 'People' with another client ID:another_client_id='sd2329-3fb6-4458-a291-0bsdf23a08b'client.revoke('people',another_client_id)
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------require'e3db'# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.config=E3DB::Config.default# Now create a client using that configuration.client=E3DB::Client.new(config)# ---------------------------------------------------------# Simple sharing by record type# ---------------------------------------------------------# Revoke all of the records of type 'test-contact' with another client ID:another_client_id='db1744b9-3fb6-4458-a291-sdf29008fj'client.revoke('test-contact',another_client_id)
Clientclient=...;// Get a client instanceUUIDreaderId=...;// Get the ID of the reader with whom we shareclient.revoke("lyric",readerId,newResultHandler<Void>(){@Overridepublicvoidhandle(Result<Void>r){if(!r.isError()){// record shared}}});
<?php// Configuration values must be set in an immutable configuration object.
// You can use whatever "profiles" or client credentials you want.
$config=newConfig(\getenv('CLIENT_ID'),\getenv('API_KEY_ID'),\getenv('API_SECRET'),\getenv('PUBLIC_KEY'),\getenv('PRIVATE_KEY'),\getenv('API_URL'));// Now create a client using that configuration and a Guzzle-powered connection
$connection=newGuzzleConnection($config);$client=newClient($config,$connection);/**
* ---------------------------------------------------------
* Simple sharing by record type
* ---------------------------------------------------------
*/// Revoke all of the records of type 'test-contact' with another client ID:
$another_client_id='db1744b9-3fb6-4458-a291-sdf2231';$client->revoke('test-contact',$another_client_id);?>
import(..."github.com/tozny/e3db-go/v2"...)// Share all "feedback" records with that user ID.client,err:=e3db.GetDefaultClient()chk(err)err=client.Share(context.Background(),"feedback",feedbackClient.ClientID)chk(err)
// Get the recipient client ID externallyletotherClient:UUID=???// Remove access to "UserInfo" records from the given cliente3db.revoke(type:"UserInfo",readerId:otherClient){resultinguardcase.success=resultelse{returnprint("An error occurred attempting to revoke access to records: \(result.error)")}// Revoking was successful!}
These functions change access control and add or remove an
encryption key so that a new party can read or write data. It can be run by any client with
permission to this data. It does not require downloading or re-encrypting the data, since
TozStore utilizes a key wrapping approach for efficiency. As a result, a very large amount of
data can be unshared with multiple parties using a fast, constant-time operation.
Parameter
Required
Type
Description
record_type
true
String
The 'type' of records that should be shared with a client
client_id
true
String
The recipient who will get access to the records
Upload File
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------importe3db# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.# Load ~/.tozny/dev/e3db.json profile# conf = e3db.Config.load('dev')# Load default config in ~/.tozny/e3db.jsonconf=e3db.Config.load()# Now create a client using that configuration.client=e3db.Client(conf)record_type="test_large_files"# Plaintext file that we want to encrypt and send to E3DB for storageplaintext_filename="mylargefile.txt"# Encrypt and write the file to the E3DB Serverencrypted_file_meta=client.write_file(record_type,plaintext_filename)
...FilereadmeFile=newFile("README.md");StringrecordType="docs";client.writeFile(recordType,readmeFile,null,newResultHandler<RecordMeta>(){@Overridepublicvoidhandle(Result<RecordMeta>r){if(!r.isError()){// file written successfullyRecordMetarecord=r.asValue();// Log or print record ID, e.g.:System.out.println("Record ID: "+record.meta().recordId());}else{// an error occurredthrownewRuntimeException(r.asError().other());}}});
letdata=Data("Hello there".utf8)letsrc=FileManager.default.temporaryDirectory.appendingPathComponent("source-file").appendingPathExtension("txt")guardFileManager.default.createFile(atPath:src.path,contents:data)else{returnprint("Could not create file")}varrecordId:UUID?e3db.writeFile(type:type,fileUrl:src){resultinswitchresult{// The operation was successful, here's the `Meta` instance.case.success(letmeta):recordId=meta.recordIdcase.failure(leterror):print("An error occurred attempting to write file: \(error)")}}
TozStore supports the storage of large encrypted files, using a similar interface for reading and writing records. The SDK will handle encrypting and uploading the file. Similarly, it will download and decrypt files as well. Note that file upload and download is currently in development and not supported in all of our SDK's. If you are actively looking for support in a specific library please contact us at support@tozny.com.
Download File
# ---------------------------------------------------------# Initialization# ---------------------------------------------------------importe3db# Configuration files live in ~/.tozny and you can have several# different "profiles" like *dev* and *production*.# Load ~/.tozny/dev/e3db.json profile# conf = e3db.Config.load('dev')# Load default config in ~/.tozny/e3db.jsonconf=e3db.Config.load()# Now create a client using that configuration.client=e3db.Client(conf)record_type="test_large_files"# Plaintext file that we want to encrypt and send to E3DB for storageplaintext_filename="mylargefile.txt"# Encrypt and write the file to the E3DB Serverread_file_info=client.read_file(encrypted_file_meta.record_id,plaintext_filename)
...UUIDreadmeRecordId=...;// Record ID of file written previouslyFiledestinationFile=newFile("README-2.md");client.readFile(readmeRecordId,destinationFile,newResultHandler<RecordMeta>(){@Overridepublicvoidhandle(Result<RecordMeta>r){if(r.isError()){// an error occurredthrownewRuntimeException(r.asError().other());}// `README-2.md` will contain contents of file, which we write to standard out.try{System.out.println("README-2.md: "+newString(Files.readAllBytes(destinationFile),"UTF-8"));}catch(IOExceptione){// Handle error where file isn't found ...}}});
letdest=FileManager.default.temporaryDirectory.appendingPathComponent("destination-file").appendingPathExtension("txt")guardFileManager.default.createFile(atPath:dest.path,contents:nil)else{returnprint("Could not create file")}e3db.readFile(recordId:recordId,destination:dest){resultinswitchresult{case.success:print("File was downloaded, decrypted, and saved to \(dest.path)!")case.failure(leterror):print("An error occurred attempting to read file: \(error)")}}
TozStore supports the storage of large encrypted files, using a similar interface for reading and writing records. The SDK will handle encrypting and uploading the file. Similarly, it will download and decrypt files as well. Note that file upload and download is currently in development and not supported in all of our SDK's. If you are actively looking for support in a specific library please contact us at support@tozny.com.
Authorize User (Beta)
Share on behalf of (Beta)
Errors
The Kittn API uses the following error codes:
Error Code
Meaning
400
Bad Request -- Your request is invalid.
401
Unauthorized -- Your API key is wrong.
403
Forbidden -- The kitten requested is hidden for administrators only.
404
Not Found -- The specified kitten could not be found.
405
Method Not Allowed -- You tried to access a kitten with an invalid method.
406
Not Acceptable -- You requested a format that isn't json.
410
Gone -- The kitten requested has been removed from our servers.
418
I'm a teapot.
429
Too Many Requests -- You're requesting too many kittens! Slow down!
500
Internal Server Error -- We had a problem with our server. Try again later.
503
Service Unavailable -- We're temporarily offline for maintenance. Please try again later.