1 /*
2 * Copyright (c) 2019, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/init.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/entropy.h>
10 #include <zephyr/kernel.h>
11 #include <string.h>
12
13 #if defined(CONFIG_MBEDTLS)
14 #if !defined(CONFIG_MBEDTLS_CFG_FILE)
15 #include "mbedtls/config.h"
16 #else
17 #include CONFIG_MBEDTLS_CFG_FILE
18 #endif /* CONFIG_MBEDTLS_CFG_FILE */
19 #include <mbedtls/ctr_drbg.h>
20
21 #elif defined(CONFIG_TINYCRYPT)
22
23 #include <tinycrypt/ctr_prng.h>
24 #include <tinycrypt/aes.h>
25 #include <tinycrypt/constants.h>
26
27 #endif /* CONFIG_MBEDTLS */
28
29 static K_SEM_DEFINE(state_sem, 1, 1);
30
31 /*
32 * entropy_dev is initialized at runtime to allow first time initialization
33 * of the ctr_drbg engine.
34 */
35 static const struct device *entropy_dev;
36 static const unsigned char drbg_seed[] = CONFIG_CS_CTR_DRBG_PERSONALIZATION;
37 static bool ctr_initialised;
38
39 #if defined(CONFIG_MBEDTLS)
40
41 static mbedtls_ctr_drbg_context ctr_ctx;
42
ctr_drbg_entropy_func(void * ctx,unsigned char * buf,size_t len)43 static int ctr_drbg_entropy_func(void *ctx, unsigned char *buf, size_t len)
44 {
45 return entropy_get_entropy(entropy_dev, (void *)buf, len);
46 }
47
48 #elif defined(CONFIG_TINYCRYPT)
49
50 static TCCtrPrng_t ctr_ctx;
51
52 #endif /* CONFIG_MBEDTLS */
53
54
ctr_drbg_initialize(void)55 static int ctr_drbg_initialize(void)
56 {
57 int ret;
58
59 entropy_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
60
61 if (!device_is_ready(entropy_dev)) {
62 __ASSERT(0, "Entropy device %s not ready", entropy_dev->name);
63 return -ENODEV;
64 }
65
66 #if defined(CONFIG_MBEDTLS)
67
68 mbedtls_ctr_drbg_init(&ctr_ctx);
69
70 ret = mbedtls_ctr_drbg_seed(&ctr_ctx,
71 ctr_drbg_entropy_func,
72 NULL,
73 drbg_seed,
74 sizeof(drbg_seed));
75
76 if (ret != 0) {
77 mbedtls_ctr_drbg_free(&ctr_ctx);
78 return -EIO;
79 }
80
81 #elif defined(CONFIG_TINYCRYPT)
82
83 uint8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
84
85 ret = entropy_get_entropy(entropy_dev, (void *)&entropy,
86 sizeof(entropy));
87 if (ret != 0) {
88 return -EIO;
89 }
90
91 ret = tc_ctr_prng_init(&ctr_ctx,
92 (uint8_t *)&entropy,
93 sizeof(entropy),
94 (uint8_t *)drbg_seed,
95 sizeof(drbg_seed));
96
97 if (ret == TC_CRYPTO_FAIL) {
98 return -EIO;
99 }
100
101 #endif
102 ctr_initialised = true;
103 return 0;
104 }
105
106
z_impl_sys_csrand_get(void * dst,uint32_t outlen)107 int z_impl_sys_csrand_get(void *dst, uint32_t outlen)
108 {
109 int ret;
110 unsigned int key = irq_lock();
111
112 if (unlikely(!ctr_initialised)) {
113 ret = ctr_drbg_initialize();
114 if (ret != 0) {
115 ret = -EIO;
116 goto end;
117 }
118 }
119
120 #if defined(CONFIG_MBEDTLS)
121
122 ret = mbedtls_ctr_drbg_random(&ctr_ctx, (unsigned char *)dst, outlen);
123
124 #elif defined(CONFIG_TINYCRYPT)
125
126 uint8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
127
128 ret = tc_ctr_prng_generate(&ctr_ctx, 0, 0, (uint8_t *)dst, outlen);
129
130 if (ret == TC_CRYPTO_SUCCESS) {
131 ret = 0;
132 } else if (ret == TC_CTR_PRNG_RESEED_REQ) {
133
134 ret = entropy_get_entropy(entropy_dev,
135 (void *)&entropy, sizeof(entropy));
136 if (ret != 0) {
137 ret = -EIO;
138 goto end;
139 }
140
141 ret = tc_ctr_prng_reseed(&ctr_ctx,
142 entropy,
143 sizeof(entropy),
144 drbg_seed,
145 sizeof(drbg_seed));
146
147 ret = tc_ctr_prng_generate(&ctr_ctx, 0, 0,
148 (uint8_t *)dst, outlen);
149
150 ret = (ret == TC_CRYPTO_SUCCESS) ? 0 : -EIO;
151 } else {
152 ret = -EIO;
153 }
154 #endif
155 end:
156 irq_unlock(key);
157
158 return ret;
159 }
160