Crypt Vault Storage Developer Notes

Copyright 2015, Bryan Nielsen <bnielsen1965@gmail.com>

Version 1.0

Table of Contents

Table of Contents

Implementation

PHP

Initialization

Namespace

Exceptions

Saving Records

Reading Records

Remote API

Appendix

Database Tables

User Flags

User Flag Values

Key Flags

Key Flag Values

Implementation

To use the Crypt Vault Storage on a web site or other platform requires a minor level of development to implement the Vault into a web site or application. The implementation can be through the PHP library or the REST API.

In addition to these developer notes you will find detailed library and API documentation for methods in both the PHP Library and the REST API.

PHP

The backend for the Crypt Vault Storage application was written in PHP so the primary method of implementation is to use the PHP libraries that are provided with the software.

The library utilizes namespaces, class files, and exceptions that should ease implementation in any existing PHP based application. If your project does not use namespaces, classes, or exceptions you can still use the library in a procedural way by following the examples below.

Initialization

The Crypt Vault Storage code provides an initialization script, cvs/init.php, that loads the application configuration and a class autoloader. If your application includes this initialization script then you can call the library classes and methods without the need to figure out which files to include or which constants to set.

Namespace

The classes for the PHP library all exist within the namespace \CryptVault\Storage to ensure they do not conflict with any other library that may be in use. If you are not using namespaces in your project or you are unfamiliar with namespaces then fear not. In most cases you only need to worry about the namespace when you create an instance of a class object. After instantiation you can call the class methods without concern for the namespace.

Note in the following example where an instance of the StorageProcessor is created. The initialization script is included to provide the configuration settings and the class autoloader. The StorageProcessor instance is then created with the namespace prefixed to the class name.

...

    // initialize the library

    include 'cvs/init.php';

    // create instance of the storage processor

    $storage = new \CryptVault\Storage\StorageProcessor();

...

After the instance of the StorageProcessor is created you can use the instance to call the methods in the processor class. You will see examples of this in the follow steps.

Exceptions

While the Crypt Vault Storage PHP Library is designed to work with or without exceptions the default configuration is to use exceptions and this is recommended. Wrap your code with a try / catch statement when you are using the library methods and you will be able to catch meaningful error messages when failures occur.

Note in the following example how the saveRecord() method call is wrapped in a try statement. If the save succeeds then the catch statement is not executed. If the save process fails it will throw an Exception resulting in the catch statement executing andcopying the message from the exception into the error variable.

try {

  // save as a new record

  $recordId = $storage->saveRecord('New Subscriptions', $description, $content);

  $success = true;

}

catch ( \Exception $ex) {

  // save failed

  $success = false;

  $error = $ex->getMessage();

}

Saving Records

Every implementation of the Crypt Vault Storage will require saving of records. While reading the records can be accomplished through the administration page the process of saving will require an action from the target application that is collecting the data to be saved. To save a new record in the database you will need the name of a key to use for encryption, a brief description string for the record, and the contents that will be encrypted.

The name of the key is from the administration page when the key was created while the description and contents are defined in your web site code that processes the form submission.

As an example assume we have a customer form on a web site that collects a customer name and email address for a subscription request. The email address of the customer must be kept confidential so we will encrypt this content before it is saved. And we have created an encryption key in the administration panel named New Subscriptions that will be used with this form.

<form method="POST" action="subscribe.php">

  <h1>Subscribe to our newsletter</h1>

  <small>(Your email address will be kept confidential)</small><br>

  <label>Full Name</label> <input type="text" name="client_name"><br>

  <label>Email</label> <input type="text" name="client_email"><br>

  <button type="submit">Subscribe</button>

</form>

When this form is posted to the PHP script the contents can be stored in the Crypt Vault in a few simple steps:

  1. Process the form data into a description variable and a content variable. The content will be encrypted while the description is plain text in the database.
  2. Include the init.php script from the Crypt Vault to initialize the library.
  3. Create an instance of the StorageProcessor class.
  4. Save the record using the name of the key, the description and the content generated from the form.
  1. Handle success or
  2. Handle any exceptions.

The code for this example may look something like the following…

<?php

// process the form submission when post parameters are set

if ( isset($_POST['client_name']) && isset($_POST['client_email']) ) {

  try {

    // Step 1, prepare the form data

    $description = 'New Subscription From: ' . $_POST['client_name'];

    $content = 'Client: ' . $_POST['client_name'] . "\n" . 'Email: ' . $_POST['client_email'] . "\n";

    // Step 2, initialize the library

    include 'cvs/init.php';

    // Step 3, create instance of the storage processor

    $storage = new \CryptVault\Storage\StorageProcessor();

    // Step 4, save as a new record

    $recordId = $storage->saveRecord('New Subscriptions', $description, $content);

    // Step 5a, record successfully saved

    $saveSuccess = true;

    $message = 'Thank you for your subscription request.(' . $recordId . ')';

  }

  catch ( \Exception $e ) {

    // Step 5b, exception based failure, details are in the exception message

    $saveSuccess = false;

    $message = 'Failed to save the request. ' . $e->getMessage();

  }

 

  // display message based on success status

  if ( $saveSuccess ) {

      echo '<div class="message">' . $message . '</div>';

  }

  else {

      echo '<div class="error">' . $message . '</div>';

  }

}

?>

Reading Records

While the administration page provides access to read functions that will decrypt the records it is also possible to use the PHP library to read encrypted records as well.

Using the previous example as a starting point, it is possible to read the encrypted email records from the system using a similar set of steps and providing the id of the record in the system and the passphrase for the private key. In this case we will not show HTML for the example but it would need inputs to select a record id from the database and enter the passphrase that would enable the private key associated with the record.

The steps to process the request would be something like the following...

  1. Include the init.php script from the Crypt Vault to initialize the library.
  2. Create an instance of the StorageProcessor class.
  3. Read the record from the system using the record id and passphrase in the request.
  1. Handle success or
  2. Handle exception.

Again the code for such an example may look like the following...

<?php

// process the form submission when post parameters are set

if ( isset($_POST['recordid']) ) {

  try {

    // Step 1, initialize the library

    include 'cvs/init.php';

    // Step 2, create instance of the storage processor

    $storage = new \CryptVault\Storage\StorageProcessor();

    // Step 3, read the record from the vault

    $record = $storage->readRecord($_POST['recordid'], $_POST['passphrase']);

   

    // Step 4a, record successfully read

    $readSuccess = true;

    $message = 'Read success.<br>' .

      'Description: ' . $record['description'] . '<br>' .

      'Content: ' . $record['content'] . '<br>';

  }

  catch ( \Exception $e ) {

    // Step 4b, exception based failure, details are in the exception message

    $readSuccess = false;

    $message = 'Read failed. ' . $e->getMessage();

  }

 

  // display message based on success status

  if ( $readSuccess ) {

      echo '<div class="message">' . $message . '</div>';

  }

  else {

      echo '<div class="error">' . $message . '</div>';

  }

}

?>

PHP Examples

Some basic implementation examples are provided in the documentation examples folder that demonstrate the use of the PHP Library. The examples will show how to process your forms within a try / catch statement to utilize exceptions for error handling and they show how to use the \CryptVault\Storage namespace when creating instances of the StorageProcessor.

The first example demonstrates how to use the PHP Library to query a list of key names from the database and how to save content in the Crypt Vault. When records are saved in the database using the example you should then use the administration page to view the saved records.

In the second example the PHP Library is used to save a record where the encrypted content is a JSON formatted data object. Again these records can be viewed in the administration page. But the example goes further and demonstrates how to read the records from the Vault and restore the values from the JSON data.

Remote API

In some cases a project may not be developed using PHP and the standard Crypt Vault Storage PHP library cannot be used. It is still possible to integrate the vault into the project by using the web based remote API.

NOTE: Saving records using the remote API is normally disabled on each key. On the Manage Keys tab of the administration page you can toggle the Remote Record Save option on each key to allow saving of records using a key through the remote API.

The remote API uses JSON messages in the body of HTTP POST requests. Each request must contain at a minimum the API method to execute and each method may require additional parameters. The following example is a raw HTTP POST to a Crypt Vault Storage installation with a request to save a new record…

POST /cryptvaultstorage/cvs/api.php HTTP/1.1

Host: getwebscripts.com

Content-Type: application/json

Cache-Control: no-cache

{

    "method": "saveRecord",

    "keyName": "New Subscriptions",

    "description": "New Subscription From: Bob Toad",

    "data": "Client: Bob Toad\nEmail: bobt@bobtoad.org"

}

NOTE: The saveRecord method is the simplest request made through the API. Many of the methods will require additional parameters and in some cases may require pre-authentication, a session cookie, and a GUID. See the Remote API documentation for more details.

Assuming the saveRecord request is successful the response may look something like the following…

HTTP/1.1 200 OK

Cache-Control: no-cache, must-revalidate
Connection: close
Content-Length: 72
Content-Type: application/json
Date: Wed, 07 Oct 2015 02:45:46 GMT
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Pragma: no-cache
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.3

{

  "id": "fea109f5-ab87-4bf8-8d31-72cd711d994e",

  "success": true,

  "errors": []

}

With this remote API syntax in mind, and assuming the remote record save is enabled on the Crypt Vault Storage key we wish to use, the following is an example of a python script that is sending a saveRecord request to the server running the Crypt Vault Storage application…

import urllib2
import json

data = {
       
"method": "saveRecord",
       
"keyName": "New Subscriptions",
       
"description": "New Subscription From: Bob Toad",
       
"data": "Client: Bob Toad\nEmail: bobt@bobtoad.org"
}

request = urllib2.Request('https://getwebscripts.com/cryptvaultstorage/cvs/api.php')
request.add_header('Content-Type', 'application/json')

response = urllib2.urlopen(request, json.dumps(data))
data = json.load(response)
print
"ID: %s" % data['id']

The remote API provides a full set of methods to utilize the vault in a variety of applications. As an example, the administration page used to maintain the vault uses the remote API for all method requests. Check the remote API documentation included with the Crypt Vault Storage package for the details on all the available methods.

Appendix

Database Tables

The database includes a set of four tables. One table to hold the encryption keys that are used to encrypt and decrypt records. A table to hold the encrypted records. A table to hold the details about user accounts for the administration page. And a table to hold log events for the administration page.

Table: cvs_keys

Field

Type

Description

key_name

varchar(255)

The name of the key. (PK)

key_description

text

A description of the key.

key_certificate

text

The PEM encoded self signed certificate for the key.

key_private_key

text

The PEM encoded private key. NOTE: This field will be empty if the "save private key" option was not selected.

key_flags

integer

Binary flags for key settings.

Table: cvs_records

Field

Type

Description

record_id

varchar(36)

The unique id for the record. (PK)

record_description

text

A description of the record.

key_name

varchar(255)

The name of the key used for encryption. (FK)

record

text

The encrypted record content.

record_created

integer

Unix epoch timestamp for the creation date.

record_last_read

integer

Unix epoch timestamp for the last time the record was read in the administration page.

Table: cvs_users

Field

Type

Description

user_username

varchar(255)

The account username. (PK)

user_password

varchar(512)

The hashed account password.

user_flags

integer

Binary flags for account settings.

user_key_safe

text

The encrypted keyring from the user's session.

Table: cvs_log

Field

Type

Description

log_id

varchar(50)

Unique id for the log event. (PK)

log_timestamp

integer

Unix epoch timestamp for the log event.

user_username

varchar(255)

The account username associated with this event. (FK)

log_event

text

The event description.

User Flags

The user flags are based on binary bit values that make it easy to check for a specific user flag using bitwise operators. As an example, if the variable flags contains a users's flag settings and you want to check the user's flags to see if the user is an Administrator you can use the statement (flags & 4) and this will return a value of 0 if it is not an Administrator and 4 if it is an Administrator.

User Flag Values

Constant

Value

USER_CLERK

1

USER_MANAGER

2

USER_ADMIN

4

USER_ASSOCIATE

8

Key Flags

The key flags are based on binary bit values which makes it possible to use bitwise operators to check whether a flag bit is set or clear.

Key Flag Values

Constant

Value

KEY_SAVE_PKEY

1

KEY_RECORDS_EXPIRE

2

KEY_REMOTE

4

KEY_ENABLED

8