Skip to main content

Crypt Service

The crypt service service implements a key/value store for all other services to store and retrieve encrypted keys or data. To encrypt data the crypt service generates keys that are encrypted using the hardware secure element or a user supplied passphrase.

Store DB

The crypt service is implemented as a sqlite database (the path is set by the config.ini parameter cryptDbPath), which contains two tables: secrets and store.

The schema for the secrets table is as follows:

CREATE TABLE secrets (id TEXT NOT NULL, value TEXT, salt TEXT, iv TEXT, PRIMARY KEY (id));

where id is the ID of the generated key, value is the value of the key, iv the initial value (IV) used to encrypt and decrypt the key and salt is the salt parameter.

An example of the secrets table row is given below:

IDVALUESALTIV
masterLbknNO6o+s+u1b4wg9eGzQjHCanicVtDlDJBWZ0u4VaV25oIUCt1b5bthzLwhQO0Z95m5G/+jgb3ga0dufa//whka2MmSUkJUJBf7TQMYnug
resta2UiZR/DLYb3hX61ZQ7Mb/vdVVIchJzkuNnoIhLDCHXe9453IlWjOfOymodUZIsqRLdlnafYj7279lne7A5UoAlgTKNxgxbeCxg4VySS/7vw
94:b9:7e:15:47:95lPVf5wqMnb9+8Q8Cik5oetOI9MfA6qjPm1tKTR3WGPWgZYtaybEeDKWGX/x4EUUBgFvI5tfeHANOafJlFsHXpgmH2yeX/FEvJd1ilg25Zwcg

The value, salt and iv are base64 encoded.

When a user or service wants to store a key/value, they will need to provide an ID for the key that will be used to encrypt/decrypt the user's value. If such an ID does not exist in the secrets table, the service will randomly generate one and encrypt it using the hardware secure element or the user supplied passphrase. When the user provides the passphrase, the service will generate an encryption key using the salt and Password-Based Key Derivation Function 2 (PBKDF2). The derived key is not stored on the device. If the user instead uses the hardware secure element, the key derivation, encryption and decryption is done in secure memory.

Each key/value pair is stored in the store table with the following schema:

CREATE TABLE store (key TEXT NOT NULL, value TEXT, id TEXT, iv TEXT, PRIMARY KEY (key));

where key is the key for the value, value is the value to be stored, id is the key id used to encrypt/decrypt the value and iv is the IV used to encrypt/decrypt the value.

An example of the store table rows is given below.

KEYVALUEIDIV
7815f8ce-57b8-49c8-9121-5b98986cbccdGCM564Ugwyh0bW3f4JuFkwmasterJa0pz9cdH7p3Q+BBP2MIrw
db07c38a-2842-4f45-9672-74d57ec99e6323cHWe6r033czxopWsv6NgmasterFU7hUGGbifro65cv0u0OwQ
1a35f54d-c5f9-4072-85b0-4b40f8fb4a14LR3iRw6SrN/pWKSTJvNtrAmasterx9hFentG2Q6iynHXCk2ktA
831ffbb1-2e79-422a-bdad-e9e96a56d568CdoxKK4PbDvWD9cOdRcTXQmasterRHR1AGsjpWVHDR4VN2PiLA

The value and iv are base64 encoded.

Each row of the store DB contains the id of the key that was used to encrypt/decrypt the value. The encryption algorithm used is AES 256 CBC.

Secure element

In order to enable the use of secure element one needs to set the USE_CRYPTO_SERVICE and USE_*_HSM options in CMake when compiling edgesec, which corresponds to a particular implementation of the secure element API.

In order to add an aditional implementation of a secure hardware element, one can use the generic driver interface generec_hsm_drive.h as a template. The generic driver interface defines the context:

struct hsm_context {
void *hsm_ctx;
};

that is passed to the init and encrypt/decrypt functions as follows:

struct hsm_context *init_hsm(void);
int close_hsm(struct hsm_context *context);
int generate_hsm_key(struct hsm_context *context, uint8_t *key, size_t key_size);
int encrypt_hsm_blob(struct hsm_context *context, uint8_t *in, size_t in_size, uint8_t **out, size_t *out_size);
int decrypt_hsm_blob(struct hsm_context *context, uint8_t *in, size_t in_size, uint8_t **out, size_t *out_size);

The developer will have to provide a tailored implementation for the above functions in order to use a particular hardware secure element. An example is provided in zymkey4_driver.h.