-
Notifications
You must be signed in to change notification settings - Fork 3k
mbedtls/F439ZI: add md5 HASH feature #4160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e10d956
10fab73
1cdeb67
dda762c
ace8abb
7766a6d
9a2360a
f973d9a
cdb81d1
8579dac
ef78f3e
a74ec50
d9ac785
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* | ||
* MD5 hw acceleration | ||
******************************************************************************* | ||
* Copyright (c) 2017, STMicroelectronics | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
#if defined(MBEDTLS_MD5_C) | ||
#include "mbedtls/md5.h" | ||
|
||
#if defined(MBEDTLS_MD5_ALT) | ||
#include "mbedtls/platform.h" | ||
|
||
/* Implementation that should never be optimized out by the compiler */ | ||
static void mbedtls_zeroize( void *v, size_t n ) { | ||
volatile unsigned char *p = v; while( n-- ) *p++ = 0; | ||
} | ||
|
||
static int st_md5_restore_hw_context(mbedtls_md5_context *ctx) | ||
{ | ||
uint32_t i; | ||
uint32_t tickstart; | ||
/* allow multi-instance of HASH use: save context for HASH HW module CR */ | ||
/* Check that there is no HASH activity on going */ | ||
tickstart = HAL_GetTick(); | ||
while ((HASH->SR & (HASH_FLAG_BUSY | HASH_FLAG_DMAS)) != 0) { | ||
if ((HAL_GetTick() - tickstart) > ST_MD5_TIMEOUT) { | ||
return 0; // timeout: HASH processor is busy | ||
} | ||
} | ||
HASH->STR = ctx->ctx_save_str; | ||
HASH->CR = (ctx->ctx_save_cr | HASH_CR_INIT); | ||
for (i=0;i<38;i++) { | ||
HASH->CSR[i] = ctx->ctx_save_csr[i]; | ||
} | ||
return 1; | ||
} | ||
|
||
static int st_md5_save_hw_context(mbedtls_md5_context *ctx) | ||
{ | ||
uint32_t i; | ||
uint32_t tickstart; | ||
/* Check that there is no HASH activity on going */ | ||
tickstart = HAL_GetTick(); | ||
while ((HASH->SR & (HASH_FLAG_BUSY | HASH_FLAG_DMAS)) != 0) { | ||
if ((HAL_GetTick() - tickstart) > ST_MD5_TIMEOUT) { | ||
return 0; // timeout: HASH processor is busy | ||
} | ||
} | ||
/* allow multi-instance of HASH use: restore context for HASH HW module CR */ | ||
ctx->ctx_save_cr = HASH->CR; | ||
ctx->ctx_save_str = HASH->STR; | ||
for (i=0;i<38;i++) { | ||
ctx->ctx_save_csr[i] = HASH->CSR[i]; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @adustm: Thanks for making these changes. I have a couple of questions regarding this functionality though:
Therefore, my understanding is that only the values from the CSR register are required.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hello @andresag01
and a note:
We are not using the interrupts in mbed-os: I did not save HASH_IMR register. But STR and CR are required to be saved-restored. I don't save |
||
return 1; | ||
} | ||
|
||
void mbedtls_md5_init( mbedtls_md5_context *ctx ) | ||
{ | ||
mbedtls_zeroize( ctx, sizeof( mbedtls_md5_context ) ); | ||
|
||
/* Enable HASH clock */ | ||
__HAL_RCC_HASH_CLK_ENABLE(); | ||
|
||
} | ||
|
||
void mbedtls_md5_free( mbedtls_md5_context *ctx ) | ||
{ | ||
if( ctx == NULL ) | ||
return; | ||
mbedtls_zeroize( ctx, sizeof( mbedtls_md5_context ) ); | ||
} | ||
|
||
void mbedtls_md5_clone( mbedtls_md5_context *dst, | ||
const mbedtls_md5_context *src ) | ||
{ | ||
*dst = *src; | ||
} | ||
|
||
void mbedtls_md5_starts( mbedtls_md5_context *ctx ) | ||
{ | ||
/* HASH IP initialization */ | ||
if (HAL_HASH_DeInit(&ctx->hhash_md5) != 0) { | ||
// error found to be returned | ||
return; | ||
} | ||
|
||
/* HASH Configuration */ | ||
ctx->hhash_md5.Init.DataType = HASH_DATATYPE_8B; | ||
if (HAL_HASH_Init(&ctx->hhash_md5) != 0) { | ||
// return error code | ||
return; | ||
} | ||
if (st_md5_save_hw_context(ctx) != 1) { | ||
return; // return HASH_BUSY timeout Error here | ||
} | ||
} | ||
|
||
void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[ST_MD5_BLOCK_SIZE] ) | ||
{ | ||
if (st_md5_restore_hw_context(ctx) != 1) { | ||
return; // Return HASH_BUSY timout error here | ||
} | ||
if (HAL_HASH_MD5_Accumulate(&ctx->hhash_md5, (uint8_t *)data, ST_MD5_BLOCK_SIZE) != 0) { | ||
return; // Return error code here | ||
} | ||
if (st_md5_save_hw_context(ctx) != 1) { | ||
return; // return HASH_BUSY timeout Error here | ||
} | ||
} | ||
|
||
void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ) | ||
{ | ||
size_t currentlen = ilen; | ||
if (st_md5_restore_hw_context(ctx) != 1) { | ||
return; // Return HASH_BUSY timout error here | ||
} | ||
// store mechanism to accumulate ST_MD5_BLOCK_SIZE bytes (512 bits) in the HW | ||
if (currentlen == 0){ // only change HW status is size if 0 | ||
if(ctx->hhash_md5.Phase == HAL_HASH_PHASE_READY) { | ||
/* Select the MD5 mode and reset the HASH processor core, so that the HASH will be ready to compute | ||
the message digest of a new message */ | ||
HASH->CR |= HASH_ALGOSELECTION_MD5 | HASH_CR_INIT; | ||
} | ||
ctx->hhash_md5.Phase = HAL_HASH_PHASE_PROCESS; | ||
} else if (currentlen < (ST_MD5_BLOCK_SIZE - ctx->sbuf_len)) { | ||
// only buffurize | ||
memcpy(ctx->sbuf+ctx->sbuf_len, input, currentlen); | ||
ctx->sbuf_len += currentlen; | ||
} else { | ||
// fill buffer and process it | ||
memcpy(ctx->sbuf + ctx->sbuf_len, input, (ST_MD5_BLOCK_SIZE - ctx->sbuf_len)); | ||
currentlen -= (ST_MD5_BLOCK_SIZE - ctx->sbuf_len); | ||
mbedtls_md5_process(ctx, ctx->sbuf); | ||
// Process every input as long as it is %64 bytes, ie 512 bits | ||
size_t iter = currentlen / ST_MD5_BLOCK_SIZE; | ||
if (iter !=0) { | ||
if (HAL_HASH_MD5_Accumulate(&ctx->hhash_md5, (uint8_t *)(input + ST_MD5_BLOCK_SIZE - ctx->sbuf_len), (iter * ST_MD5_BLOCK_SIZE)) != 0) { | ||
return; // Return error code here | ||
} | ||
} | ||
// sbuf is completely accumulated, now copy up to 63 remaining bytes | ||
ctx->sbuf_len = currentlen % ST_MD5_BLOCK_SIZE; | ||
if (ctx->sbuf_len !=0) { | ||
memcpy(ctx->sbuf, input + ilen - ctx->sbuf_len, ctx->sbuf_len); | ||
} | ||
} | ||
if (st_md5_save_hw_context(ctx) != 1) { | ||
return; // return HASH_BUSY timeout Error here | ||
} | ||
} | ||
|
||
void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ) | ||
{ | ||
if (st_md5_restore_hw_context(ctx) != 1) { | ||
return; // Return HASH_BUSY timout error here | ||
} | ||
if (ctx->sbuf_len > 0) { | ||
if (HAL_HASH_MD5_Accumulate(&ctx->hhash_md5, ctx->sbuf, ctx->sbuf_len) != 0) { | ||
return; // Return error code here | ||
} | ||
} | ||
mbedtls_zeroize( ctx->sbuf, ST_MD5_BLOCK_SIZE); | ||
ctx->sbuf_len = 0; | ||
__HAL_HASH_START_DIGEST(); | ||
|
||
if (HAL_HASH_MD5_Finish(&ctx->hhash_md5, output, 10)) { | ||
// error code to be returned | ||
} | ||
if (st_md5_save_hw_context(ctx) != 1) { | ||
return; // return HASH_BUSY timeout Error here | ||
} | ||
} | ||
|
||
#endif /* MBEDTLS_MD5_ALT */ | ||
#endif /* MBEDTLS_MD5_C */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/** | ||
* \file md5_alt.h | ||
* | ||
* \brief MD5 hw acceleration (hash function) | ||
* | ||
* Copyright (c) 2017, STMicroelectronics | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
#ifndef MBEDTLS_MD5_ALT_H | ||
#define MBEDTLS_MD5_ALT_H | ||
|
||
#if defined(MBEDTLS_MD5_ALT) | ||
|
||
#include "cmsis.h" | ||
#include <string.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#define ST_MD5_BLOCK_SIZE ((size_t)(64)) // HW handles 512 bits, ie 64 bytes | ||
#define ST_MD5_TIMEOUT ((uint32_t) 3) | ||
|
||
/** | ||
* \brief MD5 context structure | ||
* \note HAL_HASH_MD5_Accumulate will accumulate 512 bits packets, unless it is the last call to the function | ||
* A ST_MD5_BLOCK_SIZE bytes buffer is used to save values and handle the processing | ||
* ST_MD5_BLOCK_SIZE bytes per ST_MD5_BLOCK_SIZE bytes | ||
* If MD5_finish is called and sbuf_len>0, the remaining bytes are accumulated prior to the call to HAL_HASH_MD5_Finish | ||
*/ | ||
typedef struct | ||
{ | ||
HASH_HandleTypeDef hhash_md5;/*!< ST HAL HASH struct */ | ||
unsigned char sbuf[ST_MD5_BLOCK_SIZE]; /*!< MBEDTLS_MD5_BLOCK_SIZE buffer to store values so that algorithm is caled once the buffer is filled */ | ||
unsigned char sbuf_len; /*!< number of bytes to be processed in sbuf */ | ||
uint32_t ctx_save_cr; | ||
uint32_t ctx_save_str; | ||
uint32_t ctx_save_csr[38]; | ||
} | ||
mbedtls_md5_context; | ||
|
||
/** | ||
* \brief Initialize MD5 context | ||
* | ||
* \param ctx MD5 context to be initialized | ||
*/ | ||
void mbedtls_md5_init( mbedtls_md5_context *ctx ); | ||
|
||
/** | ||
* \brief Clear MD5 context | ||
* | ||
* \param ctx MD5 context to be cleared | ||
*/ | ||
void mbedtls_md5_free( mbedtls_md5_context *ctx ); | ||
|
||
/** | ||
* \brief Clone (the state of) an MD5 context | ||
* | ||
* \param dst The destination context | ||
* \param src The context to be cloned | ||
*/ | ||
void mbedtls_md5_clone( mbedtls_md5_context *dst, | ||
const mbedtls_md5_context *src ); | ||
|
||
/** | ||
* \brief MD5 context setup | ||
* | ||
* \param ctx context to be initialized | ||
*/ | ||
void mbedtls_md5_starts( mbedtls_md5_context *ctx ); | ||
|
||
/** | ||
* \brief MD5 process buffer | ||
* | ||
* \param ctx MD5 context | ||
* \param input buffer holding the data | ||
* \param ilen length of the input data | ||
*/ | ||
void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ); | ||
|
||
/** | ||
* \brief MD5 final digest | ||
* | ||
* \param ctx MD5 context | ||
* \param output MD5 checksum result | ||
*/ | ||
void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ); | ||
|
||
/* Internal use */ | ||
void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[ST_MD5_BLOCK_SIZE] ); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* MBEDTLS_MD5_ALT */ | ||
|
||
#endif /* md5_alt.h */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Is it necessary here to check the status register to ensure that we are not affecting any ongoing operation of the accelerator? For example, what happens if the DMA bit is set because some data is being processed and the accelerator's state is simultaneously being changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DMA is not used in mbed-os.
Aren't you planning some kind of mutex system later on ? It should be handled at a higher level, shouldn't it ?
You are right : I assume that there are not multiple instances of operation at the same time.
What if I cannot run the function and I cannot return any error code anyway ? Should I wait with a timeout or exit as soon as it does not work... ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @adustm
I agree that with the current framework/interface, there is not much we can do here. I think the best way is to return immediately, and record in a comment that an error code should be returned here, like you did it elsewhere in similar situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your reply. I think to answer these planning questions it would be good to include @sbutcher-arm and @yanesca in the discussion.