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