1 /* Copyright (c) 2024 Nordic Semiconductor
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 #include <psa/crypto.h>
5 #include <zephyr/logging/log.h>
6 
7 LOG_MODULE_REGISTER(persistent_key);
8 
9 #define SAMPLE_KEY_ID   PSA_KEY_ID_USER_MIN
10 #define SAMPLE_KEY_TYPE PSA_KEY_TYPE_AES
11 #define SAMPLE_ALG      PSA_ALG_CTR
12 #define SAMPLE_KEY_BITS 256
13 
generate_persistent_key(void)14 int generate_persistent_key(void)
15 {
16 	LOG_INF("Generating a persistent key...");
17 	psa_status_t ret;
18 	psa_key_id_t key_id;
19 	psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
20 
21 	psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
22 	psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
23 	psa_set_key_id(&key_attributes, SAMPLE_KEY_ID);
24 	psa_set_key_type(&key_attributes, SAMPLE_KEY_TYPE);
25 	psa_set_key_algorithm(&key_attributes, SAMPLE_ALG);
26 	psa_set_key_bits(&key_attributes, SAMPLE_KEY_BITS);
27 
28 	ret = psa_generate_key(&key_attributes, &key_id);
29 	if (ret != PSA_SUCCESS) {
30 		LOG_ERR("Failed to generate the key. (%d)", ret);
31 		return -1;
32 	}
33 	__ASSERT_NO_MSG(key_id == SAMPLE_KEY_ID);
34 
35 	/* Purge the key from volatile memory. Has the same affect than resetting the device. */
36 	ret = psa_purge_key(SAMPLE_KEY_ID);
37 	if (ret != PSA_SUCCESS) {
38 		LOG_ERR("Failed to purge the generated key from volatile memory. (%d).", ret);
39 		return -1;
40 	}
41 
42 	LOG_INF("Persistent key generated.");
43 	return 0;
44 }
45 
use_persistent_key(void)46 int use_persistent_key(void)
47 {
48 	LOG_INF("Using the persistent key to encrypt and decrypt some plaintext...");
49 	psa_status_t ret;
50 	size_t ciphertext_len;
51 	size_t decrypted_text_len;
52 
53 	static uint8_t plaintext[] =
54 		"Example plaintext to demonstrate basic usage of a persistent key.";
55 	static uint8_t ciphertext[PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(SAMPLE_KEY_TYPE, SAMPLE_ALG,
56 								 sizeof(plaintext))];
57 	static uint8_t decrypted_text[sizeof(plaintext)];
58 
59 	ret = psa_cipher_encrypt(SAMPLE_KEY_ID, SAMPLE_ALG, plaintext, sizeof(plaintext),
60 				 ciphertext, sizeof(ciphertext), &ciphertext_len);
61 	if (ret != PSA_SUCCESS) {
62 		LOG_ERR("Failed to encrypt the plaintext. (%d)", ret);
63 		return -1;
64 	}
65 
66 	ret = psa_cipher_decrypt(SAMPLE_KEY_ID, SAMPLE_ALG, ciphertext, ciphertext_len,
67 				 decrypted_text, sizeof(decrypted_text), &decrypted_text_len);
68 	if (ret != PSA_SUCCESS) {
69 		LOG_ERR("Failed to decrypt the ciphertext. (%d)", ret);
70 		return -1;
71 	}
72 	__ASSERT_NO_MSG(decrypted_text_len == sizeof(plaintext));
73 
74 	/* Make sure the decryption gives us the original plaintext back. */
75 	if (memcmp(plaintext, decrypted_text, sizeof(plaintext))) {
76 		LOG_HEXDUMP_INF(plaintext, sizeof(plaintext), "Plaintext:");
77 		LOG_HEXDUMP_INF(ciphertext, ciphertext_len, "Ciphertext:");
78 		LOG_HEXDUMP_INF(decrypted_text, sizeof(decrypted_text), "Decrypted text:");
79 		LOG_ERR("The decrypted text doesn't match the plaintext.");
80 		return -1;
81 	}
82 
83 	LOG_INF("Persistent key usage successful.");
84 	return 0;
85 }
86 
destroy_persistent_key(void)87 static int destroy_persistent_key(void)
88 {
89 	LOG_INF("Destroying the persistent key...");
90 	psa_status_t ret;
91 
92 	ret = psa_destroy_key(SAMPLE_KEY_ID);
93 	if (ret != PSA_SUCCESS) {
94 		LOG_ERR("Failed to destroy the key. (%d)", ret);
95 		return -1;
96 	}
97 
98 	LOG_INF("Persistent key destroyed.");
99 	return 0;
100 }
101 
main(void)102 int main(void)
103 {
104 	LOG_INF("Persistent key sample started.");
105 
106 	/* Ensure there is not already a key with this ID. */
107 	psa_destroy_key(SAMPLE_KEY_ID);
108 
109 	if (generate_persistent_key()) {
110 		return -1;
111 	}
112 
113 	if (use_persistent_key()) {
114 		return -1;
115 	}
116 
117 	if (destroy_persistent_key()) {
118 		return -1;
119 	}
120 
121 	LOG_INF("Sample finished successfully.");
122 	return 0;
123 }
124