From a7e0f4e4830ea275239961c8e07ae4f6a5fdd9bf Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 26 Dec 2012 15:16:39 -0700 Subject: [PATCH] add STM32F2 SHA1, MD5 support --- ctaocrypt/src/md5.c | 116 ++++++++++++++++++++++++++++++++++++++++ ctaocrypt/src/misc.c | 2 + ctaocrypt/src/sha.c | 117 +++++++++++++++++++++++++++++++++++++++++ cyassl/ctaocrypt/md5.h | 3 ++ cyassl/ctaocrypt/sha.h | 3 ++ 5 files changed, 241 insertions(+) diff --git a/ctaocrypt/src/md5.c b/ctaocrypt/src/md5.c index f735c74d2..13bee81bd 100644 --- a/ctaocrypt/src/md5.c +++ b/ctaocrypt/src/md5.c @@ -33,6 +33,120 @@ #endif +#ifdef STM32F2_CRYPTO + /* + * 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 */ + #ifndef min static INLINE word32 min(word32 a, word32 b) @@ -224,3 +338,5 @@ void Md5Final(Md5* md5, byte* hash) InitMd5(md5); /* reset state */ } +#endif /* STM32F2_CRYPTO */ + diff --git a/ctaocrypt/src/misc.c b/ctaocrypt/src/misc.c index 91aa8a1dc..60d84de19 100644 --- a/ctaocrypt/src/misc.c +++ b/ctaocrypt/src/misc.c @@ -76,6 +76,8 @@ STATIC INLINE word32 ByteReverseWord32(word32 value) #ifdef PPC_INTRINSICS /* PPC: load reverse indexed instruction */ return (word32)__lwbrx(&value,0); +#elif defined(KEIL_INTRINSICS) + return (word32)__rev(value); #elif defined(FAST_ROTATE) /* 5 instructions with rotate instruction, 9 without */ return (rotrFixed(value, 8U) & 0xff00ff00) | diff --git a/ctaocrypt/src/sha.c b/ctaocrypt/src/sha.c index 7347fbd40..725760d19 100644 --- a/ctaocrypt/src/sha.c +++ b/ctaocrypt/src/sha.c @@ -31,6 +31,121 @@ #endif +#ifdef STM32F2_CRYPTO + /* + * STM32F2 hardware SHA1 support through the STM32F2 standard peripheral + * library. Documentation located in STM32F2xx Standard Peripheral Library + * document (See note in README). + */ + #include "stm32f2xx.h" + + void InitSha(Sha* sha) + { + /* STM32F2 struct notes: + * sha->buffer = first 4 bytes used to hold partial block if needed + * sha->buffLen = num bytes currently stored in sha->buffer + * sha->loLen = num bytes that have been written to STM32 FIFO + */ + XMEMSET(sha->buffer, 0, SHA_REG_SIZE); + sha->buffLen = 0; + sha->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_SHA1 | HASH_AlgoMode_HASH + | HASH_DataType_8b); + + /* reset HASH processor */ + HASH->CR |= HASH_CR_INIT; + } + + void ShaUpdate(Sha* sha, const byte* data, word32 len) + { + word32 i = 0; + word32 fill = 0; + word32 diff = 0; + + /* if saved partial block is available */ + if (sha->buffLen) { + fill = 4 - sha->buffLen; + + /* if enough data to fill, fill and push to FIFO */ + if (fill <= len) { + XMEMCPY((byte*)sha->buffer + sha->buffLen, data, fill); + HASH_DataIn(*(uint32_t*)sha->buffer); + + data += fill; + len -= fill; + sha->loLen += 4; + sha->buffLen = 0; + } else { + /* append partial to existing stored block */ + XMEMCPY((byte*)sha->buffer + sha->buffLen, data, len); + sha->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(sha->buffer, 0, SHA_REG_SIZE); + XMEMCPY((byte*)sha->buffer, data, diff); + sha->buffLen = diff; + } else { + HASH_DataIn(*(uint32_t*)data); + data+=4; + } + } + + /* keep track of total data length thus far */ + sha->loLen += (len - sha->buffLen); + } + + void ShaFinal(Sha* sha, byte* hash) + { + __IO uint16_t nbvalidbitsdata = 0; + + /* finish reading any trailing bytes into FIFO */ + if (sha->buffLen) { + HASH_DataIn(*(uint32_t*)sha->buffer); + sha->loLen += sha->buffLen; + } + + /* calculate number of valid bits in last word of input data */ + nbvalidbitsdata = 8 * (sha->loLen % SHA_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 */ + sha->digest[0] = HASH->HR[0]; + sha->digest[1] = HASH->HR[1]; + sha->digest[2] = HASH->HR[2]; + sha->digest[3] = HASH->HR[3]; + sha->digest[4] = HASH->HR[4]; + + ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE); + + XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE); + + InitSha(sha); /* reset state */ + } + +#else /* CTaoCrypt software implementation */ + #ifndef min static INLINE word32 min(word32 a, word32 b) @@ -228,3 +343,5 @@ void ShaFinal(Sha* sha, byte* hash) InitSha(sha); /* reset state */ } +#endif /* STM32F2_CRYPTO */ + diff --git a/cyassl/ctaocrypt/md5.h b/cyassl/ctaocrypt/md5.h index 246ec3997..9c06722a4 100644 --- a/cyassl/ctaocrypt/md5.h +++ b/cyassl/ctaocrypt/md5.h @@ -33,6 +33,9 @@ /* in bytes */ enum { +#ifdef STM32F2_CRYPTO + MD5_REG_SIZE = 4, /* STM32 register size, bytes */ +#endif MD5 = 0, /* hash type unique */ MD5_BLOCK_SIZE = 64, MD5_DIGEST_SIZE = 16, diff --git a/cyassl/ctaocrypt/sha.h b/cyassl/ctaocrypt/sha.h index 5c1b5aa60..5ce340445 100644 --- a/cyassl/ctaocrypt/sha.h +++ b/cyassl/ctaocrypt/sha.h @@ -32,6 +32,9 @@ /* in bytes */ enum { +#ifdef STM32F2_CRYPTO + SHA_REG_SIZE = 4, /* STM32 register size, bytes */ +#endif SHA = 1, /* hash type unique */ SHA_BLOCK_SIZE = 64, SHA_DIGEST_SIZE = 20,