Chip ID

Requirements

Enable quiddikey driver in your application.

Description

This example shows how to make a chip identification procedure using GAP9’s puf(quiddikey).

How to run

cmake -B build
cmake --build build --target menuconfig # Select your board in the menu
cmake --build build --target run

Or use the gap command:

gap init
gap menuconfig
gap run

Results

You should have an output looking like this (order may vary):

Chip id example
Starting enroll (first boot) procedure
Starting id verification procedure
ID verification procedure done
/* 
 * Copyright (C) 2023 ETH Zurich, University of Bologna and GreenWaves Technologies
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD license.  See the LICENSE file for details.
 *
 * Author: Antoine Faravelon, GWT (antoine.faravelon@greenwaves-technologies.com)
 */

#include "pmsis.h"

// NOTE1: saved AC and KC, sizes are for worst case, follow documentation to determine
// proper size for your use case
// NOTE2: In real product, this should be in eMRAM
uint8_t saved_activation_code[2048];
uint8_t saved_key_code[2048];
uint8_t saved_key[2048];

// wrap key into key_code
int wrap_key(pi_device_t *qk, uint16_t key_length, uint8_t *key, uint8_t *key_code)
{
    pi_quiddikey_context_t context = {0, 0, 0, 0, 0};

    // dor ok, so ok, no special context
    pi_quiddikey_set_key_context(&context, uQUIDDIKEY_Started, key_length, 1, 1, 0);
    return pi_quiddikey_wrap(qk, (uint32_t *)key, (uint32_t *)key_code, &context);
}

int unwrap_key(pi_device_t *qk, uint16_t key_length, uint8_t *key, uint8_t *key_code)
{
    pi_quiddikey_context_t context = {0, 0, 0, 0, 0};

    // dor ok, so ok, no special context
    pi_quiddikey_set_key_context(&context, uQUIDDIKEY_Started, key_length, 1, 1, 0);
    return pi_quiddikey_unwrap(qk, (uint32_t *)key_code, (uint32_t *)key, context.key_length);
}

void chip_id_enroll(void)
{
    printf("Starting enroll (first boot) procedure\n");

    int error = 0;
    pi_device_t qk_device = {0};
    pi_device_t *qk = &qk_device;
    pi_quiddikey_conf_t conf = {0};
    conf.id = 0;
    conf.enroll = 1;
    conf.ac = saved_activation_code;
    qk_device.config = &conf;
    error = pi_quiddikey_open(qk);
    if(error)
    {
        printf("quiddikey enroll failed\n");
        exit(-1);
    }
    pi_quiddikey_close(&qk_device);
    // reopen the quiddikey in "normal" mode, failing to do so will make
    // wrapped key unwrappable in normal operation mode
    conf.enroll = 0;
    error = pi_quiddikey_open(&qk_device);
    // generate a random key
    uint32_t data_length = 1024; // 1024 bits
    pi_quiddikey_context_t context = {data_length, 0, 0, 0, 0};

    error = pi_quiddikey_generate_random(qk, (uint32_t *)saved_key,
            &context);
    if(error)
    {
        printf("Error: could'nt generate random number\n");
        exit(-1);
    }
    // wrap random key
    error = wrap_key(qk, data_length, saved_key, saved_key_code);
    if(error)
    {
        printf("couldn't wrap key\n");
        exit(-1);
    }
    pi_quiddikey_close(qk);
}

void chip_id_verify(void)
{
    printf("Starting id verification procedure\n");
    int error = 0;
    pi_device_t qk_device = {0};
    pi_device_t *qk = &qk_device;
    pi_quiddikey_conf_t conf = {0};
    conf.id = 0;
    conf.enroll = 0;
    conf.ac = saved_activation_code;
    qk_device.config = &conf;
    error = pi_quiddikey_open(qk);
    if(error)
    {
        printf("Failed to start quiddikey with saved AC\n");
        exit(-1);
    }
    uint32_t key_length = 1024; // 1024 bits
    uint8_t *key_check = pi_malloc(2048);
    error = unwrap_key(qk, key_length, key_check, saved_key_code);
    for(unsigned int i = 0; i< (key_length >> 3); i++)
    {
        if(key_check[i] != saved_key[i])
        {
            printf("Key code verifcation failed\n");
            exit(-1);
        }
    }
    pi_free(key_check);
    pi_quiddikey_close(qk);
    printf("ID verification procedure done\n");
}


int main(void)
{
    printf("Entering chip id example\n");

    // First, demonstrate enroll procedure:
    // NOTE: this should only be done once at factory
    chip_id_enroll();

    // Now, demonstrate verification prodecure: to be done at library start
    chip_id_verify();
}