1 /*!
2  * @file        apm32f4xx_hash_md5.c
3  *
4  * @brief       This file provides high level functions to compute the HASH MD5 and
5  *              HMAC MD5 Digest of an input message.
6  *
7  * @version     V1.0.2
8  *
9  * @date        2022-06-23
10  *
11  * @attention
12  *
13  *  Copyright (C) 2021-2022 Geehy Semiconductor
14  *
15  *  You may not use this file except in compliance with the
16  *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
17  *
18  *  The program is only for reference, which is distributed in the hope
19  *  that it will be usefull and instructional for customers to develop
20  *  their software. Unless required by applicable law or agreed to in
21  *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
22  *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
23  *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
24  *  and limitations under the License.
25  */
26 
27 
28 #include "apm32f4xx_hash.h"
29 
30 /** @addtogroup APM32F4xx_StdPeriphDriver
31   @{
32 */
33 
34 /** @defgroup HASH_MD5_Driver
35   * @brief HASH MD5 driver modules
36   @{
37 */
38 
39 /** @defgroup HASH_MD5_Functions
40   @{
41 */
42 
43 /** @defgroup HASH_MD5_Macros Macros
44   @{
45 */
46 
47 /* HASH MD5 timeout definition */
48 #define MD5_BUSY_TIMEOUT    ((uint32_t) 0x00010000)
49 
50 /**@} end of group HASH_MD5_Macros*/
51 
52 /*!
53  * @brief     Compute the HASH MD5 digest
54  *
55  * @param     inBuffer: pointer to the input buffer to be treated
56  *
57  * @param     lenBuffer: length of the input buffer.
58  *
59  * @param     outBuffer: the returned digest.
60  *
61  * @retval    An ErrorStatus enumeration value:
62  *            SUCCESS: digest computation done
63  *            ERROR: digest computation failed
64  *
65  */
HASH_ComputeMD5(uint8_t * inBuffer,uint32_t lenBuffer,uint8_t outBuffer[16])66 uint8_t HASH_ComputeMD5(uint8_t *inBuffer, uint32_t lenBuffer,
67                         uint8_t outBuffer[16])
68 {
69     HASH_Config_T hashMD5Config;
70     HASH_MessageDigest_T hashMD5MessageDigest;
71     uint16_t nuValidBits = 0;
72     uint32_t m = 0;
73     uint32_t inBufferaddr  = (uint32_t)inBuffer;
74     uint32_t outBufferaddr = (uint32_t)outBuffer;
75 
76     nuValidBits = 8 * (lenBuffer % 4);
77 
78     HASH_Reset();
79 
80     /* HASH Configuration */
81     hashMD5Config.algoSelect = HASH_ALGO_SELECTION_MD5;
82     hashMD5Config.algoMode = HASH_ALGO_MODE_HASH;
83     hashMD5Config.dataType = HASH_DATA_TYPE_8B;
84     HASH_Config(&hashMD5Config);
85 
86     /* Configure the number of valid bits in last word of the data */
87     HASH_ConfigLastWordValidBitsNbr(nuValidBits);
88 
89     /* Write the input block in the IN FIFO */
90     for (m = 0; m < lenBuffer; m += 4)
91     {
92         HASH_WritesInputData(*(uint32_t *)inBufferaddr);
93         inBufferaddr += 4;
94     }
95 
96     /* Start the HASH processor */
97     HASH_StartDigest();
98 
99     /* wait until the Busy flag is RESET */
100     if (HASH_WaitForCompute(MD5_BUSY_TIMEOUT) != 0)
101     {
102         return ERROR;
103     }
104     else
105     {
106         /* Read the message digest */
107         HASH_ReadDigest(&hashMD5MessageDigest);
108 
109         *(uint32_t *)(outBufferaddr)  = __REV(hashMD5MessageDigest.Data[0]);
110 
111         outBufferaddr += 4;
112         *(uint32_t *)(outBufferaddr)  = __REV(hashMD5MessageDigest.Data[1]);
113 
114         outBufferaddr += 4;
115         *(uint32_t *)(outBufferaddr)  = __REV(hashMD5MessageDigest.Data[2]);
116 
117         outBufferaddr += 4;
118         *(uint32_t *)(outBufferaddr)  = __REV(hashMD5MessageDigest.Data[3]);
119     }
120 
121     return SUCCESS;
122 }
123 
124 /*!
125  * @brief     Compute the HMAC MD5 digest
126  *
127  * @param     key: pointer to the Key used for HMAC
128  *
129  * @param     lenkey: length of the Key used for HMAC
130  *
131  * @param     inBuffer: pointer to the Input buffer to be treated
132  *
133  * @param     lenBuffer: length of the Input buffer
134  *
135  * @param     outBuffer: the returned digest
136  *
137  * @retval    An ErrorStatus enumeration value:
138  *            SUCCESS: digest computation done
139  *            ERROR: digest computation failed
140  *
141  */
HMAC_ComputeMD5(uint8_t * key,uint32_t keylen,uint8_t * inBuffer,uint32_t lenBuffer,uint8_t outBuffer[16])142 uint8_t HMAC_ComputeMD5(uint8_t *key, uint32_t keylen, uint8_t *inBuffer,
143                         uint32_t lenBuffer, uint8_t outBuffer[16])
144 {
145     HASH_Config_T hmacMD5Config;
146     HASH_MessageDigest_T hmacMD5MessageDigest;
147     uint16_t nuValidBits = 0;
148     uint16_t nuValidKey = 0;
149     uint32_t m = 0;
150     uint32_t keyaddr    = (uint32_t)key;
151     uint32_t inBufferaddr  = (uint32_t)inBuffer;
152     uint32_t outBufferaddr = (uint32_t)outBuffer;
153 
154     nuValidBits = 8 * (lenBuffer % 4);
155     nuValidKey = 8 * (keylen % 4);
156 
157     HASH_Reset();
158 
159     /* HASH Configuration */
160     hmacMD5Config.algoSelect = HASH_ALGO_SELECTION_MD5;
161     hmacMD5Config.algoMode = HASH_ALGO_MODE_HMAC;
162     hmacMD5Config.dataType = HASH_DATA_TYPE_8B;
163 
164     if (keylen > 64)
165     {
166         hmacMD5Config.hmacKeyType = HASH_HMAC_KEY_TYPE_LONGKEY;
167     }
168     else
169     {
170         hmacMD5Config.hmacKeyType = HASH_HMAC_KEY_TYPE_SHORTKEY;
171     }
172 
173     HASH_Config(&hmacMD5Config);
174     HASH_ConfigLastWordValidBitsNbr(nuValidKey);
175 
176     for (m = 0; m < keylen; m += 4)
177     {
178         HASH_WritesInputData(*(uint32_t *)keyaddr);
179         keyaddr += 4;
180     }
181 
182     /* Start the HASH processor */
183     HASH_StartDigest();
184 
185     /* wait until the Busy flag is RESET */
186     if (HASH_WaitForCompute(MD5_BUSY_TIMEOUT) != 0)
187     {
188         return ERROR;
189     }
190     else
191     {
192         /* Configure the number of valid bits in last word of the input data */
193         HASH_ConfigLastWordValidBitsNbr(nuValidBits);
194 
195         /* Write the input block in the IN FIFO */
196         for (m = 0; m < lenBuffer; m += 4)
197         {
198             HASH_WritesInputData(*(uint32_t *)inBufferaddr);
199             inBufferaddr += 4;
200         }
201 
202         /* Start the HASH processor */
203         HASH_StartDigest();
204 
205         /* wait until the Busy flag is RESET */
206         if (HASH_WaitForCompute(MD5_BUSY_TIMEOUT) != 0)
207         {
208             return ERROR;
209         }
210         else
211         {
212             HASH_ConfigLastWordValidBitsNbr(nuValidKey);
213             keyaddr = (uint32_t)key;
214 
215             for (m = 0; m < keylen; m += 4)
216             {
217                 HASH_WritesInputData(*(uint32_t *)keyaddr);
218                 keyaddr += 4;
219             }
220 
221             /* Start the HASH processor */
222             HASH_StartDigest();
223 
224             /* wait until the Busy flag is RESET */
225             if (HASH_WaitForCompute(MD5_BUSY_TIMEOUT) != 0)
226             {
227                 return ERROR;
228             }
229             else
230             {
231                 /* Read the message digest */
232                 HASH_ReadDigest(&hmacMD5MessageDigest);
233 
234                 *(uint32_t *)(outBufferaddr)  = __REV(hmacMD5MessageDigest.Data[0]);
235 
236                 outBufferaddr += 4;
237                 *(uint32_t *)(outBufferaddr)  = __REV(hmacMD5MessageDigest.Data[1]);
238 
239                 outBufferaddr += 4;
240                 *(uint32_t *)(outBufferaddr)  = __REV(hmacMD5MessageDigest.Data[2]);
241 
242                 outBufferaddr += 4;
243                 *(uint32_t *)(outBufferaddr)  = __REV(hmacMD5MessageDigest.Data[3]);
244             }
245         }
246     }
247 
248     return SUCCESS;
249 }
250 
251 /**@} end of group HASH_MD5_Functions */
252 /**@} end of group HASH_MD5_Driver */
253 /**@} end of group APM32F4xx_StdPeriphDriver */
254