1 /**
2   ******************************************************************************
3   * @file    stm32f4xx_hash_md5.c
4   * @author  MCD Application Team
5   * @version V1.6.1
6   * @date    21-October-2015
7   * @brief   This file provides high level functions to compute the HASH MD5 and
8   *          HMAC MD5 Digest of an input message.
9   *          It uses the stm32f4xx_hash.c/.h drivers to access the STM32F4xx HASH
10   *          peripheral.
11   *
12 @verbatim
13  ===================================================================
14                   ##### How to use this driver #####
15  ===================================================================
16  [..]
17    (#) Enable The HASH controller clock using
18        RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_HASH, ENABLE); function.
19 
20    (#) Calculate the HASH MD5 Digest using HASH_MD5() function.
21 
22    (#) Calculate the HMAC MD5 Digest using HMAC_MD5() function.
23 
24 @endverbatim
25   *
26   ******************************************************************************
27   * @attention
28   *
29   * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
30   *
31   * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
32   * You may not use this file except in compliance with the License.
33   * You may obtain a copy of the License at:
34   *
35   *        http://www.st.com/software_license_agreement_liberty_v2
36   *
37   * Unless required by applicable law or agreed to in writing, software
38   * distributed under the License is distributed on an "AS IS" BASIS,
39   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40   * See the License for the specific language governing permissions and
41   * limitations under the License.
42   *
43   ******************************************************************************
44   */
45 
46 /* Includes ------------------------------------------------------------------*/
47 #include "stm32f4xx_hash.h"
48 
49 /** @addtogroup STM32F4xx_StdPeriph_Driver
50   * @{
51   */
52 
53 /** @defgroup HASH
54   * @brief HASH driver modules
55   * @{
56   */
57 
58 /* Private typedef -----------------------------------------------------------*/
59 /* Private define ------------------------------------------------------------*/
60 #define MD5BUSY_TIMEOUT    ((uint32_t) 0x00010000)
61 
62 /* Private macro -------------------------------------------------------------*/
63 /* Private variables ---------------------------------------------------------*/
64 /* Private function prototypes -----------------------------------------------*/
65 /* Private functions ---------------------------------------------------------*/
66 
67 /** @defgroup HASH_Private_Functions
68   * @{
69   */
70 
71 /** @defgroup HASH_Group7 High Level MD5 functions
72  *  @brief   High Level MD5 Hash and HMAC functions
73  *
74 @verbatim
75  ===============================================================================
76               ##### High Level MD5 Hash and HMAC functions #####
77  ===============================================================================
78 
79 
80 @endverbatim
81   * @{
82   */
83 
84 /**
85   * @brief  Compute the HASH MD5 digest.
86   * @param  Input: pointer to the Input buffer to be treated.
87   * @param  Ilen: length of the Input buffer.
88   * @param  Output: the returned digest
89   * @retval An ErrorStatus enumeration value:
90   *          - SUCCESS: digest computation done
91   *          - ERROR: digest computation failed
92   */
HASH_MD5(uint8_t * Input,uint32_t Ilen,uint8_t Output[16])93 ErrorStatus HASH_MD5(uint8_t *Input, uint32_t Ilen, uint8_t Output[16])
94 {
95   HASH_InitTypeDef MD5_HASH_InitStructure;
96   HASH_MsgDigest MD5_MessageDigest;
97   __IO uint16_t nbvalidbitsdata = 0;
98   uint32_t i = 0;
99   __IO uint32_t counter = 0;
100   uint32_t busystatus = 0;
101   ErrorStatus status = SUCCESS;
102   uint32_t inputaddr  = (uint32_t)Input;
103   uint32_t outputaddr = (uint32_t)Output;
104 
105 
106   /* Number of valid bits in last word of the Input data */
107   nbvalidbitsdata = 8 * (Ilen % 4);
108 
109   /* HASH peripheral initialization */
110   HASH_DeInit();
111 
112   /* HASH Configuration */
113   MD5_HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_MD5;
114   MD5_HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HASH;
115   MD5_HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
116   HASH_Init(&MD5_HASH_InitStructure);
117 
118   /* Configure the number of valid bits in last word of the data */
119   HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
120 
121   /* Write the Input block in the IN FIFO */
122   for(i=0; i<Ilen; i+=4)
123   {
124     HASH_DataIn(*(uint32_t*)inputaddr);
125     inputaddr+=4;
126   }
127 
128   /* Start the HASH processor */
129   HASH_StartDigest();
130 
131   /* wait until the Busy flag is RESET */
132   do
133   {
134     busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
135     counter++;
136   }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));
137 
138   if (busystatus != RESET)
139   {
140      status = ERROR;
141   }
142   else
143   {
144     /* Read the message digest */
145     HASH_GetDigest(&MD5_MessageDigest);
146     *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[0]);
147     outputaddr+=4;
148     *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[1]);
149     outputaddr+=4;
150     *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[2]);
151     outputaddr+=4;
152     *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[3]);
153   }
154   return status;
155 }
156 
157 /**
158   * @brief  Compute the HMAC MD5 digest.
159   * @param  Key: pointer to the Key used for HMAC.
160   * @param  Keylen: length of the Key used for HMAC.
161   * @param  Input: pointer to the Input buffer to be treated.
162   * @param  Ilen: length of the Input buffer.
163   * @param  Output: the returned digest
164   * @retval An ErrorStatus enumeration value:
165   *          - SUCCESS: digest computation done
166   *          - ERROR: digest computation failed
167   */
HMAC_MD5(uint8_t * Key,uint32_t Keylen,uint8_t * Input,uint32_t Ilen,uint8_t Output[16])168 ErrorStatus HMAC_MD5(uint8_t *Key, uint32_t Keylen, uint8_t *Input,
169                      uint32_t Ilen, uint8_t Output[16])
170 {
171   HASH_InitTypeDef MD5_HASH_InitStructure;
172   HASH_MsgDigest MD5_MessageDigest;
173   __IO uint16_t nbvalidbitsdata = 0;
174   __IO uint16_t nbvalidbitskey = 0;
175   uint32_t i = 0;
176   __IO uint32_t counter = 0;
177   uint32_t busystatus = 0;
178   ErrorStatus status = SUCCESS;
179   uint32_t keyaddr    = (uint32_t)Key;
180   uint32_t inputaddr  = (uint32_t)Input;
181   uint32_t outputaddr = (uint32_t)Output;
182 
183   /* Number of valid bits in last word of the Input data */
184   nbvalidbitsdata = 8 * (Ilen % 4);
185 
186   /* Number of valid bits in last word of the Key */
187   nbvalidbitskey = 8 * (Keylen % 4);
188 
189   /* HASH peripheral initialization */
190   HASH_DeInit();
191 
192   /* HASH Configuration */
193   MD5_HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_MD5;
194   MD5_HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HMAC;
195   MD5_HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
196   if(Keylen > 64)
197   {
198     /* HMAC long Key */
199     MD5_HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_LongKey;
200   }
201   else
202   {
203     /* HMAC short Key */
204     MD5_HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_ShortKey;
205   }
206   HASH_Init(&MD5_HASH_InitStructure);
207 
208   /* Configure the number of valid bits in last word of the Key */
209   HASH_SetLastWordValidBitsNbr(nbvalidbitskey);
210 
211   /* Write the Key */
212   for(i=0; i<Keylen; i+=4)
213   {
214     HASH_DataIn(*(uint32_t*)keyaddr);
215     keyaddr+=4;
216   }
217 
218   /* Start the HASH processor */
219   HASH_StartDigest();
220 
221   /* wait until the Busy flag is RESET */
222   do
223   {
224     busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
225     counter++;
226   }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));
227 
228   if (busystatus != RESET)
229   {
230      status = ERROR;
231   }
232   else
233   {
234     /* Configure the number of valid bits in last word of the Input data */
235     HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
236 
237     /* Write the Input block in the IN FIFO */
238     for(i=0; i<Ilen; i+=4)
239     {
240       HASH_DataIn(*(uint32_t*)inputaddr);
241       inputaddr+=4;
242     }
243 
244     /* Start the HASH processor */
245     HASH_StartDigest();
246 
247     /* wait until the Busy flag is RESET */
248     counter =0;
249     do
250     {
251        busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
252        counter++;
253     }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));
254 
255     if (busystatus != RESET)
256     {
257       status = ERROR;
258     }
259     else
260     {
261       /* Configure the number of valid bits in last word of the Key */
262       HASH_SetLastWordValidBitsNbr(nbvalidbitskey);
263 
264       /* Write the Key */
265       keyaddr = (uint32_t)Key;
266       for(i=0; i<Keylen; i+=4)
267       {
268         HASH_DataIn(*(uint32_t*)keyaddr);
269         keyaddr+=4;
270       }
271 
272        /* Start the HASH processor */
273        HASH_StartDigest();
274 
275        /* wait until the Busy flag is RESET */
276        counter =0;
277        do
278        {
279           busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
280           counter++;
281       }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));
282 
283       if (busystatus != RESET)
284       {
285          status = ERROR;
286       }
287       else
288       {
289          /* Read the message digest */
290          HASH_GetDigest(&MD5_MessageDigest);
291          *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[0]);
292          outputaddr+=4;
293          *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[1]);
294          outputaddr+=4;
295          *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[2]);
296          outputaddr+=4;
297          *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[3]);
298       }
299     }
300   }
301   return status;
302 }
303 /**
304   * @}
305   */
306 
307 /**
308   * @}
309   */
310 
311 /**
312   * @}
313   */
314 
315 /**
316   * @}
317   */
318 
319 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
320 
321