+#ifdef FREESCALE_MMCAU
+ #include "cau_api.h"
+ #define XTRANSFORM(S,B) cau_md5_hash_n((B), 1, (unsigned char*)(S)->digest)
+#else
+ #define XTRANSFORM(S,B) Transform((S))
+#endif
+
+
+#ifdef STM32F2_HASH
+ /*
+ * STM32F2 hardware MD5 support through the STM32F2 standard peripheral
+ * library. Documentation located in STM32F2xx Standard Peripheral Library
+ * document (See note in README).
+ */
+ #include "stm32f2xx.h"
+
+ void InitMd5(Md5* md5)
+ {
+ /* STM32F2 struct notes:
+ * md5->buffer = first 4 bytes used to hold partial block if needed
+ * md5->buffLen = num bytes currently stored in md5->buffer
+ * md5->loLen = num bytes that have been written to STM32 FIFO
+ */
+ XMEMSET(md5->buffer, 0, MD5_REG_SIZE);
+
+ md5->buffLen = 0;
+ md5->loLen = 0;
+
+ /* initialize HASH peripheral */
+ HASH_DeInit();
+
+ /* configure algo used, algo mode, datatype */
+ HASH->CR &= ~ (HASH_CR_ALGO | HASH_CR_DATATYPE | HASH_CR_MODE);
+ HASH->CR |= (HASH_AlgoSelection_MD5 | HASH_AlgoMode_HASH
+ | HASH_DataType_8b);
+
+ /* reset HASH processor */
+ HASH->CR |= HASH_CR_INIT;
+ }
+
+ void Md5Update(Md5* md5, const byte* data, word32 len)
+ {
+ word32 i = 0;
+ word32 fill = 0;
+ word32 diff = 0;
+
+ /* if saved partial block is available */
+ if (md5->buffLen > 0) {
+ fill = 4 - md5->buffLen;
+
+ /* if enough data to fill, fill and push to FIFO */
+ if (fill <= len) {
+ XMEMCPY((byte*)md5->buffer + md5->buffLen, data, fill);
+ HASH_DataIn(*(uint32_t*)md5->buffer);
+
+ data += fill;
+ len -= fill;
+ md5->loLen += 4;
+ md5->buffLen = 0;
+ } else {
+ /* append partial to existing stored block */
+ XMEMCPY((byte*)md5->buffer + md5->buffLen, data, len);
+ md5->buffLen += len;
+ return;
+ }
+ }
+
+ /* write input block in the IN FIFO */
+ for (i = 0; i < len; i += 4)
+ {
+ diff = len - i;
+ if (diff < 4) {
+ /* store incomplete last block, not yet in FIFO */
+ XMEMSET(md5->buffer, 0, MD5_REG_SIZE);
+ XMEMCPY((byte*)md5->buffer, data, diff);
+ md5->buffLen = diff;
+ } else {
+ HASH_DataIn(*(uint32_t*)data);
+ data+=4;
+ }
+ }
+
+ /* keep track of total data length thus far */
+ md5->loLen += (len - md5->buffLen);
+ }
+
+ void Md5Final(Md5* md5, byte* hash)
+ {
+ __IO uint16_t nbvalidbitsdata = 0;
+
+ /* finish reading any trailing bytes into FIFO */
+ if (md5->buffLen > 0) {
+ HASH_DataIn(*(uint32_t*)md5->buffer);
+ md5->loLen += md5->buffLen;
+ }
+
+ /* calculate number of valid bits in last word of input data */
+ nbvalidbitsdata = 8 * (md5->loLen % MD5_REG_SIZE);
+
+ /* configure number of valid bits in last word of the data */
+ HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);
+
+ /* start HASH processor */
+ HASH_StartDigest();
+
+ /* wait until Busy flag == RESET */
+ while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET) {}
+
+ /* read message digest */
+ md5->digest[0] = HASH->HR[0];
+ md5->digest[1] = HASH->HR[1];
+ md5->digest[2] = HASH->HR[2];
+ md5->digest[3] = HASH->HR[3];
+
+ ByteReverseWords(md5->digest, md5->digest, MD5_DIGEST_SIZE);
+
+ XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE);
+
+ InitMd5(md5); /* reset state */
+ }
+
+#else /* CTaoCrypt software implementation */