1 /*!
2     \file    gd32l23x_cau_tdes.c
3     \brief   CAU TDES driver
4 
5     \version 2021-08-04, V1.0.0, firmware for GD32L23x
6 */
7 
8 /*
9     Copyright (c) 2021, GigaDevice Semiconductor Inc.
10 
11     Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13 
14     1. Redistributions of source code must retain the above copyright notice, this
15        list of conditions and the following disclaimer.
16     2. Redistributions in binary form must reproduce the above copyright notice,
17        this list of conditions and the following disclaimer in the documentation
18        and/or other materials provided with the distribution.
19     3. Neither the name of the copyright holder nor the names of its contributors
20        may be used to endorse or promote products derived from this software without
21        specific prior written permission.
22 
23     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34 
35 #include "gd32l23x_cau.h"
36 
37 #define TDESBSY_TIMEOUT    ((uint32_t)0x00010000U)
38 
39 /* TDES calculate process */
40 static ErrStatus cau_tdes_calculate(uint8_t *input, uint32_t in_length, uint8_t *output);
41 
42 /*!
43     \brief      encrypt and decrypt using TDES in ECB mode
44     \param[in]  cau_parameter: pointer to the input structure
45                   alg_dir: algorithm dirctory
46                     CAU_ENCRYPT, CAU_DECRYPT
47                   key: key, 24 bytes
48                   input: input data
49                   in_length: input data length in bytes, must be a multiple of 8 bytes
50     \param[out] output: pointer to the output structure
51     \retval     ErrStatus: SUCCESS or ERROR
52 */
cau_tdes_ecb(cau_parameter_struct * cau_parameter,uint8_t * output)53 ErrStatus cau_tdes_ecb(cau_parameter_struct *cau_parameter, uint8_t *output)
54 {
55     ErrStatus ret = ERROR;
56     cau_key_parameter_struct key_initpara;
57     uint32_t keyaddr    = (uint32_t)(cau_parameter->key);
58     uint32_t inputaddr  = (uint32_t)(cau_parameter->input);
59     uint32_t outputaddr = (uint32_t)output;
60 
61     /* key structure initialization */
62     cau_key_struct_para_init(&key_initpara);
63     /* initialize the CAU peripheral */
64     cau_init(cau_parameter->alg_dir, CAU_MODE_TDES_ECB, CAU_SWAPPING_8BIT);
65 
66     /* key initialization */
67     key_initpara.key_1_high = __REV(*(uint32_t *)(keyaddr));
68     keyaddr += 4U;
69     key_initpara.key_1_low  = __REV(*(uint32_t *)(keyaddr));
70     keyaddr += 4U;
71     key_initpara.key_2_high = __REV(*(uint32_t *)(keyaddr));
72     keyaddr += 4U;
73     key_initpara.key_2_low  = __REV(*(uint32_t *)(keyaddr));
74     keyaddr += 4U;
75     key_initpara.key_3_high = __REV(*(uint32_t *)(keyaddr));
76     keyaddr += 4U;
77     key_initpara.key_3_low  = __REV(*(uint32_t *)(keyaddr));
78     cau_key_init(&key_initpara);
79 
80     /* flush the IN and OUT FIFOs */
81     cau_fifo_flush();
82 
83     /* enable the CAU peripheral */
84     cau_enable();
85     /* TDES calculate process */
86     ret = cau_tdes_calculate((uint8_t *)inputaddr, cau_parameter->in_length, (uint8_t *)outputaddr);
87     /* disable the CAU peripheral */
88     cau_disable();
89 
90     return ret;
91 }
92 
93 /*!
94     \brief      encrypt and decrypt using TDES in CBC mode
95     \param[in]  cau_parameter: pointer to the input structure
96                   alg_dir: algorithm dirctory
97                     CAU_ENCRYPT, CAU_DECRYPT
98                   key: key, 24 bytes
99                   iv: initialization vector, 8 bytes
100                   input: input data
101                   in_length: input data length in bytes, must be a multiple of 8 bytes
102     \param[out] output: pointer to the output structure
103     \retval     ErrStatus: SUCCESS or ERROR
104 */
cau_tdes_cbc(cau_parameter_struct * cau_parameter,uint8_t * output)105 ErrStatus cau_tdes_cbc(cau_parameter_struct *cau_parameter, uint8_t *output)
106 {
107     ErrStatus ret = ERROR;
108     cau_key_parameter_struct key_initpara;
109     cau_iv_parameter_struct iv_initpara;
110     uint32_t keyaddr    = (uint32_t)(cau_parameter->key);
111     uint32_t inputaddr  = (uint32_t)(cau_parameter->input);
112     uint32_t outputaddr = (uint32_t)output;
113     uint32_t ivaddr     = (uint32_t)(cau_parameter->iv);
114 
115     /* key structure initialization */
116     cau_key_struct_para_init(&key_initpara);
117     /* initialize the CAU peripheral */
118     cau_init(cau_parameter->alg_dir, CAU_MODE_TDES_CBC, CAU_SWAPPING_8BIT);
119 
120     /* key initialization */
121     key_initpara.key_1_high = __REV(*(uint32_t *)(keyaddr));
122     keyaddr += 4U;
123     key_initpara.key_1_low  = __REV(*(uint32_t *)(keyaddr));
124     keyaddr += 4U;
125     key_initpara.key_2_high = __REV(*(uint32_t *)(keyaddr));
126     keyaddr += 4U;
127     key_initpara.key_2_low  = __REV(*(uint32_t *)(keyaddr));
128     keyaddr += 4U;
129     key_initpara.key_3_high = __REV(*(uint32_t *)(keyaddr));
130     keyaddr += 4U;
131     key_initpara.key_3_low  = __REV(*(uint32_t *)(keyaddr));
132     cau_key_init(&key_initpara);
133 
134     /* vectors initialization */
135     iv_initpara.iv_0_high = __REV(*(uint32_t *)(ivaddr));
136     ivaddr += 4U;
137     iv_initpara.iv_0_low  = __REV(*(uint32_t *)(ivaddr));
138     cau_iv_init(&iv_initpara);
139 
140     /* flush the IN and OUT FIFOs */
141     cau_fifo_flush();
142     /* enable the CAU peripheral */
143     cau_enable();
144     /* TDES calculate process */
145     ret = cau_tdes_calculate((uint8_t *)inputaddr, cau_parameter->in_length, (uint8_t *)outputaddr);
146     /* disable the CAU peripheral */
147     cau_disable();
148 
149     return ret;
150 }
151 
152 /*!
153     \brief      TDES calculate process
154     \param[in]  input: pointer to the input buffer
155     \param[in]  in_length: length of the input buffer in bytes, must be a multiple of 8 bytes
156     \param[out] output: pointer to the returned buffer
157     \retval     ErrStatus: SUCCESS or ERROR
158 */
cau_tdes_calculate(uint8_t * input,uint32_t in_length,uint8_t * output)159 static ErrStatus cau_tdes_calculate(uint8_t *input, uint32_t in_length, uint8_t *output)
160 {
161     uint32_t inputaddr  = (uint32_t)input;
162     uint32_t outputaddr = (uint32_t)output;
163     uint32_t i = 0U;
164     __IO uint32_t counter = 0U;
165     uint32_t busystatus = 0U;
166 
167     /* the clock is not enabled or there is no embeded CAU peripheral */
168     if(DISABLE == cau_enable_state_get()) {
169         return ERROR;
170     }
171 
172     for(i = 0U; i < in_length; i += 8U) {
173         /* write data to the IN FIFO */
174         cau_data_write(*(uint32_t *)(inputaddr));
175         inputaddr += 4U;
176         cau_data_write(*(uint32_t *)(inputaddr));
177         inputaddr += 4U;
178 
179         /* wait until the complete message has been processed */
180         counter = 0U;
181         do {
182             busystatus = cau_flag_get(CAU_FLAG_BUSY);
183             counter++;
184         } while((TDESBSY_TIMEOUT != counter) && (RESET != busystatus));
185 
186         if(RESET != busystatus) {
187             return ERROR;
188         } else {
189             /* read the output block from the output FIFO */
190             *(uint32_t *)(outputaddr) = cau_data_read();
191             outputaddr += 4U;
192             *(uint32_t *)(outputaddr) = cau_data_read();
193             outputaddr += 4U;
194         }
195     }
196 
197     return SUCCESS;
198 }
199