1 /*
2 * Copyright (c) 2023-2024, The TrustedFirmware-M Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "cc3xx_kdf.h"
9
10 #include "cc3xx_rng.h"
11 #include "cc3xx_stdlib.h"
12
13 #include <assert.h>
14
15 /* This is a NIST SP-800-108 counter mode KDF with CMAC as the pseudo-random
16 * function, using the modified Label || 0x00 || Context || [L]2 || K (0)
17 * construction where K(0) = PRF(K IN, Label || 0x00 || Context || [L]2 )
18 * proposed as a countermeasure for CMAC KDFs in SP-800-108 section 4.1.
19 */
cc3xx_lowlevel_kdf_cmac(cc3xx_aes_key_id_t key_id,const uint32_t * key,cc3xx_aes_keysize_t key_size,const uint8_t * label,size_t label_length,const uint8_t * context,size_t context_length,uint32_t * output_key,size_t out_length)20 cc3xx_err_t cc3xx_lowlevel_kdf_cmac(
21 cc3xx_aes_key_id_t key_id, const uint32_t *key,
22 cc3xx_aes_keysize_t key_size,
23 const uint8_t *label, size_t label_length,
24 const uint8_t *context, size_t context_length,
25 uint32_t *output_key, size_t out_length)
26 {
27 uint32_t i_idx = 1;
28 uint32_t l_total_length = out_length;
29 uint8_t null_byte = 0;
30 cc3xx_err_t err;
31 uint32_t cmac_buf[AES_TAG_MAX_LEN / sizeof(uint32_t)];
32 uint32_t k0[AES_TAG_MAX_LEN / sizeof(uint32_t)];
33 size_t output_idx;
34
35 /* Check alignment */
36 assert(((uintptr_t)output_key & 0b11) == 0);
37 assert((out_length / sizeof(cmac_buf)) != 0);
38
39 err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT, CC3XX_AES_MODE_CMAC,
40 key_id, key, key_size, NULL, 0);
41 if (err != CC3XX_ERR_SUCCESS) {
42 goto out;
43 }
44
45 cc3xx_lowlevel_aes_set_tag_len(AES_TAG_MAX_LEN);
46
47 cc3xx_lowlevel_aes_update_authed_data(label, label_length);
48 cc3xx_lowlevel_aes_update_authed_data(&null_byte, sizeof(null_byte));
49 cc3xx_lowlevel_aes_update_authed_data(context, context_length);
50 cc3xx_lowlevel_aes_update_authed_data((uint8_t *)&l_total_length,
51 sizeof(l_total_length));
52 cc3xx_lowlevel_aes_finish(k0, NULL);
53
54 for(output_idx = 0; output_idx < out_length; output_idx += sizeof(cmac_buf)) {
55 err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT, CC3XX_AES_MODE_CMAC,
56 key_id, key, key_size, NULL, 0);
57 if (err != CC3XX_ERR_SUCCESS) {
58 goto out;
59 }
60
61 cc3xx_lowlevel_aes_set_tag_len(AES_TAG_MAX_LEN);
62
63 cc3xx_lowlevel_aes_update_authed_data((uint8_t *)&i_idx, sizeof(i_idx));
64 cc3xx_lowlevel_aes_update_authed_data(label, label_length);
65 cc3xx_lowlevel_aes_update_authed_data(&null_byte, sizeof(null_byte));
66 cc3xx_lowlevel_aes_update_authed_data(context, context_length);
67 cc3xx_lowlevel_aes_update_authed_data((uint8_t *)&l_total_length,
68 sizeof(l_total_length));
69 cc3xx_lowlevel_aes_update_authed_data((uint8_t *)k0, sizeof(k0));
70 cc3xx_lowlevel_aes_finish(cmac_buf, NULL);
71
72 cc3xx_dpa_hardened_word_copy((void *)output_key + output_idx, cmac_buf,
73 sizeof(cmac_buf) / sizeof(uint32_t));
74 i_idx += 1;
75 }
76
77 err = CC3XX_ERR_SUCCESS;
78 out:
79 cc3xx_secure_erase_buffer(k0, sizeof(k0) / sizeof(uint32_t));
80 cc3xx_secure_erase_buffer(cmac_buf, sizeof(cmac_buf) / sizeof(uint32_t));
81
82 if (err != CC3XX_ERR_SUCCESS) {
83 cc3xx_secure_erase_buffer(output_key, out_length / sizeof(uint32_t));
84 }
85
86 return err;
87 }
88