Mistake on this page?
Report an issue in GitHub or email us

DeviceKey

DeviceKey class hierarchy

DeviceKey is a mechanism that implements key derivation from a root of trust key. The DeviceKey mechanism generates symmetric keys that security features need. You can use these keys for encryption, authentication and more. The DeviceKey API allows key derivation without exposing the actual root of trust, to reduce the possibility of accidental exposure of the root of trust outside the device.

We have implemented DeviceKey according to NIST SP 800-108, section "KDF in Counter Mode", with AES-CMAC as the pseudorandom function.

Root of Trust

The root of trust key, which DeviceKey uses to derive additional keys, is generated using the hardware random generator if it exists, or using a key injected to the device in the production process.

The characteristics required by this root of trust are:

  • It must be unique per device.
  • It must be difficult to guess.
  • It must be at least 128 bits.
  • It must be kept secret.

The DeviceKey feature keeps the root of trust key in internal storage, using the KVStore component. Internal storage provides protection from external physical attacks to the device.

The root of trust must be created before its first use. Otherwise, the key derivation API fails.

Key derivation API

generate_derived_key: This API generates a new key based on an array of data (salt the caller provides. A single salt value always generates the same key, so if you need a new key, you must use a new salt value. The salt can have any value - array, string and so on.

The generated keys can be 128b or 256b in length.

Root of Trust generation API

DeviceKey class needs root of trust ready to use before the derivation API's first call. There are two options to achieve this:

  • Create a device key using a built-in random number generator.
  • Manually fill the device key data array.

Both cases requires injecting this key data to the KVStore reserved area.

When DEVICE_TRNG is defined, the device supports a random number generator, and you may generate the key by calling generate_root_of_trust(). The call succeeds only if the key does not already exist. You can't change the existing key.

int status = DeviceKey::get_instance().generate_root_of_trust();
if(status == DEVICEKEY_SUCCESS) {
    //success
} else {
   //error
}

If DEVICE_TRNG is not defined, the key buffer must be filled manually by calling device_inject_root_of_trust(). The example below shows an injection of a dummy key:

uint32_t key[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
memcpy(key, "12345678123456781234567812345678", DEVICE_KEY_32BYTE);
int size = DEVICE_KEY_32BYTE;

int status = DeviceKey::get_instance().device_inject_root_of_trust(key, size);
if(status == DEVICEKEY_SUCCESS) {
    //success
} else {
    //error
}

Using DeviceKey

DeviceKey is a singleton class, meaning the system can have only a single instance of it.

To instantiate DeviceKey, call its get_instance member function:

    DeviceKey &deviceKey = DeviceKey::get_instance();

Testing DeviceKey

Run the DeviceKey functionality test with the mbed:

    mbed test -n features-device_key-tests-device_key-functionality

DeviceKey API class reference

Public Member Functions
int generate_derived_key (const unsigned char *isalt, size_t isalt_size, unsigned char *output, uint16_t ikey_type)
 Derive a new key based on the salt string. More...
int device_inject_root_of_trust (uint32_t *value, size_t isize)
 Set a device key into the KVStore. More...
int generate_root_of_trust (size_t key_size=16)
 Generate Root of Trust. More...
Static Public Member Functions
static DeviceKeyget_instance ()
 As a singleton, return the single instance of the class. More...

DeviceKey example

/*
* Copyright (c) 2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "mbed.h"
#include "DeviceKey.h"

// Print a unsigned char buffer in hex format
void print_buffer(unsigned char *buf, size_t size)
{
    for (size_t i = 0; i < size; i++) {
        printf("%02X", buf[i]);
    }
}

// Injection of a dummy key when there is no TRNG
int inject_rot_key()
{
    uint32_t key[DEVICE_KEY_16BYTE / sizeof(uint32_t)];

    memset(key, 0, DEVICE_KEY_16BYTE);
    memcpy(key, "ABCDEF1234567890", DEVICE_KEY_16BYTE);
    int size = DEVICE_KEY_16BYTE;
    DeviceKey &devkey = DeviceKey::get_instance();
    return devkey.device_inject_root_of_trust(key, size);
}

// Entry point for the example
int main()
{
    unsigned char derive_key1 [DEVICE_KEY_32BYTE];
    unsigned char salt1[] = "SALT1 ----- SALT1 ------ SALT1";
    int ret = DEVICEKEY_SUCCESS;

    printf("\nMbed OS DeviceKey example \n");

    // DeviceKey is a singleton
    DeviceKey &devkey = DeviceKey::get_instance();

#if !defined(DEVICE_TRNG)

    // If TRNG is not available it is a must to inject the ROT before the first call to derive key method.
    printf("No TRNG support for this device. injecting ROT.\n");
    ret = inject_rot_key();
    if (DEVICEKEY_SUCCESS != ret && DEVICEKEY_ALREADY_EXIST != ret) {
        printf("Error, injection of ROT key has failed with status %d\n", ret);
        return -1;
    }

    if (DEVICEKEY_ALREADY_EXIST == ret) {
        printf("ROT Key already exists in the persistent memory.\n", ret);
    } else {
        printf("ROT Key injected and stored in persistent memory.\n", ret);
    }

#endif

    printf("Salt for key derivation: %s \n", salt1);

    // 16 byte key derivation.
    ret = devkey.generate_derived_key(salt1, sizeof(salt1), derive_key1, DEVICE_KEY_16BYTE);
    if (DEVICEKEY_SUCCESS != ret) {
        printf("Error, derive key failed with error code %d \n", ret);
        return -1;
    }

    printf("16-byte Derived key is: ");
    print_buffer(derive_key1, DEVICE_KEY_16BYTE);
    printf("\n");

    printf("Mbed OS DeviceKey example done.\n");

    return 0;
}
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.