-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add sample to demonstrate PBKDF2 use-case. Signed-off-by: Joakim Andersson <[email protected]>
- Loading branch information
Showing
11 changed files
with
364 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# | ||
# Copyright (c) 2023 Nordic Semiconductor ASA | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
# | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
|
||
project(pbkdf2) | ||
|
||
target_sources(app PRIVATE | ||
src/main.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
.. _crypto_pbkdf2: | ||
|
||
Crypto: PBKDF2 | ||
############## | ||
|
||
.. contents:: | ||
:local: | ||
:depth: 2 | ||
|
||
The Password Based Key Derivation Function (PBKDF2) sample shows how to derive keys with the PBKDF2 algorithm, using a sample password salt, and iteration count. | ||
The underlying pseudorandom function (PRF) used in this sample is HMAC with SHA-256. | ||
|
||
Requirements | ||
************ | ||
|
||
The sample supports the following development kits: | ||
|
||
.. table-from-sample-yaml:: | ||
|
||
.. include:: /includes/tfm.txt | ||
|
||
Overview | ||
******** | ||
|
||
The sample performs the following operations: | ||
|
||
1. Initialization of the Platform Security Architecture (PSA) API. | ||
|
||
#. Key derivation: | ||
|
||
a. Imports the input password into the PSA crypto keystore. | ||
#. Derives the output key. | ||
|
||
#. Cleanup: | ||
|
||
a. The input password is removed from the PSA crypto keystore. | ||
|
||
Building and running | ||
******************** | ||
|
||
.. |sample path| replace:: :file:`samples/crypto/pbkdf2` | ||
|
||
.. include:: /includes/build_and_run_ns.txt | ||
|
||
Testing | ||
======= | ||
|
||
After programming the sample to your development kit, complete the following steps to test it: | ||
|
||
1. |connect_terminal| | ||
#. Compile and program the application. | ||
#. Observe the logs from the application using a terminal emulator. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Enable both oberon driver and hardware crypto accelerator | ||
# Key derivation is only supported in software driver but is using chained | ||
# driver to accelerate sub-operations. | ||
CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y | ||
CONFIG_PSA_CRYPTO_DRIVER_OBERON=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Enable both oberon driver and hardware crypto accelerator | ||
# Key derivation is only supported in software driver but is using chained | ||
# driver to accelerate sub-operations. | ||
CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y | ||
CONFIG_PSA_CRYPTO_DRIVER_OBERON=y |
4 changes: 4 additions & 0 deletions
4
samples/crypto/pbkdf2/boards/nrf5340dk_nrf5340_cpuapp_ns.conf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
CONFIG_TFM_PROFILE_TYPE_NOT_SET=y | ||
|
||
# Using hardware crypto accelerator | ||
CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Enable both oberon driver and hardware crypto accelerator | ||
# Key derivation is only supported in software driver but is using chained | ||
# driver to accelerate sub-operations. | ||
CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y | ||
CONFIG_PSA_CRYPTO_DRIVER_OBERON=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
CONFIG_TFM_PROFILE_TYPE_NOT_SET=y | ||
|
||
# Using hardware crypto accelerator | ||
CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
* Copyright (c) 2020 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
*/ | ||
|
||
/* Disable uart1 in nonsecure since it is used by the TFM secure app. */ | ||
&uart1 { | ||
status = "disabled"; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# The Zephyr CMSIS emulation assumes that ticks are ms, currently | ||
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 | ||
|
||
CONFIG_MAIN_STACK_SIZE=4096 | ||
CONFIG_HEAP_MEM_POOL_SIZE=4096 | ||
|
||
# Enable logging | ||
CONFIG_CONSOLE=y | ||
CONFIG_LOG=y | ||
|
||
# Enable nordic security backend and PSA APIs | ||
CONFIG_NRF_SECURITY=y | ||
CONFIG_MBEDTLS_PSA_CRYPTO_C=y | ||
|
||
CONFIG_MBEDTLS_ENABLE_HEAP=y | ||
CONFIG_MBEDTLS_HEAP_SIZE=8192 | ||
|
||
CONFIG_PSA_WANT_ALG_SHA_256=y | ||
CONFIG_PSA_WANT_ALG_HMAC=y | ||
CONFIG_PSA_WANT_ALG_PBKDF2_HMAC=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
sample: | ||
description: HMAC key derivation function example | ||
name: PBKDF2 example | ||
tests: | ||
sample.pbkdf2: | ||
tags: introduction psa cc3xx | ||
platform_allow: > | ||
nrf5340dk_nrf5340_cpuapp | ||
nrf9160dk_nrf9160 nrf52840dk_nrf52840 | ||
harness: console | ||
harness_config: | ||
type: multi_line | ||
regex: | ||
- ".*Example finished successfully!.*" | ||
integration_platforms: | ||
- nrf5340dk_nrf5340_cpuapp | ||
- nrf9160dk_nrf9160 | ||
- nrf52840dk_nrf52840 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
/* | ||
* Copyright (c) 2023 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/logging/log.h> | ||
#include <stdint.h> | ||
#include <psa/crypto.h> | ||
|
||
#ifdef CONFIG_BUILD_WITH_TFM | ||
#include <tfm_ns_interface.h> | ||
#endif | ||
|
||
#define APP_SUCCESS (0) | ||
#define APP_ERROR (-1) | ||
#define APP_SUCCESS_MESSAGE "Example finished successfully!" | ||
#define APP_ERROR_MESSAGE "Example exited with error!" | ||
|
||
#define PRINT_HEX(p_label, p_text, len)\ | ||
({\ | ||
LOG_INF("---- %s (len: %u): ----", p_label, len);\ | ||
LOG_HEXDUMP_INF(p_text, len, "Content:");\ | ||
LOG_INF("---- %s end ----", p_label);\ | ||
}) | ||
|
||
LOG_MODULE_REGISTER(pkbdf2, LOG_LEVEL_DBG); | ||
|
||
/* ====================================================================== */ | ||
/* Global variables/defines for the PBKDF2 example */ | ||
|
||
#define PBKDF2_SAMPLE_INPUT_KEY_SIZE (6) | ||
#define PBKDF2_SAMPLE_SALT_SIZE (4) | ||
#define PBKDF2_SAMPLE_OUTPUT_KEY_SIZE (64) | ||
|
||
/* Test data from RFC 5869 Test Case 2 | ||
* https://datatracker.ietf.org/doc/html/rfc7914.html#section-11 | ||
*/ | ||
static const uint8_t m_input_password[PBKDF2_SAMPLE_INPUT_KEY_SIZE] = { | ||
'p', 'a', 's', 's', 'w', 'd', | ||
}; | ||
|
||
static const uint8_t m_salt[PBKDF2_SAMPLE_SALT_SIZE] = { | ||
's', 'a', 'l', 't' | ||
}; | ||
|
||
/* (NIST) "Recommendation for Password-Based Key Derivation: | ||
* The iteration count shall be selected as large as possible, as | ||
* long as the time required to generate the key using the entered | ||
* password is acceptable for the users. [...] A minimum iteration | ||
* count of 1,000 is recommended. | ||
*/ | ||
static uint32_t m_iteration_count = 1; | ||
|
||
/* Buffer to hold the output generated from PKBD2S */ | ||
static uint8_t m_output_key[PBKDF2_SAMPLE_OUTPUT_KEY_SIZE]; | ||
|
||
static const uint8_t m_expected_output_key[PBKDF2_SAMPLE_OUTPUT_KEY_SIZE] = { | ||
0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f, | ||
0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05, | ||
0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65, | ||
0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc, | ||
0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45, | ||
0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31, | ||
0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5, | ||
0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83, | ||
}; | ||
|
||
static psa_key_id_t m_input_key_id; | ||
static psa_key_id_t m_output_key_id; | ||
/* ====================================================================== */ | ||
|
||
int crypto_init(void) | ||
{ | ||
psa_status_t status; | ||
|
||
/* Initialize PSA Crypto */ | ||
status = psa_crypto_init(); | ||
if (status != PSA_SUCCESS) | ||
return APP_ERROR; | ||
|
||
return APP_SUCCESS; | ||
} | ||
|
||
int crypto_finish(void) | ||
{ | ||
psa_status_t status; | ||
|
||
/* Destroy the key handle */ | ||
status = psa_destroy_key(m_input_key_id); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_destroy_key failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
status = psa_destroy_key(m_output_key_id); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_destroy_key failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
return APP_SUCCESS; | ||
} | ||
|
||
int import_input_password(void) | ||
{ | ||
psa_status_t status; | ||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; | ||
|
||
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); | ||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); | ||
psa_set_key_algorithm(&attributes, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); | ||
psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD); | ||
psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(PBKDF2_SAMPLE_INPUT_KEY_SIZE)); | ||
|
||
status = psa_import_key(&attributes, m_input_password, PBKDF2_SAMPLE_INPUT_KEY_SIZE, | ||
&m_input_key_id); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_import_key failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
return APP_SUCCESS; | ||
} | ||
|
||
int derive_output_key(void) | ||
{ | ||
psa_status_t status; | ||
int cmp_status; | ||
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; | ||
|
||
status = psa_key_derivation_setup(&operation, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_key_derivation_setup failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, | ||
m_iteration_count); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_key_derivation_input_integer failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, m_salt, | ||
PBKDF2_SAMPLE_SALT_SIZE); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_key_derivation_input_bytes failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, | ||
m_input_key_id); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_key_derivation_input_key failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
/* This outputs the derived key as bytes to the application. | ||
* If the derived key is to be used for in cryptographic operations use | ||
* psa_key_derivation_output_key instead. | ||
*/ | ||
status = psa_key_derivation_output_bytes(&operation, m_output_key, | ||
PBKDF2_SAMPLE_OUTPUT_KEY_SIZE); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_key_derivation_output_bytes failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
status = psa_key_derivation_abort(&operation); | ||
if (status != PSA_SUCCESS) { | ||
LOG_INF("psa_key_derivation_abort failed! (Error: %d)", status); | ||
return APP_ERROR; | ||
} | ||
|
||
LOG_INF("Compare derived key with expected value..."); | ||
cmp_status = memcmp(m_expected_output_key, m_output_key, sizeof(m_output_key)); | ||
if (cmp_status != 0) { | ||
LOG_INF("Error, the derived key doesn't match the expected value!"); | ||
return APP_ERROR; | ||
} | ||
|
||
LOG_INF("Key derivation successful!"); | ||
PRINT_HEX("Password", m_input_password, sizeof(m_input_password)); | ||
PRINT_HEX("Salt", m_salt, sizeof(m_salt)); | ||
LOG_INF("Iteration count: %d", m_iteration_count); | ||
PRINT_HEX("Derived Key:", m_output_key, sizeof(m_output_key)); | ||
|
||
return APP_SUCCESS; | ||
} | ||
|
||
|
||
int main(void) | ||
{ | ||
int status; | ||
|
||
LOG_INF("Starting PBKDF2 example..."); | ||
|
||
status = crypto_init(); | ||
if (status != APP_SUCCESS) { | ||
LOG_INF(APP_ERROR_MESSAGE); | ||
return APP_ERROR; | ||
} | ||
|
||
status = import_input_password(); | ||
if (status != APP_SUCCESS) { | ||
LOG_INF(APP_ERROR_MESSAGE); | ||
return APP_ERROR; | ||
} | ||
|
||
status = derive_output_key(); | ||
if (status != APP_SUCCESS) { | ||
LOG_INF(APP_ERROR_MESSAGE); | ||
return APP_ERROR; | ||
} | ||
|
||
status = crypto_finish(); | ||
if (status != APP_SUCCESS) { | ||
LOG_INF(APP_ERROR_MESSAGE); | ||
return APP_ERROR; | ||
} | ||
|
||
LOG_INF(APP_SUCCESS_MESSAGE); | ||
|
||
return APP_SUCCESS; | ||
} |