1 /*
2  * Copyright (c) 2020 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ctype.h>
8 
9 #include <device.h>
10 #include <sys/crc.h>
11 #include <logging/log.h>
12 
13 #ifdef CONFIG_OSDP_SC_ENABLED
14 #include <crypto/cipher.h>
15 #include <random/rand32.h>
16 #endif
17 
18 #include "osdp_common.h"
19 
20 LOG_MODULE_DECLARE(osdp, CONFIG_OSDP_LOG_LEVEL);
21 
osdp_dump(const char * head,uint8_t * buf,int len)22 void osdp_dump(const char *head, uint8_t *buf, int len)
23 {
24 	LOG_HEXDUMP_DBG(buf, len, head);
25 }
26 
osdp_compute_crc16(const uint8_t * buf,size_t len)27 uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len)
28 {
29 	return crc16_itu_t(0x1D0F, buf, len);
30 }
31 
osdp_millis_now(void)32 int64_t osdp_millis_now(void)
33 {
34 	return (int64_t) k_uptime_get();
35 }
36 
osdp_millis_since(int64_t last)37 int64_t osdp_millis_since(int64_t last)
38 {
39 	int64_t tmp = last;
40 
41 	return (int64_t) k_uptime_delta(&tmp);
42 }
43 
osdp_cmd_alloc(struct osdp_pd * pd)44 struct osdp_cmd *osdp_cmd_alloc(struct osdp_pd *pd)
45 {
46 	struct osdp_cmd *cmd = NULL;
47 
48 	if (k_mem_slab_alloc(&pd->cmd.slab, (void **)&cmd, K_MSEC(100))) {
49 		LOG_ERR("Memory allocation time-out");
50 		return NULL;
51 	}
52 	return cmd;
53 }
54 
osdp_cmd_free(struct osdp_pd * pd,struct osdp_cmd * cmd)55 void osdp_cmd_free(struct osdp_pd *pd, struct osdp_cmd *cmd)
56 {
57 	k_mem_slab_free(&pd->cmd.slab, (void **)&cmd);
58 }
59 
osdp_cmd_enqueue(struct osdp_pd * pd,struct osdp_cmd * cmd)60 void osdp_cmd_enqueue(struct osdp_pd *pd, struct osdp_cmd *cmd)
61 {
62 	sys_slist_append(&pd->cmd.queue, &cmd->node);
63 }
64 
osdp_cmd_dequeue(struct osdp_pd * pd,struct osdp_cmd ** cmd)65 int osdp_cmd_dequeue(struct osdp_pd *pd, struct osdp_cmd **cmd)
66 {
67 	sys_snode_t *node;
68 
69 	node = sys_slist_peek_head(&pd->cmd.queue);
70 	if (node == NULL) {
71 		return -1;
72 	}
73 	sys_slist_remove(&pd->cmd.queue, NULL, node);
74 	*cmd = CONTAINER_OF(node, struct osdp_cmd, node);
75 	return 0;
76 }
77 
osdp_cmd_get_last(struct osdp_pd * pd)78 struct osdp_cmd *osdp_cmd_get_last(struct osdp_pd *pd)
79 {
80 	return (struct osdp_cmd *)sys_slist_peek_tail(&pd->cmd.queue);
81 }
82 
83 #ifdef CONFIG_OSDP_SC_ENABLED
84 
osdp_encrypt(uint8_t * key,uint8_t * iv,uint8_t * data,int len)85 void osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len)
86 {
87 	const struct device *dev;
88 	struct cipher_ctx ctx = {
89 		.keylen = 16,
90 		.key.bit_stream = key,
91 		.flags = CAP_NO_IV_PREFIX
92 	};
93 	struct cipher_pkt encrypt = {
94 		.in_buf = data,
95 		.in_len = len,
96 		.out_buf = data,
97 		.out_len = len
98 	};
99 
100 	dev = device_get_binding(CONFIG_OSDP_CRYPTO_DRV_NAME);
101 	if (dev == NULL) {
102 		LOG_ERR("Failed to get crypto dev binding!");
103 		return;
104 	}
105 
106 	if (iv != NULL) {
107 		if (cipher_begin_session(dev, &ctx,
108 					 CRYPTO_CIPHER_ALGO_AES,
109 					 CRYPTO_CIPHER_MODE_CBC,
110 					 CRYPTO_CIPHER_OP_ENCRYPT)) {
111 			LOG_ERR("Failed at cipher_begin_session");
112 			return;
113 		}
114 		if (cipher_cbc_op(&ctx, &encrypt, iv)) {
115 			LOG_ERR("CBC ENCRYPT - Failed");
116 		}
117 	} else {
118 		if (cipher_begin_session(dev, &ctx,
119 					 CRYPTO_CIPHER_ALGO_AES,
120 					 CRYPTO_CIPHER_MODE_ECB,
121 					 CRYPTO_CIPHER_OP_ENCRYPT)) {
122 			LOG_ERR("Failed at cipher_begin_session");
123 			return;
124 		}
125 		if (cipher_block_op(&ctx, &encrypt)) {
126 			LOG_ERR("ECB ENCRYPT - Failed");
127 		}
128 	}
129 	cipher_free_session(dev, &ctx);
130 }
131 
osdp_decrypt(uint8_t * key,uint8_t * iv,uint8_t * data,int len)132 void osdp_decrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len)
133 {
134 	const struct device *dev;
135 	struct cipher_ctx ctx = {
136 		.keylen = 16,
137 		.key.bit_stream = key,
138 		.flags = CAP_NO_IV_PREFIX
139 	};
140 	struct cipher_pkt decrypt = {
141 		.in_buf = data,
142 		.in_len = len,
143 		.out_buf = data,
144 		.out_len = len
145 	};
146 
147 	dev = device_get_binding(CONFIG_OSDP_CRYPTO_DRV_NAME);
148 	if (dev == NULL) {
149 		LOG_ERR("Failed to get crypto dev binding!");
150 		return;
151 	}
152 
153 	if (iv != NULL) {
154 		if (cipher_begin_session(dev, &ctx,
155 					 CRYPTO_CIPHER_ALGO_AES,
156 					 CRYPTO_CIPHER_MODE_CBC,
157 					 CRYPTO_CIPHER_OP_DECRYPT)) {
158 			LOG_ERR("Failed at cipher_begin_session");
159 			return;
160 		}
161 		if (cipher_cbc_op(&ctx, &decrypt, iv)) {
162 			LOG_ERR("CBC DECRYPT - Failed");
163 		}
164 	} else {
165 		if (cipher_begin_session(dev, &ctx,
166 					 CRYPTO_CIPHER_ALGO_AES,
167 					 CRYPTO_CIPHER_MODE_ECB,
168 					 CRYPTO_CIPHER_OP_DECRYPT)) {
169 			LOG_ERR("Failed at cipher_begin_session");
170 			return;
171 		}
172 		if (cipher_block_op(&ctx, &decrypt)) {
173 			LOG_ERR("ECB DECRYPT - Failed");
174 		}
175 	}
176 	cipher_free_session(dev, &ctx);
177 }
178 
osdp_fill_random(uint8_t * buf,int len)179 void osdp_fill_random(uint8_t *buf, int len)
180 {
181 	sys_csrand_get(buf, len);
182 }
183 
osdp_get_sc_status_mask(void)184 uint32_t osdp_get_sc_status_mask(void)
185 {
186 	int i;
187 	uint32_t mask = 0;
188 	struct osdp_pd *pd;
189 	struct osdp *ctx = osdp_get_ctx();
190 
191 	for (i = 0; i < NUM_PD(ctx); i++) {
192 		pd = TO_PD(ctx, i);
193 		if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) {
194 			mask |= 1 << i;
195 		}
196 	}
197 	return mask;
198 }
199 
200 #endif /* CONFIG_OSDP_SC_ENABLED */
201