Skip to content
Simon Kelly edited this page Feb 5, 2015 · 2 revisions

Background

In order to both encrypt data on local devices, but also permit for a remote server to enable decryption in cases where user credentials are lost, CommCare ODK supports retrieving encryption keys from a remote server, rather than generating them as tied directly to user credentials. This API specifies how a server and client should generate and make these keys available.

Request and Response

A remote client should begin the process by performing a GET to an authenticated url provided by the server. The server should receive and authenticate that request as specified by the OpenRosa Request API.

The URI should accept a parameter last_issued, which (if provided) specifies that the client needs keys as of a certain period. If this flag is present, the server should provide both the key which was used in the last_issued period as well as the current key. This is important if, say, a user's remote password is changed after a key auth change, and the user needs to be able to retrieve offline data which was encrypted by an old key before transferring storage to a new DB.

The client should ensure that the GET is performed across an SSL channel, and reject redirection.

Upon successfully authenticating the remote user, the server should provide a response in the following payload format to the OR envelope:

<auth_keys domain="" issued="">          <!-- Exactly one. The block of auth key records.-->
                                         <!-- @domain: Exactly one. The client should only accept keys from domains that match the request -->
                                         <!-- @issued: Exactly one. An ISO8601 timestamp from the server which denotes the date and time that the key requests were processed. This is the value that should be provided as the `last_issued` parameter to future requests. -->
     <key_record valid="" expires="">    <!-- At Least One: A record for a key that the authenticating user has access to -->
                                         <!-- @valid:  Exactly one - The first date on which this key should be trusted -->
                                         <!-- @expires:  At Most one - A date on which the key was supplanted. If expires is not present, the phone will assume that it is currently valid -->
         <uuid title=""/>                         <!-- Exactly One: A unique ID for this key. The same key record can be issued to multiple users (for superuser functions, etc). -->
                                                  <!-- @title: At most one. An optional description of the sandbox, to allow differentiating between different datastores -->
         <key type=""/>                  <!-- Exactly One: The key content. Should be Base64 Encoded -->
                                         <!-- @type: Exactly one. The type of key being shared. Currently only AES256 is supported as either (AES, AES256) -->
     </key_record>
</auth_keys>

Workflow

Upon a first request for authentication keys, the server should generate the necessary keys (AES only at this point) and provide them to the client. Subsequent requests should return the same key until the date specified in the "expires" date. After this point the server can re-issue the same key, or issue a new key, with updated dates of trust.

The server may retract a key at any point. If it does so it should create a new key, and serve it with the appropriate valid and expires timestamps. It should also still be prepared to serve up the old key in addition for any phones requesting authentication keys which were valid during that period.

The client should always perform a new key request if it is unable to authenticate a user, since the users password may have changed remotely. If that is the case, the server will provide all appropriate keys for the user, and once they are received, the client can expunge any saved keys encrypted under the old password.

After receiving keys the client should encrypt those keys against the same credentials used to request them. If a user's credentials are changed remotely, the keys used to encrypt actual data can be downloaded and encrypted against the new credentials, and the old saved keys can be removed.

Data Encryption Processes

Storage Separation

Devices supporting encryption should maintain an independent encrypted database for each different user, based on the uuid provided. Currently, a user can assume that the uuid located in the key authentication response is the correct destination for OTA requests which authenticate with that user.

In special cases, users may receive UUID's for multiple users in their key requests (superusers who need to view data on the phone for users they have authority for, for instance). The app should only maintain one storage set for individual uuid. If a user logs in and has access to auth keys for another, they should be able to access that private sandbox.

Key Handoff

When a device requests auth keys from the server it may receive a new authentication key in addition to the one that was used to last encrypt data (which should have properly set dates for validity and expiration). Upon detecting a key change, the device should immediately cease writing data to any existing databases encrypted by the old, expired, key. The client should re-encrypt (either in-place if possibly, or by copying to a new encrypted location) the data to new storage and remove the old data after doing so.