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