1 /*
2 * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /******************************************************************************
18 * @file ck_sha.c
19 * @brief CSI Source File for SHA Driver
20 * @version V1.0
21 * @date 02. June 2017
22 ******************************************************************************/
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #include "csi_core.h"
27 #include "drv_sha.h"
28 #include "ck_sha.h"
29
30
31 typedef struct {
32 uint32_t base;
33 uint32_t irq;
34 sha_event_cb_t cb;
35 sha_status_t status;
36 sha_mode_e mode;
37 sha_endian_mode_e endian;
38 } ck_sha_priv_t;
39
40 static ck_sha_priv_t sha_handle[CONFIG_SHA_NUM];
41 bool finish_flag = 0;
42
43 /* Driver Capabilities */
44 static const sha_capabilities_t driver_capabilities = {
45 .sha1 = 1, /* sha1 mode */
46 .sha224 = 1, /* sha224 mode */
47 .sha256 = 1, /* sha256 mode */
48 .sha384 = 1, /* sha384 mode */
49 .sha512 = 1, /* sha512 mode */
50 .sha512_224 = 1, /* sha512_224 mode */
51 .sha512_256 = 1, /* sha512_256 mode */
52 .endianmode = 1, /* endian mode */
53 .interruptmode = 1 /* interrupt mode */
54 };
55
56 #define ERR_SHA(errno) (CSI_DRV_ERRNO_SHA_BASE | errno)
57 #define SHA_NULL_PARAM_CHK(para) \
58 do { \
59 if (para == NULL) { \
60 return ERR_SHA(EDRV_PARAMETER); \
61 } \
62 } while (0)
63 //
64 // Functions
65 //
66
67 ck_sha_reg_t *sha_reg = NULL;
68 volatile static uint8_t sha_int_flag = 1;
69
sha_set_mode(sha_mode_e mode)70 static int32_t sha_set_mode(sha_mode_e mode)
71 {
72 sha_reg->SHA_CON = mode;
73 return 0;
74 }
75
sha_enable_interrupt(void)76 static int32_t sha_enable_interrupt(void)
77 {
78 sha_reg->SHA_CON |= 1 << SHA_INT_ENABLE_OFFSET;
79 return 0;
80 }
81
sha_disable_interrupt(void)82 static int32_t sha_disable_interrupt(void)
83 {
84 sha_reg->SHA_CON &= ~(1 << SHA_INT_ENABLE_OFFSET);
85 return 0;
86 }
87
sha_clear_interrupt(void)88 static void sha_clear_interrupt(void)
89 {
90 sha_reg->SHA_INTSTATE = 0;
91 }
92
sha_enable_initial(void)93 static int32_t sha_enable_initial(void)
94 {
95 sha_reg->SHA_CON |= 1 << SHA_INIT_OFFSET;
96 return 0;
97 }
98
sha_enable_calculate(void)99 static int32_t sha_enable_calculate(void)
100 {
101 sha_reg->SHA_CON |= 1 << SHA_CAL_OFFSET;
102 return 0;
103 }
104
sha_select_endian_mode(sha_endian_mode_e mode)105 static int32_t sha_select_endian_mode(sha_endian_mode_e mode)
106 {
107 sha_reg->SHA_CON |= mode << SHA_ENDIAN_OFFSET;
108 return 0;
109 }
110
sha_input_data(uint32_t * data,uint32_t length)111 static int32_t sha_input_data(uint32_t *data, uint32_t length)
112 {
113 uint8_t i;
114 uint32_t *input_data = (uint32_t *) & (sha_reg->SHA_DATA1);
115
116 for (i = 0; i < length; i++) {
117 *(input_data + i) = *(data + i);
118 }
119
120 return 0;
121 }
122
sha_get_data(sha_handle_t handle,uint32_t * data)123 static int32_t sha_get_data(sha_handle_t handle, uint32_t *data)
124 {
125 ck_sha_priv_t *sha_priv = handle;
126
127 uint8_t len;
128 uint8_t i;
129 uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
130 /* according to different mode to obtain the hash result */
131 if (sha_priv->mode == SHA_MODE_1 || sha_priv->mode == SHA_MODE_224 || sha_priv->mode == SHA_MODE_256) {
132 if (sha_priv->mode == SHA_MODE_1) {
133 len = 5;
134 } else if (sha_priv->mode == SHA_MODE_224) {
135 len = 7;
136 } else if (sha_priv->mode == SHA_MODE_256) {
137 len = 8;
138 }
139
140 for (i = 0; i < len; i++) {
141 data[i] = *(result + i);
142 }
143 } else {
144 if (sha_priv->mode == SHA_MODE_384) {
145 len = 6;
146 } else if (sha_priv->mode == SHA_MODE_512) {
147 len = 8;
148 }
149
150 uint32_t *resulth = (uint32_t *)&sha_reg->SHA_H0H;
151 for (i = 0; i < len; i++) {
152 data[i << 1] = *(resulth + i);
153 data[(i << 1) + 1] = *(result + i);
154 }
155 }
156
157 return 0;
158 }
159
sha_reverse_order(uint8_t * pdata,int32_t length)160 static inline void sha_reverse_order(uint8_t *pdata, int32_t length)
161 {
162 uint8_t input_data[length];
163 uint8_t result[length];
164 uint32_t tmp = 0;
165 int32_t i = 0;
166 memcpy((void *)input_data, (void *)pdata, length);
167
168 for (i = 0; i < length; i++) {
169 tmp = i >> 2;
170 tmp = tmp << 3;
171 result[i] = input_data[tmp + 3 - i];
172 }
173
174 memcpy((void *)pdata, (void *)result, length);
175 }
176
ck_sha_irqhandler(int32_t idx)177 void ck_sha_irqhandler(int32_t idx)
178 {
179 sha_int_flag = 0;
180 sha_clear_interrupt(); //clear sha interrupt
181
182 ck_sha_priv_t *sha_priv = &sha_handle[idx];
183 if (finish_flag != 0) {
184 if (sha_priv->cb != NULL) {
185 sha_priv->cb(SHA_EVENT_COMPLETE); //execute the callback function
186 }
187 }
188 }
189
target_get_sha_count(void)190 int32_t __attribute__((weak)) target_get_sha_count(void)
191 {
192 return 0;
193 }
194
target_get_sha(int32_t idx,uint32_t * base,uint32_t * irq)195 int32_t __attribute__((weak)) target_get_sha(int32_t idx, uint32_t *base, uint32_t *irq)
196 {
197 return NULL;
198 }
199
200 /**
201 \brief get sha handle count.
202 \return sha handle count
203 */
csi_sha_get_instance_count(void)204 int32_t csi_sha_get_instance_count(void)
205 {
206 return target_get_sha_count();
207 }
208
209 /**
210 \brief Initialize SHA Interface. 1. Initializes the resources needed for the SHA interface 2.registers event callback function
211 \param[in] idx must not exceed return value of csi_sha_get_instance_count()
212 \param[in] cb_event Pointer to \ref sha_event_cb_t
213 \return return sha handle if success
214 */
csi_sha_initialize(int32_t idx,sha_event_cb_t cb_event)215 sha_handle_t csi_sha_initialize(int32_t idx, sha_event_cb_t cb_event)
216 {
217
218 if (idx < 0 || idx >= CONFIG_SHA_NUM) {
219 return NULL;
220 }
221
222 uint32_t base = 0u;
223 uint32_t irq;
224 /* obtain the sha information */
225 int32_t real_idx = target_get_sha(idx, &base, &irq);
226
227 if (real_idx != idx) {
228 return NULL;
229 }
230
231 ck_sha_priv_t *sha_priv = &sha_handle[idx];
232
233 sha_priv->base = base;
234 sha_priv->irq = irq;
235
236 /* initialize the sha context */
237 sha_priv->cb = cb_event;
238 sha_priv->status.busy = 0;
239
240 drv_nvic_enable_irq(sha_priv->irq);
241
242 return (sha_handle_t)sha_priv;
243 }
244
245 /**
246 \brief De-initialize SHA Interface. stops operation and releases the software resources used by the interface
247 \param[in] handle sha handle to operate.
248 \return error code
249 */
csi_sha_uninitialize(sha_handle_t handle)250 int32_t csi_sha_uninitialize(sha_handle_t handle)
251 {
252 SHA_NULL_PARAM_CHK(handle);
253
254 ck_sha_priv_t *sha_priv = handle;
255 sha_priv->cb = NULL;
256
257 sha_disable_interrupt();
258 drv_nvic_disable_irq(sha_priv->irq);
259
260 return 0;
261 }
262
263 /**
264 \brief Get driver capabilities.
265 \param[in] handle sha handle to operate.
266 \return \ref sha_capabilities_t
267 */
csi_sha_get_capabilities(sha_handle_t handle)268 sha_capabilities_t csi_sha_get_capabilities(sha_handle_t handle)
269 {
270 return driver_capabilities;
271 }
272
273 /**
274 \brief config sha mode.
275 \param[in] handle sha handle to operate.
276 \param[in] mode \ref sha_mode_e
277 \param[in] endian \ref sha_endian_mode_e
278 \return error code
279 */
csi_sha_config(sha_handle_t handle,sha_mode_e mode,sha_endian_mode_e endian_mode)280 int32_t csi_sha_config(sha_handle_t handle, sha_mode_e mode, sha_endian_mode_e endian_mode)
281 {
282 SHA_NULL_PARAM_CHK(handle);
283
284 ck_sha_priv_t *sha_priv = handle;
285 sha_reg = (ck_sha_reg_t *)(sha_priv->base);
286
287 /* config the sha mode */
288 switch (mode) {
289 case SHA_MODE_512_256:
290 case SHA_MODE_512_224:
291 return ERR_SHA(EDRV_UNSUPPORTED);
292
293 case SHA_MODE_1:
294 case SHA_MODE_224:
295 case SHA_MODE_256:
296 case SHA_MODE_384:
297 case SHA_MODE_512:
298 sha_priv->mode = mode;
299 break;
300
301 default:
302 return ERR_SHA(EDRV_PARAMETER);
303 }
304
305 sha_set_mode(mode);
306
307 /*config the sha endian mode */
308 if (endian_mode == SHA_ENDIAN_MODE_LITTLE) {
309 sha_priv->endian = endian_mode;
310 sha_select_endian_mode(endian_mode);
311 } else if (endian_mode == SHA_ENDIAN_MODE_BIG) {
312 sha_priv->endian = endian_mode;
313 sha_select_endian_mode(endian_mode);
314 } else {
315 return ERR_SHA(EDRV_PARAMETER);
316 }
317
318 sha_enable_interrupt();
319
320 return 0;
321 }
322
323 /**
324 \brief start the engine
325 \param[in] handle sha handle to operate.
326 \param[in] context Pointer to the sha context.
327 \return error code
328 */
csi_sha_starts(sha_handle_t handle,void * context)329 int32_t csi_sha_starts(sha_handle_t handle, void *context)
330 {
331 SHA_NULL_PARAM_CHK(handle);
332
333 ck_sha_priv_t *sha_priv = handle;
334 sha_enable_initial();
335 sha_priv->status.busy = 1;
336
337 return 0;
338 }
339
340 /**
341 \brief updata the engine
342 \param[in] handle sha handle to operate.
343 \param[in] context Pointer to the sha context.
344 \param[in] input Pointer to the Source data
345 \param[in] len the data len
346 \return error code
347 */
348 static uint8_t sha_buffer[128];
349 static uint32_t total[2] = {0x0};
350 static uint32_t last_left = 0;
csi_sha_update(sha_handle_t handle,void * context,const void * input,uint32_t len)351 int32_t csi_sha_update(sha_handle_t handle, void *context, const void *input, uint32_t len)
352 {
353 SHA_NULL_PARAM_CHK(handle);
354 SHA_NULL_PARAM_CHK(input);
355 if (len <= 0) {
356 return ERR_SHA(EDRV_PARAMETER);
357 }
358
359 ck_sha_priv_t *sha_priv = handle;
360 sha_reg = (ck_sha_reg_t *)(sha_priv->base);
361
362 uint32_t block_size;
363 uint32_t left_len = 0;
364 if (sha_priv->mode < 4) {
365 block_size = 64;
366 left_len = len & 0x3f;
367 } else {
368 block_size = 128;
369 left_len = len & 0x7f;
370 }
371
372 uint32_t left = total[0] & (block_size - 1);
373 uint32_t fill = block_size - left;
374
375 total[0] += len;
376 total[0] &= 0xffffffff;
377 uint32_t word_left = total[0] & 0x3;
378
379 uint8_t *p = (uint8_t *)input;
380 /* when the text is not aligned by block and len > fill */
381 if (left && len >= fill) {
382 if (last_left && sha_priv->endian == SHA_ENDIAN_MODE_LITTLE) {
383 uint32_t i;
384 for (i = 0; i < 4 - last_left; i++) {
385 if (finish_flag) {
386 *(sha_buffer + 3 - last_left - i) = *((uint8_t *)p + 3 - last_left - i);
387 } else {
388 *(sha_buffer + left + 3 - last_left - i) = *((uint8_t *)p + 3 - last_left - i);
389 }
390 }
391
392 fill = fill - 4 + last_left;
393 p = (p + 4 - last_left);
394 }
395
396 if (last_left) {
397 memcpy((void *)(sha_buffer + left + 4 - last_left), p, fill);
398 } else {
399 memcpy((void *)(sha_buffer + left), p, fill);
400 }
401
402 /* set the input data */
403 sha_input_data((uint32_t *)sha_buffer, block_size >> 2);
404 sha_enable_calculate();
405
406 while (sha_int_flag);
407
408 sha_int_flag = 1;
409 p += fill;
410 len -= fill;
411 left = 0;
412 }
413
414 /* calculate the hash by block */
415 while (len >= block_size) {
416 sha_input_data((uint32_t *)p, block_size >> 2);
417 sha_enable_calculate();
418
419 while (sha_int_flag);
420
421 sha_int_flag = 1;
422 p += block_size;
423 len -= block_size;
424 }
425
426 /* when the text is not aligned by block and len < fill */
427 if (len > 0) {
428 if (sha_priv->endian == SHA_ENDIAN_MODE_BIG || word_left == 0) {
429 memcpy((void *)(sha_buffer + left), p, len);
430 } else {
431 memcpy((void *)(sha_buffer + left), p, len + 4 - word_left);
432 last_left = word_left;
433 }
434 }
435
436 sha_priv->status.busy = 0;
437
438 return 0;
439 }
440
441 static unsigned char sha_padding[128] = {
442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
446 };
447
448 /**
449 \brief finish the engine
450 \param[in] handle sha handle to operate.
451 \param[in] context Pointer to the sha context.
452 \param[out] output Pointer to the dest data
453 \return error code
454 */
455 static uint32_t total_length;
csi_sha_finish(sha_handle_t handle,void * context,void * output)456 int32_t csi_sha_finish(sha_handle_t handle, void *context, void *output)
457 {
458 SHA_NULL_PARAM_CHK(handle);
459 SHA_NULL_PARAM_CHK(output);
460
461 ck_sha_priv_t *sha_priv = handle;
462 uint32_t block_size;
463 if (sha_priv->mode < 4) {
464 block_size = 64;
465 } else {
466 block_size = 128;
467 }
468
469 total_length = total[0] << 3;
470 uint32_t last = total[0] & (block_size - 1);
471 uint32_t padn = (last < block_size) ? (block_size - last) : (block_size + block_size - last);
472
473 uint32_t left = total[0] & 0x3;
474
475 uint8_t temp_data[4];
476 uint32_t j;
477 /*calculate the final word*/
478 for (j = 0; j < 4; j++) {
479 temp_data[j] = (total_length >> (8 * j)) & 0xff;
480 }
481
482 /* group the final package according to the endian mode */
483 if (sha_priv->endian == SHA_ENDIAN_MODE_BIG) {
484 memset(sha_padding, 0x0, sizeof(sha_padding));
485 sha_padding[0] = 0x80;
486
487 for (j = 0; j < 4; j++) {
488 sha_padding[padn - 4 + j] = temp_data[3 - j];
489 }
490 } else {
491 memset(sha_padding, 0x0, sizeof(sha_padding));
492 sha_padding[3 - left] = 0x80;
493
494 for (j = 0; j < 4; j++) {
495 sha_padding[padn - 4 + j] = temp_data[j];
496 }
497 }
498
499 finish_flag = 1;
500
501 csi_sha_update(handle, NULL, sha_padding, padn);
502
503 /* get the hash result */
504 sha_get_data(handle, (uint32_t *)output);
505
506 uint8_t *p = output;
507 /* convert the data endian according the sha mode */
508 if (sha_priv->mode == SHA_MODE_1) {
509 sha_reverse_order(p, 20);
510 } else if (sha_priv->mode == SHA_MODE_224) {
511 sha_reverse_order(p, 28);
512 } else if (sha_priv->mode == SHA_MODE_256) {
513 sha_reverse_order(p, 32);
514 } else if (sha_priv->mode == SHA_MODE_512) {
515 sha_reverse_order(p, 64);
516 } else if (sha_priv->mode == SHA_MODE_384) {
517 sha_reverse_order(p, 48);
518 }
519
520 total[0] = 0;
521 memset(sha_buffer, 0, sizeof(sha_buffer));
522 memset(sha_padding, 0, sizeof(sha_padding));
523 last_left = 0;
524 finish_flag = 0;
525
526 return 0;
527 }
528
529 /**
530 \brief Get SHA status.
531 \param[in] handle sha handle to operate.
532 \return SHA status \ref sha_status_t
533 */
csi_sha_get_status(sha_handle_t handle)534 sha_status_t csi_sha_get_status(sha_handle_t handle)
535 {
536 ck_sha_priv_t *sha_priv = handle;
537 return sha_priv->status;
538 }
539