W tym poście chciałbym opisać moduł HASH (Hardware Hash Processor) w STM32H7. Dokładniej w STM32H753. Układ H723 jest pozbawiony tej funkcjonalności. Dotyczy to wersji układu bez akceleratora HASH. Są prawdopodobnie dostępne wersje z takim akceleratorem, ale trzeba to weryfikować przed zakupem.
Moduł HASH jest sprzętowym akceleratorem kryptograficznym, który służy do obliczania hashy. Pozwala na szybkie i energooszczędne generowanie wartości.
Wspiera on generowanie MD-5, SHA-1, SHA-224, SHA-256 czy HMAC (ale to chyba w innej wersji). Pracują one na 512-bitowych blokach danych. Zgodne ze standardami:
Moduł HASH jest wykorzystywany w mechanizmach bezpieczeństwa jak secure boot, weryfikacji integralności oprogramowania czy uwierzytelniania danych. W związku z tym, że jest to moduł sprzętowy wspierający DMA to zapewnia bezpieczne przetwarzanie dużych ilości danych jednocześnie odciążając procesor.
Wynikiem pracy modułu jest HASH zależny od wybranego algorytmu. MD5 generuje 128 bitów, SHA-1 160 bitów, SHA-224 224 bity a SHA-256 256 bitów. Dane wejściowe mogą mieć dowolną długość, natomiast algorytmy wewnątrz STM'a dzielą te dane na 512-bitowe bloki. Dalej wykonuje odpowiednie dopełnienie wiadomości.
Warto pamiętać, że MD5 oraz SHA1 są już przestarzałe. Można używać jesli mamy do czynienia ze starszym sprzętem obsługującym stare protokoły. Obecnie zaleca się stosowanie SHA-256.
Podczas przygotowywania projektu w CubeMx można wybrać następujące rodzaje HASH:
Dodatkowo można wybrać także rodzaj podawanych danych:
- HASH_HandleTypeDef hhash;
- static void MX_HASH_Init(void)
- {
- hhash.Init.DataType = HASH_DATATYPE_8B;
- if (HAL_HASH_Init(&hhash) != HAL_OK)
- {
- Error_Handler();
- }
- }
Różne dostępne warianty można przetestować w nastepujący sposób:
- uint8_t input[] = "test123";
- uint8_t digest[32];
- if (HAL_HASHEx_SHA256_Start(&hhash, input, sizeof(input) - 1, digest, HAL_MAX_DELAY) != HAL_OK)
- {
- Error_Handler();
- }
- uint8_t input2[] = "test123";
- uint8_t digest2[20];
- if (HAL_HASH_SHA1_Start(&hhash, input2, sizeof(input2) - 1, digest2, HAL_MAX_DELAY) != HAL_OK)
- {
- Error_Handler();
- }
- uint8_t input3[] = "test123";
- uint8_t digest3[16];
- if (HAL_HASH_MD5_Start(&hhash, input3, sizeof(input3) - 1, digest3, HAL_MAX_DELAY) != HAL_OK)
- {
- Error_Handler();
- }
Typowy przebieg użycia modułu jest następujący. Na samym początku inicjalizujemy HASH, wybieramy algorytm, przekazujemy bufor do przeliczenia a na końcu dostajemy gotowy wynik. Warto pamiętać, że można korzystać z DMA. Co pozwoli na znacznie sprawniejsze przekazywanie dużych ilości danych.
Działanie HASH można zweryfikować np. na tej stronie:
Można także generować HMAC.
- uint8_t key[] = "keykeykey";
- uint8_t message[] = "tajnawiadomosc=234";
- uint8_t hmac[32];
- hhash.Init.DataType = HASH_DATATYPE_8B;
- hhash.Init.KeySize = sizeof(key) - 1;
- hhash.Init.pKey = key;
- if (HAL_HASH_Init(&hhash) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_HMACEx_SHA256_Start(
- &hhash,
- message,
- sizeof(message) - 1,
- hmac,
- HAL_MAX_DELAY) != HAL_OK)
- {
- Error_Handler();
- }
HMAC służy głównie do policzenia czy wiadomość nie została zmieniona/uszkodzona podczas jej przesyłania. Jej wartość też można zweryfikować online np. na takiej stronie:
Materiały: