1 /*  main.c  */
2 
3 /*
4  *   SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  *
9  *  Basic example of userspace thread protected memory
10  *
11  *  NOTE: The encryption algorithm is unverified and
12  *  based on a 1930's era piece of hardware.
13  *  DO NOT USE THIS CODE FOR SECURITY
14  *
15  */
16 
17 #include <zephyr/sys/__assert.h>
18 #include <zephyr/sys/libc-hooks.h> /* for z_libc_partition */
19 
20 #include "main.h"
21 #include "enc.h"
22 /* the following definition name prefix is to avoid a conflict */
23 #define SAMP_BLOCKSIZE 50
24 
25 /*
26  *  The memory partitions have been named to simplify
27  * the definition of variables.  A possible alternative
28  * is using one source file per thread and implementing
29  * a objcopy to rename the data and bss section for the
30  * thread to the partition name.
31  */
32 
33 /* prepare the memory partition structures  */
34 FOR_EACH(K_APPMEM_PARTITION_DEFINE, (;), user_part, red_part, enc_part, blk_part, ct_part);
35 /* prepare the memory domain structures  */
36 struct k_mem_domain pt_domain, enc_domain;
37 /* each variable starts with a name defined in main.h
38  * the names are symbolic for the memory partitions
39  * purpose.
40  */
41 volatile _app_red_b BYTE fBUFIN;
42 volatile _app_red_b BYTE BUFIN[63];
43 
44 volatile _app_blk_b BYTE fBUFOUT;
45 volatile _app_blk_b BYTE BUFOUT[63];
46 
47 /* declare and set wheel and reflector  */
48 /* To use add definition ALTMSG */
49 #ifdef ALTMSG
50 volatile _app_enc_d BYTE W1[26] = START_WHEEL;
51 #else
52 volatile _app_enc_d BYTE W1[26] = START_WHEEL2;
53 #endif
54 volatile _app_enc_d BYTE W2[26] = START_WHEEL;
55 volatile _app_enc_d BYTE W3[26] = START_WHEEL;
56 volatile _app_enc_d BYTE R[26] = REFLECT;
57 
58 volatile _app_enc_b int IW1;
59 volatile _app_enc_b int IW2;
60 volatile _app_enc_b int IW3;
61 
62 /*
63  *   calculated by the enc thread at init and when the wheels
64  *   change.
65  */
66 volatile _app_enc_b BYTE W1R[26];
67 volatile _app_enc_b BYTE W2R[26];
68 volatile _app_enc_b BYTE W3R[26];
69 
70 /*
71  *	sync threads
72  */
73 K_SEM_DEFINE(allforone, 0, 3);
74 
75 struct k_thread enc_thread;
76 K_THREAD_STACK_DEFINE(enc_stack, STACKSIZE);
77 
78 struct k_thread pt_thread;
79 K_THREAD_STACK_DEFINE(pt_stack, STACKSIZE);
80 
81 struct k_thread ct_thread;
82 K_THREAD_STACK_DEFINE(ct_stack, STACKSIZE);
83 
84 _app_enc_d char encMSG[] = "ENC!\n";
85 volatile _app_enc_b char enc_pt[50];  /* Copy form shared pt */
86 volatile _app_enc_b char enc_ct[50]; /* Copy to shared ct */
87 
88 _app_user_d char ptMSG[] = "PT: message to encrypt\n";
89 
90 /* encrypted message when W1 = START_WHEEL */
91 /* to use add definition ALTMSG  */
92 #ifdef ALTMSG
93 _app_user_d char ptMSG2[] = "nfttbhfspfmdqzos\n";
94 #else
95 /* encrypted message when W1 = START_WHEEL2 */
96 _app_user_d char ptMSG2[] = "ofttbhfspgmeqzos\n";
97 #endif
98 _app_ct_d char ctMSG[] = "CT!\n";
99 
100 
101 
102 
main(void)103 int main(void)
104 {
105 	struct k_mem_partition *enc_parts[] = {
106 #if Z_LIBC_PARTITION_EXISTS
107 		&z_libc_partition,
108 #endif
109 		&enc_part, &red_part, &blk_part
110 	};
111 	struct k_mem_partition *pt_parts[] = {
112 #if Z_LIBC_PARTITION_EXISTS
113 		&z_libc_partition,
114 #endif
115 		&user_part, &red_part
116 	};
117 	k_tid_t tPT, tENC, tCT;
118 	int ret;
119 
120 	fBUFIN = 0; /* clear flags */
121 	fBUFOUT = 0;
122 	calc_rev_wheel((BYTE *) &W1, (BYTE *)&W1R);
123 	calc_rev_wheel((BYTE *) &W2, (BYTE *)&W2R);
124 	calc_rev_wheel((BYTE *) &W3, (BYTE *)&W3R);
125 	IW1 = 0;
126 	IW2 = 0;
127 	IW3 = 0;
128 
129 	k_thread_access_grant(k_current_get(), &allforone);
130 
131 	/*
132 	 * create an enc thread init the memory domain and add partitions
133 	 * then add the thread to the domain.
134 	 */
135 	tENC = k_thread_create(&enc_thread, enc_stack, STACKSIZE,
136 			enc, NULL, NULL, NULL,
137 			-1, K_USER,
138 			K_FOREVER);
139 	k_thread_access_grant(tENC, &allforone);
140 	/* use K_FOREVER followed by k_thread_start*/
141 	printk("ENC Thread Created %p\n", tENC);
142 
143 	ret = k_mem_domain_init(&enc_domain, ARRAY_SIZE(enc_parts), enc_parts);
144 	__ASSERT(ret == 0, "k_mem_domain_init() on enc_domain failed %d", ret);
145 	ARG_UNUSED(ret);
146 
147 	printk("Partitions added to enc_domain\n");
148 	k_mem_domain_add_thread(&enc_domain, tENC);
149 	printk("enc_domain Created\n");
150 
151 
152 	tPT = k_thread_create(&pt_thread, pt_stack, STACKSIZE,
153 			pt, NULL, NULL, NULL,
154 			-1, K_USER,
155 			K_FOREVER);
156 	k_thread_access_grant(tPT, &allforone);
157 	printk("PT Thread Created %p\n", tPT);
158 
159 	ret = k_mem_domain_init(&pt_domain, ARRAY_SIZE(pt_parts), pt_parts);
160 	__ASSERT(ret == 0, "k_mem_domain_init() on pt_domain failed %d", ret);
161 
162 	k_mem_domain_add_thread(&pt_domain, tPT);
163 	printk("pt_domain Created\n");
164 
165 	tCT = k_thread_create(&ct_thread, ct_stack, STACKSIZE,
166 			ct, NULL, NULL, NULL,
167 			-1, K_USER,
168 			K_FOREVER);
169 	k_thread_access_grant(tCT, &allforone);
170 	printk("CT Thread Created %p\n", tCT);
171 	/* Re-using the default memory domain for CT */
172 	ret = k_mem_domain_add_partition(&k_mem_domain_default, &ct_part);
173 	if (ret != 0) {
174 		printk("Failed to add ct_part to mem domain (%d)\n", ret);
175 		k_oops();
176 	}
177 	printk("ct partitions installed\n");
178 
179 	ret = k_mem_domain_add_partition(&k_mem_domain_default, &blk_part);
180 	if (ret != 0) {
181 		printk("Failed to add blk_part to mem domain (%d)\n", ret);
182 		k_oops();
183 	}
184 	printk("blk partitions installed\n");
185 
186 	k_thread_start(&enc_thread);
187 	/* need to start all three threads.  let enc go first to perform init step */
188 
189 	printk("ENC thread started\n");
190 	k_thread_start(&pt_thread);
191 	printk("PT thread started\n");
192 
193 	k_thread_start(&ct_thread);
194 	k_sem_give(&allforone);
195 	printk("CT thread started\n");
196 	return 0;
197 }
198 
199 
200 
201 /*
202  * The enc thread.
203  * Function: initialize the simulation of the wheels.
204  * Copy memory from pt thread and encrypt to a local buffer
205  * then copy to the ct thread.
206  */
enc(void * p1,void * p2,void * p3)207 void enc(void *p1, void *p2, void *p3)
208 {
209 	ARG_UNUSED(p1);
210 	ARG_UNUSED(p2);
211 	ARG_UNUSED(p3);
212 
213 	int index, index_out;
214 
215 	while (1) {
216 		k_sem_take(&allforone, K_FOREVER);
217 		if (fBUFIN == 1) { /* 1 is process text */
218 			printk("ENC Thread Received Data\n");
219 			/* copy message form shared mem and clear flag */
220 			memcpy((void *)&enc_pt, (void *)BUFIN, SAMP_BLOCKSIZE);
221 			printk("ENC PT MSG: %s\n", (char *)&enc_pt);
222 			fBUFIN = 0;
223 			/* reset wheel: probably better as a flag option  */
224 			IW1 = 7;
225 			IW2 = 2;
226 			IW3 = 3;
227 			/* encode */
228 			memset((void *)&enc_ct, 0, SAMP_BLOCKSIZE);
229 			for (index = 0, index_out = 0; index < SAMP_BLOCKSIZE; index++) {
230 				if (enc_pt[index] == '\0') {
231 					enc_ct[index_out] = '\0';
232 					break;
233 				}
234 				if (enc_pt[index] >= 'a' && enc_pt[index] <= 'z') {
235 					enc_ct[index_out] = (BYTE)enig_enc((BYTE) enc_pt[index]);
236 					index_out++;
237 				}
238 			}
239 			/* test for CT flag */
240 			while (fBUFOUT != 0) {
241 				k_sleep(K_MSEC(1));
242 			}
243 			/* ct thread has cleared the buffer */
244 			memcpy((void *)&BUFOUT, (void *)&enc_ct,
245 			       SAMP_BLOCKSIZE);
246 			fBUFOUT = 1;
247 
248 		}
249 		k_sem_give(&allforone);
250 	}
251 }
252 
253 /*
254  * the pt function pushes data to the enc thread.
255  * It can be extended to receive data from a serial port
256  * and pass the data to enc
257  */
pt(void * p1,void * p2,void * p3)258 void pt(void *p1, void *p2, void *p3)
259 {
260 	ARG_UNUSED(p1);
261 	ARG_UNUSED(p2);
262 	ARG_UNUSED(p3);
263 
264 	k_sleep(K_MSEC(20));
265 	while (1) {
266 		k_sem_take(&allforone, K_FOREVER);
267 		if (fBUFIN == 0) { /* send message to encode */
268 			printk("\nPT Sending Message 1\n");
269 			memset((void *)&BUFIN, 0, SAMP_BLOCKSIZE);
270 			memcpy((void *)&BUFIN, (void *)&ptMSG, sizeof(ptMSG));
271 /* strlen should not be used if user provided data, needs a max length set  */
272 			fBUFIN = 1;
273 		}
274 		k_sem_give(&allforone);
275 		k_sem_take(&allforone, K_FOREVER);
276 		if (fBUFIN == 0) { /* send message to decode  */
277 			printk("\nPT Sending Message 1'\n");
278 			memset((void *)&BUFIN, 0, SAMP_BLOCKSIZE);
279 			memcpy((void *)&BUFIN, (void *)&ptMSG2, sizeof(ptMSG2));
280 			fBUFIN = 1;
281 		}
282 		k_sem_give(&allforone);
283 		k_sleep(K_MSEC(50));
284 	}
285 }
286 
287 /*
288  * CT waits for fBUFOUT = 1 then copies
289  * the message clears the flag and prints
290  */
ct(void * p1,void * p2,void * p3)291 void ct(void *p1, void *p2, void *p3)
292 {
293 	ARG_UNUSED(p1);
294 	ARG_UNUSED(p2);
295 	ARG_UNUSED(p3);
296 
297 	char tbuf[60];
298 
299 	while (1) {
300 		k_sem_take(&allforone, K_FOREVER);
301 		if (fBUFOUT == 1) {
302 			printk("CT Thread Received Message\n");
303 			memset((void *)&tbuf, 0, sizeof(tbuf));
304 			memcpy((void *)&tbuf, (void *)BUFOUT, SAMP_BLOCKSIZE);
305 			fBUFOUT = 0;
306 			printk("CT MSG: %s\n", (char *)&tbuf);
307 		}
308 		k_sem_give(&allforone);
309 	}
310 }
311